How do you do proper binding and updating of Xamarin.Forms ListView?
Solution 1
i think your model needs to implement INotifyPropertyChanged. So the UI knows that a value in model has changed
something like this :
public class Model : INotifyPropertyChanged
{
// boiler-plate
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
protected bool SetField<T>(ref T field, T value, string propertyName)
{
if (EqualityComparer<T>.Default.Equals(field, value)) return false;
field = value;
OnPropertyChanged(propertyName);
return true;
}
// props
private string _count;
public string Count
{
get { return _count; }
set { SetField(ref _count, value, "Count"); }
}
}
Solution 2
Remove the "set" method from your ViewModelList property. Whenever you use an ObservableCollection, just change the items in that one collection. Never replace it with another ObservableCollection.
Ken K
Updated on July 02, 2022Comments
-
Ken K almost 2 years
Using the MVVM pattern, I have a Model, ViewModel and View, which contains a ListView. The ListView is bound to a member of the ViewModel that is an ObservableCollection of the Model class. I can get the binding for the initial display to work and can update properties on the Model class for the appropriate row upon acting on the view, but I cannot get the view to refresh, pulling data from the Model class in the ObservableCollection. The ListView class does not contain method to invalidate or force a refresh, which would address my issue. How do I get the ListView to refresh after updating data on the Model?
Here is a simple example of what I am trying to do: Each row contains a Button and Label. Upon clicking a button, I can update the label, which will be reflected on screen. What I need to do is update the Model, which in turn should force an update of the view. However, I cannot get this to work. In an actual application, updating of the Model will be in a business logic layer, not in the view, after which I need to force refresh of the ListView.
Example Code:
using System; using System.Collections.ObjectModel; using Xamarin.Forms; namespace ListViewTest { public class Model { public static int ids = 0; public Model(string count) { Id = +1; Count = count; } public int Id { get; set; } public string Count { get; set; } } public class ModelList : ObservableCollection<Model> { } public class ViewModel { ModelList list = new ModelList(); public ModelList ViewModelList { get { return list; } set { list = value; } } } public partial class MainPage : ContentPage { public ViewModel viewModel; public class DataCell : ViewCell { public DataCell() { var Btn = new Button(); Btn.Text = "Click"; var Data = new Label(); Data.SetBinding(Label.TextProperty,"Count"); Btn.Clicked += (object sender, EventArgs e) => { Model model = (Model)(((Button)sender).Parent.BindingContext); int count = Convert.ToInt32(model.Count); count++; model.Count = count.ToString(); // Need to refresh ListView from data source here... How??? }; StackLayout s = new StackLayout(); s.Orientation = StackOrientation.Horizontal; s.Children.Add(Btn); s.Children.Add(Data); this.View = s; } } public MainPage () { viewModel = new ViewModel(); viewModel.ViewModelList.Add(new Model("0")); viewModel.ViewModelList.Add(new Model("0")); InitializeComponent(); } public void InitializeComponent() { ListView listView = new ListView { ItemsSource = viewModel.ViewModelList, ItemTemplate = new DataTemplate(() => { return new DataCell(); }) }; Content = listView; } } }