WPF, why adding PropertyChanged to List<> does not take into effect?

587 Views Asked by At

why PropertyChangedEvent can be add to a String property, but cannot be add to a List<> property?

the xaml likes this:

<StackPanel>
    <ListBox ItemsSource="{Binding Items}" Height="300"/>
    <Button Click="Button_Click">Change</Button>
</StackPanel>

and the xaml.cs like this:

public partial class MainWindow : Window, INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    //public ObservableCollection<String> Items { get; set; } = new ObservableCollection<String>(); // ok
    public List<String> Items  // no effect
    {
        get { return _items; }
        set
        {
            _items = value;
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs("Items"));
        }
    }
    private List<String> _items = new List<string>();

    public MainWindow()
    {
        InitializeComponent();
        this.DataContext = this;
        Items.Add("aaa");
        Items.Add("bbb");
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        Items.Clear();
        for (int i = 0; i < 5; i++)
            Items.Add(i.ToString());
     }
}
2

There are 2 best solutions below

1
Mak Ahmed On BEST ANSWER

Your issue can be fixed in multiple ways,

  1. Create another List on Button Click, sample code given below

  2. Use Observable Collection

    Change
        private RelayCommand _buttonClick;
         public RelayCommand ButtonClick => _buttonClick ?? new RelayCommand(onButtonClick, canButtonClick);
    
     private bool canButtonClick(object obj)
     {
         return true;
     }
    
     private void onButtonClick(object obj)
     {
         List<String> tempItems = new List<string>();
         for (int i = 0; i < 5; i++)
             tempItems.Add(i.ToString());
         Items = tempItems;
     }
    
1
Vg0 On

It doesn't work because you're only notifying when the entire List is set, not when items are added or removed within the list.

Use an ObservableCollection<string> instead of List<string>:

public partial class MainWindow : Window, INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private ObservableCollection<string> _Items = new ObservableCollection<string>();
    public ObservableCollection<string> Items
    {
        get { return _Items; }
        set
        {
            _Items = value;
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Items));
        }
    }

    public MainWindow()
    {
        InitializeComponent();
        this.DataContext = this;
        Items.Add("aaa");
        Items.Add("bbb");
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        Items.Clear();
        for (int i = 0; i < 5; i++)
            Items.Add(i.ToString());
     }
}