4

Xamarin.Forms 4.0 collection view ItemsSource binding is not working as expected if I set the binding in code behind. The items are displayed based on the initial value of the source collection but, the UI is not updating when the source collection is updated. Same is working if I set the binding in xaml.

Code behind:

    public MainPage()
    {
        this.InitializeComponent();
        this.BindingContext = this.mainViewModel = new MainViewModel();


        CollectionView courseCollectionView = new CollectionView
        {
            ItemSizingStrategy = ItemSizingStrategy.MeasureFirstItem,
            ItemTemplate = new DataTemplate(typeof(ItemView))
        };


     courseCollectionView.SetBinding(CollectionView.ItemsSourceProperty, 
     new Binding() { Source = this.mainViewModel.CountryNames, Mode = 
     BindingMode.TwoWay });

     courseCollectionView.ItemsLayout = new GridItemsLayout(4, 
      ItemsLayoutOrientation.Vertical);

        this.CoursesStack.Children.Clear();
        this.CoursesStack.Children.Add(courseCollectionView);

    }

View Model Property which is using for ItemsSource Binding:

   ObservableCollection<Country> countryNames;

    public ObservableCollection<Country> CountryNames
    {
        get => this.countryNames;
        set
        {
            this.countryNames = value;
            RaisePropertyChanged("CountryNames");
        }
    }

Expected: View should be updated as per the changes made to the ObsevableCollection (add/delete items from collection) which is bound to the ItemsSource Property.

Actual: View is not updated with changes to the ObservableCollection.

Narender Reddy
  • 145
  • 1
  • 1
  • 9
  • 1
    when you say "not updated with changes", to do you mean add/deleting items from the Collection? Or do you mean changes to the properties of individual items in the Collections? – Jason May 29 '19 at 11:41
  • When I add/delete items from the collection, the UI is not updated. – Narender Reddy May 29 '19 at 12:07
  • You don't need to bind the ItemsSource in the code behind - you can just assign it directly. But this is probably not the root problem. You also should not need a two way binding for a CollectionView – Jason May 29 '19 at 12:43
  • Yes, I can bind it in xaml but, there is a an open bug/task on collection view as mentioned here https://github.com/xamarin/Xamarin.Forms/issues/5354. And I need to update the ItemsLayout on device orientation change. Anyways @ottermatic solution worked for me. thank you :) – Narender Reddy May 30 '19 at 04:14
  • @Jason how about when you change the Item properties? – Nasreddine Galfout May 26 '20 at 19:18
  • use INotifyPropertyChanged – Jason May 26 '20 at 20:02
  • @Jason I found [this](https://forums.xamarin.com/discussion/40084/update-item-properties-in-a-listviews-observablecollection) which does the trick. it boils down to assigning the Item to its self. `public void RefreshMe(Item item) { Items[Items.IndexOf(item)] = item; }`. I also found the same explanation [here](https://stackoverflow.com/questions/59473945/update-display-of-one-item-in-a-listviews-observablecollection/59506197#59506197) on SO – Nasreddine Galfout May 26 '20 at 20:13

3 Answers3

2

I believe your binding is wrong. Try: courseCollectionView.SetBinding(CollectionView.ItemsSourceProperty, nameof(mainViewModel.CountryNames));

You need to specify the Path (mainViewModel.CountryNames) and not the Source

ottermatic
  • 992
  • 6
  • 10
2

About updating UI when using CollectionView, I do one sample that you can take a look:

public partial class MainPage : ContentPage
{
    public mainvidemodel viewmodel { get; set; }
    public MainPage()
    {
        InitializeComponent();
        viewmodel = new mainvidemodel();
        this.BindingContext = viewmodel;

        CollectionView collectionView = new CollectionView();

        collectionView.SetBinding(ItemsView.ItemsSourceProperty, "countries");

        collectionView.ItemTemplate = new DataTemplate(() =>
        {
            StackLayout stacklayout = new StackLayout();

            Label label1 = new Label();
            label1.SetBinding(Label.TextProperty,"Id");

            Label label2 = new Label();
            label2.SetBinding(Label.TextProperty, "Name");

            Label label3 = new Label();
            label3.SetBinding(Label.TextProperty, "caption");


            stacklayout.Children.Add(label1);
            stacklayout.Children.Add(label2);

            stacklayout.Children.Add(label3);
            return stacklayout;

        });
        Button btn = new Button() { Text = "btn", WidthRequest = 200, HeightRequest = 50 };
        btn.Clicked += Btn_Clicked;
        stacklayout1.Children.Add(collectionView);
        stacklayout1.Children.Add(btn);

    }

    private void Btn_Clicked(object sender, EventArgs e)
    {
        viewmodel.countries.Add(new Country()  { Id = 8, Name = "country8", caption = "caption 8" });
    }
}
public class mainvidemodel
{
    public ObservableCollection<Country> countries { get; set; }
    public mainvidemodel()
    {
        countries = new ObservableCollection<Country>()
        {
            new Country(){Id=1,Name="country1",caption="caption 1"},
            new Country(){Id=2,Name="country2",caption="caption 2"},
            new Country(){Id=3,Name="country3",caption="caption 3"},
            new Country(){Id=4,Name="country4",caption="caption 4"},
            new Country(){Id=5,Name="country5",caption="caption 5"},
            new Country(){Id=6,Name="country6",caption="caption 6"},
            new Country(){Id=7,Name="country7",caption="caption 7"},

        };

    }
}
public class Country
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string caption { get; set; }
}

enter image description here

Cherry Bu - MSFT
  • 10,160
  • 1
  • 10
  • 16
0

In this case try to extend the MainPage from INotifyPropertyChanged and instead of RaisePropertyChanged("CountryNames") in set property, use OnPropertyChanged()

Afonso
  • 75
  • 9
  • The MainViewModel is already extended from INotifyPropertyChanged and its working fine if I set binding if ItemsSource in Xaml. – Narender Reddy May 29 '19 at 12:08