papafe
papafe

Reputation: 3070

Updated list does not change on UI when PropertyChanged is called in Xamarin.Forms

I have a bindable StackLayout bound to a List in the ViewModel. When a button is pressed I am adding an element to the list and then invoking PropertyChanged with the name of the list.

I don't understand why the UI does not get updated in this case. I know that I should use an ObservableCollection, and I know how to do it, but I am curious about why the UI does not change if I am invoking PropertyChanged myself.

This is the ViewModel and Model class:

    public class Element
    {
        public string Value { get; set; }
    }

    public class MainViewModel : INotifyPropertyChanged
    {
        public List<Element> Elements { get; set; }
        public ICommand AddElementCommand { get; private set; }

        public event PropertyChangedEventHandler PropertyChanged;

        public MainViewModel()
        {
            AddElementCommand = new Command(AddElement);

            Elements = new List<Element>();
            Elements.Add(new Element { Value = "test1" });
        }

        void AddElement()
        {
            Elements.Add(new Element { Value = "testAgain" });
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Elements"));
        }
    }

And this is the view:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:d="http://xamarin.com/schemas/2014/forms/design"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             mc:Ignorable="d"
             x:Class="TestList.MainPage"
             x:Name="page">
    <StackLayout>
        <StackLayout Orientation="Horizontal">
            <Label Text="Elements"
                       FontSize="Large"
                       HorizontalOptions="FillAndExpand"
                       VerticalOptions="Center"/>
            <Button Command="{Binding AddElementCommand}"
                    Text="+" FontSize="Title"
                        VerticalOptions="Center"/>
        </StackLayout>
        <StackLayout BindableLayout.ItemsSource="{Binding Elements}">
            <BindableLayout.ItemTemplate>
                <DataTemplate>
                      <Entry Text="{Binding Value, Mode=TwoWay}" HorizontalOptions="FillAndExpand"/>
                </DataTemplate>
            </BindableLayout.ItemTemplate>
        </StackLayout>
    </StackLayout>
</ContentPage>

Upvotes: 2

Views: 938

Answers (1)

Lucas Zhang
Lucas Zhang

Reputation: 18861

If we check the source code of ObservableCollection , we will see that it had implemented INotifyCollectionChanged and INotifyPropertyChanged in default while List didn't .

public class ObservableCollection<T> : Collection<T>, INotifyCollectionChanged, INotifyPropertyChanged
public class List<T> : ICollection<T>, IEnumerable<T>, IEnumerable, IList<T>, IReadOnlyCollection<T>, IReadOnlyList<T>, ICollection, IList

If a list will contain the same items for their whole lifetime, but the individual objects within that list will change, then it's enough for just the objects to raise change notifications (typically through INotifyPropertyChanged) and List is sufficient. But if the list will contain different objects from time to time, or if the order changes, then you should use ObservableCollection.

That is why we always suggest users to choose ObservableCollection instead of List .

Upvotes: 2

Related Questions