I tried different collections under different conditions but all changes that I was able to receive were Permutation, Add, Removed and Replace changes.
In what conditions does update change emerge? What base class, what stored class and what operations is needed to produce such event?
To generate an update event, you must create an ObservableList with an extractor.
The extractor is a function mapping each element in the list to an array of Observables. If any of those Observables change (while the element is still in the list), then the list will receive an update event.
For example, given a Person class:
public class Person {
private final StringProperty name = new SimpleStringProperty();
public Person(String name) {
nameProperty().set(name);
}
public StringProperty nameProperty() {
return name ;
}
public final String getName() {
return nameProperty().get();
}
public final void setName(String name) {
nameProperty().set(name);
}
}
if you create an observable list as
ObservableList<Person> people = FXCollections.observableArrayList(person ->
new Observable[] {person.nameProperty()} );
and register a listener
people.addListener((Change<? extends Person> change) -> {
while (change.next()) {
if (change.wasAdded()) {
System.out.println("Add");
}
if (change.wasUpdated()) {
System.out.println("Update");
}
}
});
Then the following will show an update event:
Person person = new Person("Jacob Smith");
people.add(person);
person.setName("Isabella Johnson");
Related
I am very much depressed trying many times to implement this but not successful yet.
I am trying to change a javafx table raw's particular value when a user change a button. Suppose if the table has a particular raw value is 10 then if user press a button the value will be changed to 20 but how can I do that?
But this simple technique is very much easy in java swing. Please some help me to do the same thing in javafx.
You do not update the value of a TableCell directly. Instead, modify the underlying data model values.
Take a look at what type of List<> you're passing to the TableView when you call tableView.setItems(). It is that data type that you want to update.
For example, suppose you have a TableView<Person> that contains a List of Person objects:
public class Person {
private final StringProperty name = new SimpleStringProperty();
private final StringProperty email = new SimpleStringtProperty();
public Person (String name, String email) {
this.name.set(name);
this.email.set(email);
}
public String getName() {
return name.get();
}
public StringProperty nameProperty() {
return name;
}
public void setName(String name) {
this.name.set(name);
}
public String getEmail() {
return email.get();
}
public StringProperty emailProperty() {
return email;
}
public void setEmail(String email) {
this.email.set(email);
}
}
So you have your List<Person> and you've used it to populate your TableView:
tableView.setItems(FXCollections.observableArrayList(persons));
Now, when your user clicks a Button or you otherwise want to update the TableView with a new value, you would update the Person object:
person.setEmail("me#home.com");
As soon as that property is changed, the TableView will update to reflect the new value.
This is a high-level overview/example. If you need more detailed help, please edit your question and include a Minimal, Reproducible Example that demonstrates the exact problem you're facing.
It would also be wise to read the help article on How To Ask A Good Question.
I have a xamarin forms app.
There are 2 classes with data, one of the pages is filling the data.
The problem is: I'm creating new view, that should use data from both classes.
The only way i'm familiar with is to set a class as a bindingContext to pass data between pages, and it's working fine with ONE class, because apparently there couldn't be 2 bindingContext at the same time.
EXAMPLE:
1st class (all the classes are filled on the previous page. just accept that they are filled)
public class Buildings : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string _id;
public string Id
{
get { return _id; }
set
{
_id = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Id"));
}
}
}
2nd class
public class Flats : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string _num;
public string Num
{
get { return _num; }
set
{
_num = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Num"));
}
}
}
new view:
public partial class HouseView
{
private Flats _flats;
private Buildings _buildings;
public HouseView()
{
InitializeComponent();
}
private void HouseView_OnBindingContextChanged(object sender, EventArgs e)
{
var building = BindingContext as Building;
//var flat = BindingContext as Flat;
//_flat = flat;
_building = building;
var buildingInfo = await Rest.GetHouseInfo(_building.Id, _flat.Num); //function that will return info on a current house;
// rest code
}
}
Maybe there is no need for binding context, because i'm just passing the parameters, not changing them in a view? I guess the solution can be pretty simple, and i cant figure it out....
What you are missing is understanding the concept of ViewModel, and it's relation with the views.. In this case what you need is a 3rd class (ViewModel) that handles your 2 previous class:
public class HouseViewModel : INotifyPropertyChanged
{
public Flats Flats { get; set; }
private Buildings Buildings { get; set; }
}
Also using OnBindingContextChanged is just messy and will take some performance from your app .. try to prepare your data before on your VM, so the view knows as little as possible in how to get/handle data.
There is simple way to transfer data between pages in Xamarin forms.
Add new class to the main project called Transporter.cs, and this class should be static.
Inside this class, add the variables to transfer data between other pages; then you can simply access any variable by using Transporter.Variable.
Example:
public static Transporter
{
public static string x;
}
> Now, in each page, you can simply access (set or get) the value:
Transporter.x=MyName.Text;
>In another page:
MySecondName.Text=Transporter.x;
Note: MyName is an entry field in the first page, and MySecondName is an entry field in the second page.
Also, you can define any type of variables like (Lists, int, object... etc).
I need to implement search functionality inside my android app which uses toolbar, SlidingTabLayout and ViewPager that holds fragments. Inside each fragment there is a RecyclerView with list of items.
RecyclerView data is static defined in separate class (DataAccess.java) and those lists are updated and RecyclerView gets refreshed just by calling (without passing new data)
mRecyclerView.getAdapter().notifyDataSetChanged();
Is there any simple way to temporary filter RecyclerView without changing the data and after the user presses return button inside Toolbar to remove the filter and show inital list.
Before pressing Search icon inside toolbar menu:
So when the user is typing "Josip..." the filter will be active
and after he presses the X button in SearchView the user will get the same data as before without filter.
#Override
public boolean onQueryTextChange(String newText) {
// filter data (temporary remove all items from DataAccess.list that don't .startsWith(newText)
}
#Override
public boolean onQueryTextSubmit(String query)
// Doesn't help if I revert deleted items here
}
#Override
public boolean onQueryTextSubmit(String query){
((ItemAdapter) myRecList.getAdapter()).setFilter(query)
}
public class ItemAdapter extends RecyclerView.Adapter<ItemAdapter.ViewHolder> {
private List<String> visibleObjects;
private List<String> allObjects;
.....
public void flushFilter(){
visibleObjects=new ArrayList<>();
visibleObjects.addAll(allObjects);
notifyDataSetChanged();
}
public void setFilter(String queryText) {
visibleObjects = new ArrayList<>();
constraint = constraint.toString().toLowerCase();
for (String item: allObjects) {
if (item.toLowerCase().contains(queryText))
visibleObjects.add(item);
}
notifyDataSetChanged();
}
}
I wanted to add as comment but due to less reputation...I am answering post.
This method works fine if (item.toLowerCase().contains(queryText)) but what to do if match is not found in first iteration.then it will go in else part without looping throughout allObjects list...
for (RouteByATMList.Route_ATM item: Main_ATMItemList)
{
if (item.ATMNumber.contains(queryText)) {
visibleObjects.add(item);
}else {
Toast.makeText(mContext,"No search result found!",Toast.LENGTH_SHORT).show();
break;
}
}
I got the answer from my superior ,hope it helps.
public void setFilter(String queryText) {
visibleObjects = new ArrayList<>();
for (RouteByATMList.Route_ATM item: Main_ATMItemList)
{
if (item.ATMNumber.contains(queryText))
{
visibleObjects.add(item);
}
}
if(visibleObjects.size()==0){
Toast.makeText(mContext,"No search result found!",Toast.LENGTH_SHORT).show();
}
notifyDataSetChanged();
Log.e("dataset changed","dataset changed");
}
I don't oppose the given and accepted answer. There is a room for possible performance pitfalls. One should make use of Filterabe interface. Having this implemented will behave as ol'good ListView that did the filtering asynchronously. Then all you need is to write your own Filter and instantiate it in the overridden getFilter() method;
In my case I used Filter to sort an adapter of many (yeah, many many) items. It was junky sorting it on UI-thread.
So I had this abstract class
public abstract class BaseFilterableRecyclerViewAdapter<VH extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<VH> implements Filterable {
private Context mContext;
public BaseFilterableRecyclerViewAdapter(Context context) {
this.mContext = context;
}
public abstract void sort(SortingFilter.Sort sortingStrategy);
//...Other methods
}
And the class that inherit:
public class ItemAdapter extends BaseFilterableRecyclerViewAdapter<RecyclerView.ViewHolder>{
//... RecyclerView methods
#Override
public Filter getFilter() {
return new SortingFilter(mData) {
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
if (results.values != null) {
int last = mData.size();
mData = (List<Product>) results.values;
notifyDataSetChanged();
}
}
};
}
#Override
public void sort(SortingFilter.Sort sortingStrategy) {
getFilter().filter(sortingStrategy.toString());
}
}
I'm new to Mocking, but this must be something really basic that I'm missing:
The test code below produces an exception:
Expected invocation on the mock at least once, but was never performed: x => x.DeleteProducts(._products)\r\n\r\nConfigured setups:\r\nx => x.DeleteProducts(._products), Times.Never\r\n\r\nPerformed invocations:\r\nIProductRepository.DeleteProducts(System.Collections.Generic.List`1[WebApiDemo.DataAccessLayer.Product])
I step through the controller method and it does seem to call the DeleteProducts method...
// Arrange
IEnumerable<Product> _products = Helpers.ProductHelpers.CreateProducts(_numberProducts);
Mock<IProductRepository> _productRepository = new Mock<IProductRepository>();
_productRepository.Setup(x => x.DeleteProducts(_products));
ProductsController controller = new ProductsController(_productRepository.Object);
// Act
controller.Destroy(_productViewModels); // Destroy calls DeleteProducts
// Assert
_productRepository.Verify(x => x.DeleteProducts(_products));
Does DeleteProducts(_products); return void? I assume it does, so you need to put the .Verifiable() at the end of the .Setup() for it.
With that in place, it should run through ok, although I'm not sure why you have the Times.Never() instead of Times.Once() ??
I would also advocate on the Setup call using It.IsAny<T> rather than a specific collection, such as:
MyMock.Setup(x => x.MyMethod(It.IsAny<IEnumerable<Widget>>)).Verifiable()
Unless you have the mock behaviour set to strict there is no need for the setup. You are not returning anything from the Delete. The call to Verify will suffice.
Some things are not totally obvious from the code.
The repository deletes products but the controller destroys productviewmodels.
In Moq 4 the test should work if
You have a product view model for every product in _products
The Controller.Destroy method gets products from the viewmodels in the same order as _products
I would check that _productViewModels is a 1:1 match to the _products and check how Destroy() extracts the products from the viewmodels before calling Delete()
I would not go with the IsAny>() because you want to check that these specific products were deleted not any other ones.
[TestClass]
public class Verifying {
public interface IProductRepository {
void Delete(IEnumerable<Product> products);
}
public class ProductController {
private IProductRepository _repository;
public ProductController(IProductRepository repository) {
_repository = repository;
}
public void Destroy(IEnumerable<Product> products) {
_repository.Delete(products);
}
public void Destroy(IEnumerable<ProductViewModel> productViewModels) {
_repository.Delete(productViewModels.Select(vm => vm.Product));
}
}
public class Product {
}
public class ProductViewModel {
public Product Product { get; set;}
}
static Verifying() {
sProducts = new List<Product> { new Product(), new Product(), new Product() };
sProductViewModels = new List<ProductViewModel>(sProducts.Select(p => new ProductViewModel { Product = p }));
}
private static List<Product> sProducts;
private static List<ProductViewModel> sProductViewModels;
private Mock<IProductRepository> _mockRepository;
private ProductController CreateController() {
_mockRepository = new Mock<IProductRepository>();
return new ProductController(_mockRepository.Object);
}
[TestMethod]
public void DestroyingProducts() {
var controller = CreateController();
controller.Destroy(sProducts);
_mockRepository.Verify(mk => mk.Delete(sProducts));
}
[TestMethod]
public void DestroyingProductViewModels() {
var controller = CreateController();
controller.Destroy(sProductViewModels);
_mockRepository.Verify(mk => mk.Delete(sProducts));
}
}
My Grails application has a large number of enums that look like this:
public enum Rating {
BEST("be"), GOOD("go"), AVERAGE("av"), BAD("ba"), WORST("wo")
final String id
private RateType(String id) {
this.id = id
}
static public RateType getEnumFromId(String value) {
values().find {it.id == value }
}
}
If I have a command object such as this:
class MyCommand {
Rating rating
}
I would like to (for example) automatically convert a request parameter with value "wo" to Rating.WORST.
The procedure for defining custom converters is described here (in the context of converting Strings to Dates). Although this procedure works fine, I don't want to have to create a class implementing PropertyEditorSupport for each of my enums. Is there a better alternative?
I found a solution I'm pretty happy with.
Step 1: Create an implementation of PropertyEditorSupport to convert text to/from the relevant Enum
public class EnumEditor extends PropertyEditorSupport {
private Class<? extends Enum<?>> clazz
public EnumEditor(Class<? extends Enum<?>> clazz) {
this.clazz = clazz
}
public String getAsText() {
return value?.id
}
public void setAsText(String text) {
value = clazz.getEnumFromId(text)
}
}
Step 2: Define a class that registers EnumEditor as a converter for the various enum classes. To change the list of enum classes that are bindable by id, just modify BINDABLE_ENUMS
public class CustomPropertyEditorRegistrar implements PropertyEditorRegistrar {
private static final String REQUIRED_METHOD_NAME = 'getEnumFromId'
// Add any enums that you want to bind to by ID into this list
private static final BINDABLE_ENUMS = [Rating, SomeOtherEnum, SomeOtherEnum2]
public void registerCustomEditors(PropertyEditorRegistry registry) {
BINDABLE_ENUMS.each {enumClass ->
registerEnum(registry, enumClass)
}
}
/**
* Register an enum to be bound by ID from a request parameter
* #param registry Registry of types eligible for data binding
* #param enumClass Class of the enum
*/
private registerEnum(PropertyEditorRegistry registry, Class<? extends Enum<?>> enumClass) {
boolean hasRequiredMethod = enumClass.metaClass.methods.any {MetaMethod method ->
method.isStatic() && method.name == REQUIRED_METHOD_NAME && method.parameterTypes.size() == 1
}
if (!hasRequiredMethod) {
throw new MissingMethodException(REQUIRED_METHOD_NAME, enumClass, [String].toArray())
}
registry.registerCustomEditor(enumClass, new EnumEditor(enumClass))
}
}
Step 3: Make Spring aware of the registry above by defining the following Spring bean in grails-app/conf/spring/resources.grooovy
customPropertyEditorRegistrar(CustomPropertyEditorRegistrar)
So the default Databinding binds on the Enum name and not a separately defined property of the Enum. You can either create your own PropertyEditor as you have mentioned or do a work-around similar to this:
class MyCommand {
String ratingId
Rating getRating() {
return Rating.getEnumFromId(this.ratingId)
}
static constraints = {
ratingId(validator:{val, obj -> Rating.getEnumFromId(val) != null })
}
}