How do I update an ObservableCollection item's property from change in a WPF DataGrid?

24,797

Solution 1

CollectionChanged is for Insert and Delete. NotifyPropertyChanged is for update of an items. In the posted code you don't actually implement INotifyPropertyChanged.

   public event PropertyChangedEventHandler PropertyChanged;
    private void NotifyPropertyChanged(String info)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(info));
        }
    }

And I think it is cleaner to bind to a public property where you return _itemDataCol

Otherwise the TwoWay answer of celopez3

Solution 2

An ObservableCollection doesn't listen to its items' INotifyPropertyChanged events; use a BindingList instead.

In other words, [an ObservableCollection] only notices when items are added or removed, not when the values of its items change, even if those items implement INotifyPropertyChanged. In comparison, a BindingList DOES listen to INotifyPropertyChanged, and therefore, if its items are modified, the changes will be reflected in the grid. As a result grouping, sorting, and statistical functions will be updated.

http://xceed.com/CS/blogs/dontpanic/archive/2009/04/01/i-notify-we-notify-we-all-wait-no-we-don-t.aspx

Share:
24,797
K J
Author by

K J

Updated on July 09, 2022

Comments

  • K J
    K J almost 2 years

    I have a WPF DataGrid who's data source is an ObservableCollection. It is set up loosely as the following:

    public class ItemDataCollection : ObservableCollection<ItemData>
    {
    }
    
    public class ItemData : INotifyPropertyChanged
    {
        private bool _selected = true;
        public bool Selected 
        { 
            get
            {
                return _selected;
            }
            set
            {
                if (value != _selected)
                {
                    _selected = value;
                    NotifyPropertyChanged("Selected");
                }
            }
        }
        }
    
    
        _itemDataCol = new ItemDataCollection();
            <... fill the _itemDataCol with data here ...>
        dataGrid1.ItemsSource = _itemDataCol;
    

    When the collection is updated, a dataGrid1.Items.Refresh() updates dataGrid1 nicely. However when I modify the "Selected" property of a row by checking or unchecking the checkbox in the row corresponding to that property, the item in the collection does not get updated. I looked into the CollectionChanged event of the ObeservableCollection, but that is not appearing to get triggerd. What wiring do I need to get the dataGrid1 to update the collection.

    Update

    All I was doing was setting the ItemSource property to the ObservableCollection and letting the columns auto-generate. I have since changed to bind directly, and found more detail to the problem. When I simply check the box - no notification is triggerd. However if I hit after checking the box, then the collection is updated. Here is the binding:

    <DataGridCheckBoxColumn Binding="{Binding Path=Selected, Mode=TwoWay}" Header="Selected"></DataGridCheckBoxColumn>
    

    So I guess the question is how do I get the update with having to hit after checking or unchecking the box?

    Update #2 (I cannot answer as my rep is not high enough yet) OK - I think I have the solution. If I include "UpdateSourceTrigger=PropertyChanged" in the binding everything seems to work.

    <DataGridCheckBoxColumn Binding="{Binding Path=Selected, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Header="Selected"></DataGridCheckBoxColumn>
    

    Please leave comments if there are any negative affects of this that I may be missing. Thanks for the help!

  • K J
    K J about 12 years
    Sorry - I omitted the implementation of NotifyPropertyChanged to keep the post short. It is implemented correctly in my actual code.
  • paparazzo
    paparazzo about 12 years
    Does it get called? Does set get called? Please try binding to a public property. If all that fails try bypassing you ItemDataCollection and supply a ObservableCollection<ItemData> directly (for testing).
  • K J
    K J about 12 years
    All I was doing was setting the ItemSource property to the ObservableCollection and letting the columns auto-generate. I have since changed to bind directly, and found more detail to the problem. When I simply check the box - no notification is triggerd. However if I hit <enter> after checking the box, then the collection is updated. Here is the binding: <DataGridCheckBoxColumn Binding="{Binding Path=Selected, Mode=TwoWay}" Header="Selected"></DataGridCheckBoxColumn> Any ideas?
  • K J
    K J about 12 years
    I tried the following: <DataGridCheckBoxColumn Binding="{Binding Path=Selected, Mode=TwoWay}" Header="Selected"></DataGridCheckBoxColumn> Selected is public. The problem turns out that if I hit <enter> after checking or unchecking the box, the ObservableCollection is updated. Simply checking the box does is not enough to trigger the update however.
  • paparazzo
    paparazzo about 12 years
    You need to set the UpdateSourceTrigger to PropertyChanged msdn.microsoft.com/en-us/library/…
  • K J
    K J about 12 years
    I was messing with the site - still new to posting on it. When I noticed it unchecked yours, I re-accepted but it didn't take. It was not my intention - you earned the accepted answer.
  • paparazzo
    paparazzo about 12 years
    That is strange as it shows you both accepted and unaccepted today. The answer shows a check mark but I did not get credit. Please try a single click on the check mark. And if I don't get credit then no problem. Good you got it working.
  • K J
    K J about 12 years
    Hmm. I tried unaccepting and accepting again. It does show your post as the accepted answer - at least in my browser on different machines. My apologies - you were the first to post and the credit should be yours. That is what I get for playing with something that was not broken...
  • paparazzo
    paparazzo about 12 years
    Did you try to accept your answer? I bet that is what killed my answer.