ObservableCollection not noticing when Item in it changes (even with INotifyPropertyChanged)












148















Does anyone know why this code doesn't work:



public class CollectionViewModel : ViewModelBase {  
public ObservableCollection<EntityViewModel> ContentList
{
get { return _contentList; }
set
{
_contentList = value;
RaisePropertyChanged("ContentList");
//I want to be notified here when something changes..?
//debugger doesn't stop here when IsRowChecked is toggled
}
}
}

public class EntityViewModel : ViewModelBase
{

private bool _isRowChecked;

public bool IsRowChecked
{
get { return _isRowChecked; }
set { _isRowChecked = value; RaisePropertyChanged("IsRowChecked"); }
}
}


ViewModelBase containts everything for RaisePropertyChanged etc. and it's working for everything else except this problem..










share|improve this question





























    148















    Does anyone know why this code doesn't work:



    public class CollectionViewModel : ViewModelBase {  
    public ObservableCollection<EntityViewModel> ContentList
    {
    get { return _contentList; }
    set
    {
    _contentList = value;
    RaisePropertyChanged("ContentList");
    //I want to be notified here when something changes..?
    //debugger doesn't stop here when IsRowChecked is toggled
    }
    }
    }

    public class EntityViewModel : ViewModelBase
    {

    private bool _isRowChecked;

    public bool IsRowChecked
    {
    get { return _isRowChecked; }
    set { _isRowChecked = value; RaisePropertyChanged("IsRowChecked"); }
    }
    }


    ViewModelBase containts everything for RaisePropertyChanged etc. and it's working for everything else except this problem..










    share|improve this question



























      148












      148








      148


      98






      Does anyone know why this code doesn't work:



      public class CollectionViewModel : ViewModelBase {  
      public ObservableCollection<EntityViewModel> ContentList
      {
      get { return _contentList; }
      set
      {
      _contentList = value;
      RaisePropertyChanged("ContentList");
      //I want to be notified here when something changes..?
      //debugger doesn't stop here when IsRowChecked is toggled
      }
      }
      }

      public class EntityViewModel : ViewModelBase
      {

      private bool _isRowChecked;

      public bool IsRowChecked
      {
      get { return _isRowChecked; }
      set { _isRowChecked = value; RaisePropertyChanged("IsRowChecked"); }
      }
      }


      ViewModelBase containts everything for RaisePropertyChanged etc. and it's working for everything else except this problem..










      share|improve this question
















      Does anyone know why this code doesn't work:



      public class CollectionViewModel : ViewModelBase {  
      public ObservableCollection<EntityViewModel> ContentList
      {
      get { return _contentList; }
      set
      {
      _contentList = value;
      RaisePropertyChanged("ContentList");
      //I want to be notified here when something changes..?
      //debugger doesn't stop here when IsRowChecked is toggled
      }
      }
      }

      public class EntityViewModel : ViewModelBase
      {

      private bool _isRowChecked;

      public bool IsRowChecked
      {
      get { return _isRowChecked; }
      set { _isRowChecked = value; RaisePropertyChanged("IsRowChecked"); }
      }
      }


      ViewModelBase containts everything for RaisePropertyChanged etc. and it's working for everything else except this problem..







      c# observablecollection inotifypropertychanged






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Mar 1 '18 at 16:58









      Robert Harvey

      149k33276420




      149k33276420










      asked Sep 15 '09 at 14:17









      Joseph jun. MelettukunnelJoseph jun. Melettukunnel

      2,869135485




      2,869135485
























          16 Answers
          16






          active

          oldest

          votes


















          107














          The ContentList's Set method will not get called when you change a value inside the collection, instead you should be looking out for the CollectionChanged event firing.



          public class CollectionViewModel : ViewModelBase
          {
          public ObservableCollection<EntityViewModel> ContentList
          {
          get { return _contentList; }
          }

          public CollectionViewModel()
          {
          _contentList = new ObservableCollection<EntityViewModel>();
          _contentList.CollectionChanged += ContentCollectionChanged;
          }

          public void ContentCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
          {
          //This will get called when the collection is changed
          }
          }




          Okay, that's twice today I've been bitten by the MSDN documentation being wrong. In the link I gave you it says:




          Occurs when an item is added, removed,
          changed, moved, or the entire list is
          refreshed.




          But it actually doesn't fire when an item is changed. I guess you'll need a more bruteforce method then:



          public class CollectionViewModel : ViewModelBase
          {
          public ObservableCollection<EntityViewModel> ContentList
          {
          get { return _contentList; }
          }

          public CollectionViewModel()
          {
          _contentList = new ObservableCollection<EntityViewModel>();
          _contentList.CollectionChanged += ContentCollectionChanged;
          }

          public void ContentCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
          {
          if (e.Action == NotifyCollectionChangedAction.Remove)
          {
          foreach(EntityViewModel item in e.OldItems)
          {
          //Removed items
          item.PropertyChanged -= EntityViewModelPropertyChanged;
          }
          }
          else if (e.Action == NotifyCollectionChangedAction.Add)
          {
          foreach(EntityViewModel item in e.NewItems)
          {
          //Added items
          item.PropertyChanged += EntityViewModelPropertyChanged;
          }
          }
          }

          public void EntityViewModelPropertyChanged(object sender, PropertyChangedEventArgs e)
          {
          //This will get called when the property of an object inside the collection changes
          }
          }


          If you are going to need this a lot you may want to subclass your own ObservableCollection that triggers the CollectionChanged event when a member triggers its PropertyChanged event automatically (like it says it should in the documentation...)






          share|improve this answer





















          • 30





            note that if you don't want to implement the event management yourself, you can use a BindingList<EntityViewModel> in place of ObservableCollection<EntityViewModel>. It will then automatically forward EntityViewModel.PropertyChanged events as ListChanged events where ListChangedType == ItemChanged.

            – mjeanes
            Sep 15 '09 at 15:35






          • 14





            Doesn't this all depend on your understanding of the term changed? This could mean that a property of one of the elements in the collection has changed (which is how I think you are interpreting it) or it could mean that one of the elements of the collection has been changed by replacing it with a different instance (this is my interpretation). Not totally convinced though - will have to look into it further.

            – belugabob
            Jul 6 '11 at 11:45






          • 9





            What happen if I invoke _contentList.Clear()? No one will unsubscribe from PropertyChanged!

            – Paolo Moretti
            Aug 3 '12 at 11:00






          • 2





            @Paolo: That's right, ContentCollectionChanged only handles Add/Remove, and not Replace/Reset. I'll try to edit and fix the post. The way simon does it in his answer is correct.

            – Mike Fuchs
            Mar 11 '13 at 12:55






          • 1





            See also stackoverflow.com/a/4588586/638977

            – Behzad Ebrahimi
            Apr 2 '16 at 7:16



















          169














          Here is a drop-in class that sub-classes ObservableCollection and actually raises a Reset action when a property on a list item changes. It enforces all items to implement INotifyPropertyChanged.



          The benefit here is that you can data bind to this class and all of your bindings will update with changes to your item properties.



          public sealed class TrulyObservableCollection<T> : ObservableCollection<T>
          where T : INotifyPropertyChanged
          {
          public TrulyObservableCollection()
          {
          CollectionChanged += FullObservableCollectionCollectionChanged;
          }

          public TrulyObservableCollection(IEnumerable<T> pItems) : this()
          {
          foreach (var item in pItems)
          {
          this.Add(item);
          }
          }

          private void FullObservableCollectionCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
          {
          if (e.NewItems != null)
          {
          foreach (Object item in e.NewItems)
          {
          ((INotifyPropertyChanged)item).PropertyChanged += ItemPropertyChanged;
          }
          }
          if (e.OldItems != null)
          {
          foreach (Object item in e.OldItems)
          {
          ((INotifyPropertyChanged)item).PropertyChanged -= ItemPropertyChanged;
          }
          }
          }

          private void ItemPropertyChanged(object sender, PropertyChangedEventArgs e)
          {
          NotifyCollectionChangedEventArgs args = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, sender, sender, IndexOf((T)sender));
          OnCollectionChanged(args);
          }
          }





          share|improve this answer





















          • 1





            might be worth short circuiting if e.Action == move?

            – jk.
            Jul 29 '11 at 15:56






          • 4





            I've had cause to implement something similar myself, however rather than use NotifyCollectionChangedAction.Reset I instead used .Replace: new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, item, item, IndexOf(item)).

            – Chris
            Apr 29 '13 at 15:34








          • 2





            Awesome solution to my problem - thank you! For those who created their ObservableCollection with a List, you may want to add a constructor that also itterates though all the items and adds PropertyChanged.

            – Gavin
            Jun 23 '13 at 8:41








          • 3





            There's a potential memory leak here - A Reset event happens when the collection is significantly changed, e.g. on Clear. None of your INPC handlers will be unsubscribed when this happens.

            – Charles Mager
            Apr 16 '15 at 6:57






          • 5





            this is an OK implementation but it has one major issue - the NotifyCollectionChangedAction.Replace is not a good idea, because then you can't distinguish between an item in fact being replaced or event caused by an item change. It gets much better when you define public event PropertyChangedEventHandler CollectionItemChanged; and then in ItemPropertyChanged do this.CollectionItemChanged?.Invoke(sender, e);

            – Hristo Yankov
            Dec 30 '16 at 17:06





















          18














          This uses the above ideas but makes it a derived 'more sensitive' collection:



          using System;
          using System.Collections.Generic;
          using System.Linq;
          using System.Text;
          using System.ComponentModel;
          using System.Collections.ObjectModel;
          using System.Collections.Specialized;
          using System.Collections;

          namespace somethingelse
          {
          public class ObservableCollectionEx<T> : ObservableCollection<T> where T : INotifyPropertyChanged
          {
          // this collection also reacts to changes in its components' properties

          public ObservableCollectionEx() : base()
          {
          this.CollectionChanged +=new System.Collections.Specialized.NotifyCollectionChangedEventHandler(ObservableCollectionEx_CollectionChanged);
          }

          void ObservableCollectionEx_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
          {
          if (e.Action == NotifyCollectionChangedAction.Remove)
          {
          foreach(T item in e.OldItems)
          {
          //Removed items
          item.PropertyChanged -= EntityViewModelPropertyChanged;
          }
          }
          else if (e.Action == NotifyCollectionChangedAction.Add)
          {
          foreach(T item in e.NewItems)
          {
          //Added items
          item.PropertyChanged += EntityViewModelPropertyChanged;
          }
          }
          }

          public void EntityViewModelPropertyChanged(object sender, PropertyChangedEventArgs e)
          {
          //This will get called when the property of an object inside the collection changes - note you must make it a 'reset' - dunno why
          NotifyCollectionChangedEventArgs args = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset);
          OnCollectionChanged(args);
          }
          }
          }





          share|improve this answer

































            15














            I've put together what I hope is a pretty robust solution, including some of the techniques in other answers. It is a new class derived from ObservableCollection<>, which I'm calling FullyObservableCollection<>



            It has the following features:




            • It adds a new event, ItemPropertyChanged. I've deliberately kept this separate from the existing CollectionChanged:


              • To aid backward compatibility.

              • So more relevant detail can be given in the new ItemPropertyChangedEventArgs that accompanies it: the original PropertyChangedEventArgs and the index within the collection.



            • It replicates all the constructors from ObservableCollection<>.

            • It correctly handles the list being reset (ObservableCollection<>.Clear()), avoiding a possible memory leak.

            • It overrides the base class's OnCollectionChanged(), rather than a more resource-intensive subscription to the CollectionChanged event.


            Code



            The complete .cs file follows. Note that a few features of C# 6 have been used, but it should be fairly simple to backport it:



            using System;
            using System.Collections.Generic;
            using System.Collections.ObjectModel;
            using System.Collections.Specialized;
            using System.ComponentModel;

            namespace Utilities
            {
            public class FullyObservableCollection<T> : ObservableCollection<T>
            where T : INotifyPropertyChanged
            {
            /// <summary>
            /// Occurs when a property is changed within an item.
            /// </summary>
            public event EventHandler<ItemPropertyChangedEventArgs> ItemPropertyChanged;

            public FullyObservableCollection() : base()
            { }

            public FullyObservableCollection(List<T> list) : base(list)
            {
            ObserveAll();
            }

            public FullyObservableCollection(IEnumerable<T> enumerable) : base(enumerable)
            {
            ObserveAll();
            }

            protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
            {
            if (e.Action == NotifyCollectionChangedAction.Remove ||
            e.Action == NotifyCollectionChangedAction.Replace)
            {
            foreach (T item in e.OldItems)
            item.PropertyChanged -= ChildPropertyChanged;
            }

            if (e.Action == NotifyCollectionChangedAction.Add ||
            e.Action == NotifyCollectionChangedAction.Replace)
            {
            foreach (T item in e.NewItems)
            item.PropertyChanged += ChildPropertyChanged;
            }

            base.OnCollectionChanged(e);
            }

            protected void OnItemPropertyChanged(ItemPropertyChangedEventArgs e)
            {
            ItemPropertyChanged?.Invoke(this, e);
            }

            protected void OnItemPropertyChanged(int index, PropertyChangedEventArgs e)
            {
            OnItemPropertyChanged(new ItemPropertyChangedEventArgs(index, e));
            }

            protected override void ClearItems()
            {
            foreach (T item in Items)
            item.PropertyChanged -= ChildPropertyChanged;

            base.ClearItems();
            }

            private void ObserveAll()
            {
            foreach (T item in Items)
            item.PropertyChanged += ChildPropertyChanged;
            }

            private void ChildPropertyChanged(object sender, PropertyChangedEventArgs e)
            {
            T typedSender = (T)sender;
            int i = Items.IndexOf(typedSender);

            if (i < 0)
            throw new ArgumentException("Received property notification from item not in collection");

            OnItemPropertyChanged(i, e);
            }
            }

            /// <summary>
            /// Provides data for the <see cref="FullyObservableCollection{T}.ItemPropertyChanged"/> event.
            /// </summary>
            public class ItemPropertyChangedEventArgs : PropertyChangedEventArgs
            {
            /// <summary>
            /// Gets the index in the collection for which the property change has occurred.
            /// </summary>
            /// <value>
            /// Index in parent collection.
            /// </value>
            public int CollectionIndex { get; }

            /// <summary>
            /// Initializes a new instance of the <see cref="ItemPropertyChangedEventArgs"/> class.
            /// </summary>
            /// <param name="index">The index in the collection of changed item.</param>
            /// <param name="name">The name of the property that changed.</param>
            public ItemPropertyChangedEventArgs(int index, string name) : base(name)
            {
            CollectionIndex = index;
            }

            /// <summary>
            /// Initializes a new instance of the <see cref="ItemPropertyChangedEventArgs"/> class.
            /// </summary>
            /// <param name="index">The index.</param>
            /// <param name="args">The <see cref="PropertyChangedEventArgs"/> instance containing the event data.</param>
            public ItemPropertyChangedEventArgs(int index, PropertyChangedEventArgs args) : this(index, args.PropertyName)
            { }
            }
            }


            NUnit Tests



            So you can check changes you might make (and see what I tested in the first place!), I've also included my NUnit test class. Obviously, the following code is not necessary just to use FullyObservableCollection<T> in your project.



            NB The test class uses BindableBase from PRISM to implement INotifyPropertyChanged. There is no dependency on PRISM from the main code.



            using NUnit.Framework;
            using Utilities;
            using Microsoft.Practices.Prism.Mvvm;
            using System.Collections.Specialized;
            using System.Collections.Generic;

            namespace Test_Utilities
            {
            [TestFixture]
            public class Test_FullyObservableCollection : AssertionHelper
            {
            public class NotifyingTestClass : BindableBase
            {
            public int Id
            {
            get { return _Id; }
            set { SetProperty(ref _Id, value); }
            }
            private int _Id;

            public string Name
            {
            get { return _Name; }
            set { SetProperty(ref _Name, value); }
            }
            private string _Name;

            }

            FullyObservableCollection<NotifyingTestClass> TestCollection;
            NotifyingTestClass Fred;
            NotifyingTestClass Betty;
            List<NotifyCollectionChangedEventArgs> CollectionEventList;
            List<ItemPropertyChangedEventArgs> ItemEventList;

            [SetUp]
            public void Init()
            {
            Fred = new NotifyingTestClass() { Id = 1, Name = "Fred" };
            Betty = new NotifyingTestClass() { Id = 4, Name = "Betty" };

            TestCollection = new FullyObservableCollection<NotifyingTestClass>()
            {
            Fred,
            new NotifyingTestClass() {Id = 2, Name = "Barney" },
            new NotifyingTestClass() {Id = 3, Name = "Wilma" }
            };

            CollectionEventList = new List<NotifyCollectionChangedEventArgs>();
            ItemEventList = new List<ItemPropertyChangedEventArgs>();
            TestCollection.CollectionChanged += (o, e) => CollectionEventList.Add(e);
            TestCollection.ItemPropertyChanged += (o, e) => ItemEventList.Add(e);
            }

            // Change existing member property: just ItemPropertyChanged(IPC) should fire
            [Test]
            public void DetectMemberPropertyChange()
            {
            TestCollection[0].Id = 7;

            Expect(CollectionEventList.Count, Is.EqualTo(0));

            Expect(ItemEventList.Count, Is.EqualTo(1), "IPC count");
            Expect(ItemEventList[0].PropertyName, Is.EqualTo(nameof(Fred.Id)), "Field Name");
            Expect(ItemEventList[0].CollectionIndex, Is.EqualTo(0), "Collection Index");
            }


            // Add new member, change property: CollectionPropertyChanged (CPC) and IPC should fire
            [Test]
            public void DetectNewMemberPropertyChange()
            {
            TestCollection.Add(Betty);

            Expect(TestCollection.Count, Is.EqualTo(4));
            Expect(TestCollection[3].Name, Is.EqualTo("Betty"));

            Expect(ItemEventList.Count, Is.EqualTo(0), "Item Event count");

            Expect(CollectionEventList.Count, Is.EqualTo(1), "Collection Event count");
            Expect(CollectionEventList[0].Action, Is.EqualTo(NotifyCollectionChangedAction.Add), "Action (add)");
            Expect(CollectionEventList[0].OldItems, Is.Null, "OldItems count");
            Expect(CollectionEventList[0].NewItems.Count, Is.EqualTo(1), "NewItems count");
            Expect(CollectionEventList[0].NewItems[0], Is.EqualTo(Betty), "NewItems[0] dereference");

            CollectionEventList.Clear(); // Empty for next operation
            ItemEventList.Clear();

            TestCollection[3].Id = 7;
            Expect(CollectionEventList.Count, Is.EqualTo(0), "Collection Event count");

            Expect(ItemEventList.Count, Is.EqualTo(1), "Item Event count");
            Expect(TestCollection[ItemEventList[0].CollectionIndex], Is.EqualTo(Betty), "Collection Index dereference");
            }


            // Remove member, change property: CPC should fire for removel, neither CPC nor IPC should fire for change
            [Test]
            public void CeaseListentingWhenMemberRemoved()
            {
            TestCollection.Remove(Fred);

            Expect(TestCollection.Count, Is.EqualTo(2));
            Expect(TestCollection.IndexOf(Fred), Is.Negative);

            Expect(ItemEventList.Count, Is.EqualTo(0), "Item Event count (pre change)");

            Expect(CollectionEventList.Count, Is.EqualTo(1), "Collection Event count (pre change)");
            Expect(CollectionEventList[0].Action, Is.EqualTo(NotifyCollectionChangedAction.Remove), "Action (remove)");
            Expect(CollectionEventList[0].OldItems.Count, Is.EqualTo(1), "OldItems count");
            Expect(CollectionEventList[0].NewItems, Is.Null, "NewItems count");
            Expect(CollectionEventList[0].OldItems[0], Is.EqualTo(Fred), "OldItems[0] dereference");

            CollectionEventList.Clear(); // Empty for next operation
            ItemEventList.Clear();

            Fred.Id = 7;
            Expect(CollectionEventList.Count, Is.EqualTo(0), "Collection Event count (post change)");
            Expect(ItemEventList.Count, Is.EqualTo(0), "Item Event count (post change)");
            }


            // Move member in list, change property: CPC should fire for move, IPC should fire for change
            [Test]
            public void MoveMember()
            {
            TestCollection.Move(0, 1);

            Expect(TestCollection.Count, Is.EqualTo(3));
            Expect(TestCollection.IndexOf(Fred), Is.GreaterThan(0));

            Expect(ItemEventList.Count, Is.EqualTo(0), "Item Event count (pre change)");

            Expect(CollectionEventList.Count, Is.EqualTo(1), "Collection Event count (pre change)");
            Expect(CollectionEventList[0].Action, Is.EqualTo(NotifyCollectionChangedAction.Move), "Action (move)");
            Expect(CollectionEventList[0].OldItems.Count, Is.EqualTo(1), "OldItems count");
            Expect(CollectionEventList[0].NewItems.Count, Is.EqualTo(1), "NewItems count");
            Expect(CollectionEventList[0].OldItems[0], Is.EqualTo(Fred), "OldItems[0] dereference");
            Expect(CollectionEventList[0].NewItems[0], Is.EqualTo(Fred), "NewItems[0] dereference");

            CollectionEventList.Clear(); // Empty for next operation
            ItemEventList.Clear();

            Fred.Id = 7;
            Expect(CollectionEventList.Count, Is.EqualTo(0), "Collection Event count (post change)");

            Expect(ItemEventList.Count, Is.EqualTo(1), "Item Event count (post change)");
            Expect(TestCollection[ItemEventList[0].CollectionIndex], Is.EqualTo(Fred), "Collection Index dereference");
            }


            // Clear list, chnage property: only CPC should fire for clear and neither for property change
            [Test]
            public void ClearList()
            {
            TestCollection.Clear();

            Expect(TestCollection.Count, Is.EqualTo(0));

            Expect(ItemEventList.Count, Is.EqualTo(0), "Item Event count (pre change)");

            Expect(CollectionEventList.Count, Is.EqualTo(1), "Collection Event count (pre change)");
            Expect(CollectionEventList[0].Action, Is.EqualTo(NotifyCollectionChangedAction.Reset), "Action (reset)");
            Expect(CollectionEventList[0].OldItems, Is.Null, "OldItems count");
            Expect(CollectionEventList[0].NewItems, Is.Null, "NewItems count");

            CollectionEventList.Clear(); // Empty for next operation
            ItemEventList.Clear();

            Fred.Id = 7;
            Expect(CollectionEventList.Count, Is.EqualTo(0), "Collection Event count (post change)");
            Expect(ItemEventList.Count, Is.EqualTo(0), "Item Event count (post change)");
            }
            }
            }





            share|improve this answer


























            • I don't know what I am doing wrong, but this doesn't work for me. I'm binding my ListView to your collection but when I update the properties of the items inside, the ListView doesn't update, even tho' I can see all the events firing up. I'm also using the PRISM library...

              – Renato Parreira
              Feb 24 '17 at 15:20











            • @Renato, have you done anything with the new event? ListView will respond to CollectionChanged events because it knows about them. ItemPropertyChanged is a non-standard addition, so you need to teach it about that. As a quick and dirty fix, you could try just firing the CollectionChanged event as well as (or even instead of) ItemPropertyChanged in OnItemPropertyChanged(). I kept them separate for reasons stated in the answer, but for your use-case it might just do what you need.

              – Bob Sammers
              Mar 2 '17 at 18:13





















            10














            ObservableCollection will not propagate individual item changes as CollectionChanged events. You will either need to subscribe to each event and forward it manually, or you can check out the BindingList[T] class, which will do this for you.






            share|improve this answer































              7














              Added to TruelyObservableCollection event "ItemPropertyChanged":



              using System;
              using System.Collections.Generic;
              using System.Collections.ObjectModel; // ObservableCollection
              using System.ComponentModel; // INotifyPropertyChanged
              using System.Collections.Specialized; // NotifyCollectionChangedEventHandler
              using System.Linq;
              using System.Text;
              using System.Threading.Tasks;

              namespace ObservableCollectionTest
              {
              class Program
              {
              static void Main(string args)
              {
              // ATTN: Please note it's a "TrulyObservableCollection" that's instantiated. Otherwise, "Trades[0].Qty = 999" will NOT trigger event handler "Trades_CollectionChanged" in main.
              // REF: http://stackoverflow.com/questions/8490533/notify-observablecollection-when-item-changes
              TrulyObservableCollection<Trade> Trades = new TrulyObservableCollection<Trade>();
              Trades.Add(new Trade { Symbol = "APPL", Qty = 123 });
              Trades.Add(new Trade { Symbol = "IBM", Qty = 456});
              Trades.Add(new Trade { Symbol = "CSCO", Qty = 789 });

              Trades.CollectionChanged += Trades_CollectionChanged;
              Trades.ItemPropertyChanged += PropertyChangedHandler;
              Trades.RemoveAt(2);

              Trades[0].Qty = 999;

              Console.WriteLine("Hit any key to exit");
              Console.ReadLine();

              return;
              }

              static void PropertyChangedHandler(object sender, PropertyChangedEventArgs e)
              {
              Console.WriteLine(DateTime.Now.ToString() + ", Property changed: " + e.PropertyName + ", Symbol: " + ((Trade) sender).Symbol + ", Qty: " + ((Trade) sender).Qty);
              return;
              }

              static void Trades_CollectionChanged(object sender, EventArgs e)
              {
              Console.WriteLine(DateTime.Now.ToString() + ", Collection changed");
              return;
              }
              }

              #region TrulyObservableCollection
              public class TrulyObservableCollection<T> : ObservableCollection<T>
              where T : INotifyPropertyChanged
              {
              public event PropertyChangedEventHandler ItemPropertyChanged;

              public TrulyObservableCollection()
              : base()
              {
              CollectionChanged += new NotifyCollectionChangedEventHandler(TrulyObservableCollection_CollectionChanged);
              }

              void TrulyObservableCollection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
              {
              if (e.NewItems != null)
              {
              foreach (Object item in e.NewItems)
              {
              (item as INotifyPropertyChanged).PropertyChanged += new PropertyChangedEventHandler(item_PropertyChanged);
              }
              }
              if (e.OldItems != null)
              {
              foreach (Object item in e.OldItems)
              {
              (item as INotifyPropertyChanged).PropertyChanged -= new PropertyChangedEventHandler(item_PropertyChanged);
              }
              }
              }

              void item_PropertyChanged(object sender, PropertyChangedEventArgs e)
              {
              NotifyCollectionChangedEventArgs a = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset);
              OnCollectionChanged(a);

              if (ItemPropertyChanged != null)
              {
              ItemPropertyChanged(sender, e);
              }
              }
              }
              #endregion

              #region Sample entity
              class Trade : INotifyPropertyChanged
              {
              protected string _Symbol;
              protected int _Qty = 0;
              protected DateTime _OrderPlaced = DateTime.Now;

              public DateTime OrderPlaced
              {
              get { return _OrderPlaced; }
              }

              public string Symbol
              {
              get
              {
              return _Symbol;
              }
              set
              {
              _Symbol = value;
              NotifyPropertyChanged("Symbol");
              }
              }

              public int Qty
              {
              get
              {
              return _Qty;
              }
              set
              {
              _Qty = value;
              NotifyPropertyChanged("Qty");
              }
              }

              public event PropertyChangedEventHandler PropertyChanged;

              private void NotifyPropertyChanged(String propertyName = "")
              {
              if (PropertyChanged != null)
              {
              PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
              }
              }
              }
              #endregion
              }





              share|improve this answer
























              • You could use PropertyChanged from ObservableCollection directly, since it implements INotifyPropertyChanged.

                – Dieter Meemken
                Jun 3 '16 at 14:23



















              6














              I used Jack Kenyons answer to implement my own OC, but I'd like to point out one change i had to make to make it work. Instead of:



                  if (e.Action == NotifyCollectionChangedAction.Remove)
              {
              foreach(T item in e.NewItems)
              {
              //Removed items
              item.PropertyChanged -= EntityViewModelPropertyChanged;
              }
              }


              I used this:



                  if (e.Action == NotifyCollectionChangedAction.Remove)
              {
              foreach(T item in e.OldItems)
              {
              //Removed items
              item.PropertyChanged -= EntityViewModelPropertyChanged;
              }
              }


              It seems that the "e.NewItems" produces null if action is .Remove.






              share|improve this answer
























              • I think it needs further changes as well what if e.Action == replace

                – jk.
                Jul 29 '11 at 15:53



















              6














              Just adding my 2 cents on this topic. Felt the TrulyObservableCollection required the two other constructors as found with ObservableCollection:



              public TrulyObservableCollection()
              : base()
              {
              HookupCollectionChangedEvent();
              }

              public TrulyObservableCollection(IEnumerable<T> collection)
              : base(collection)
              {
              foreach (T item in collection)
              item.PropertyChanged += ItemPropertyChanged;

              HookupCollectionChangedEvent();
              }

              public TrulyObservableCollection(List<T> list)
              : base(list)
              {
              list.ForEach(item => item.PropertyChanged += ItemPropertyChanged);

              HookupCollectionChangedEvent();
              }

              private void HookupCollectionChangedEvent()
              {
              CollectionChanged += new NotifyCollectionChangedEventHandler(TrulyObservableCollectionChanged);
              }





              share|improve this answer































                5














                I know that I'm too late for this party, but maybe - it will help to someone..



                Here you can find my implementation of ObservableCollectionEx. It has some features:




                • it supports everything from ObservableCollection

                • it's thread safe

                • it supports ItemPropertyChanged event (it raises each time when Item.PropertyChanged item is fired)

                • it supports filters (so, you could create ObservableCollectionEx, pass another collection as Source to it, and Filter with simple predicate. Very useful in WPF, I use this feature a lot in my applications). Even more - filter tracks changes of items via INotifyPropertyChanged interface.


                Of course, any comments are appreciated ;)






                share|improve this answer



















                • 1





                  Большое спасибо! Many thanks for sharing that! You saved me numerous hours by not having to write my own implementation! :)

                  – Alexander
                  Jul 7 '13 at 6:23













                • @Alexander you're very wellcome :)

                  – chopikadze
                  Jul 7 '13 at 12:02













                • @chopikadze, i am unable to download the cs file of your ObservableCollectionEx can you kindly fix it. Thanks

                  – Shax
                  Jan 11 '17 at 8:06











                • The link is dead.

                  – user2655904
                  Jul 31 '17 at 5:39



















                1














                Simple solution for standard observablecollection that I've used:



                DO NOT ADD to your property OR CHANGE it's inner items DIRECTLY, instead, create some temp collection like this



                ObservableCollection<EntityViewModel> tmpList= new ObservableCollection<EntityViewModel>();


                and add items or make changes to tmpList,



                tmpList.Add(new EntityViewModel(){IsRowChecked=false}); //Example
                tmpList[0].IsRowChecked= true; //Example
                ...


                then pass it to your actual property by assignment.



                ContentList=tmpList;


                this will change whole property which causes notice the INotifyPropertyChanged as you need.






                share|improve this answer

































                  1














                  I try this solution, but only works for me like a RaisePropertyChange("SourceGroupeGridView") when collection changed, that fired for each item add or changed.



                  The problem is in:



                  public void EntityViewModelPropertyChanged(object sender, PropertyChangedEventArgs e)
                  {
                  NotifyCollectionChangedEventArgs args = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset);
                  OnCollectionChanged(args);
                  }


                  NotifyCollectionChangedAction.Reset this action make a complete rebind of all items in groupedgrid, is equivalent at RaisePropertyChanged. When you use it all groups of gridview refreshed.



                  IF you, only want to refresh in UI the group of the new item, you don't use Reset action, you will need simulate a Add action in itemproperty with something like this:



                  void item_PropertyChanged(object sender, PropertyChangedEventArgs e)
                  {
                  var index = this.IndexOf((T)sender);

                  this.RemoveAt(index);
                  this.Insert(index, (T)sender);

                  var a = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, sender);
                  OnCollectionChanged(a);
                  }


                  Sorry by my english, and thanks for the base code :),
                  I hope this helps someone ^_^



                  Enjoi!!






                  share|improve this answer

































                    1














                    Here's an extension method for the above solution...



                    public static TrulyObservableCollection<T> ToTrulyObservableCollection<T>(this List<T> list)
                    where T : INotifyPropertyChanged
                    {
                    var newList = new TrulyObservableCollection<T>();

                    if (list != null)
                    {
                    list.ForEach(o => newList.Add(o));
                    }

                    return newList;
                    }





                    share|improve this answer


























                    • You may want to explain the answer

                      – geedubb
                      Oct 23 '18 at 15:43






                    • 1





                      Here's a link that describes extension methods. docs.microsoft.com/en-us/dotnet/csharp/programming-guide/…

                      – LawMan
                      Oct 23 '18 at 19:18





















                    1














                    Instead of an ObservableCollection or TrulyObservableCollection, consider using a BindingList and calling the ResetBindings method.



                    For example:



                    private BindingList<TfsFile> _tfsFiles;

                    public BindingList<TfsFile> TfsFiles
                    {
                    get { return _tfsFiles; }
                    set
                    {
                    _tfsFiles = value;
                    NotifyPropertyChanged();
                    }
                    }


                    Given an event, such as a click your code would look like this:



                    foreach (var file in TfsFiles)
                    {
                    SelectedFile = file;
                    file.Name = "Different Text";
                    TfsFiles.ResetBindings();
                    }


                    My model looked like this:



                    namespace Models
                    {
                    public class TfsFile
                    {
                    public string ImagePath { get; set; }

                    public string FullPath { get; set; }

                    public string Name { get; set; }

                    public string Text { get; set; }

                    }
                    }





                    share|improve this answer





















                    • 1





                      Good info on this method of BindingList, but there is a limitation to this approach that the other answers overcome: this technique relies on the value being changed in code and where a call to ResetBindings() can be added. Most of the other answers will work if the list's objects are altered through other means, such as unalterable code or from a binding to a second control.

                      – Bob Sammers
                      Mar 2 '17 at 18:44



















                    1














                    If i know ObservableCollection make event only when we add/delete or move items in our collection. When we simly update some properties in collection items collection don`t signalize about it and UI will not be updated.



                    You can simly implement INotifyPropertyChange in your Model class.
                    And than when we update some propery in collection item it automatically will update UI.



                    public class Model:INotifyPropertyChange
                    {
                    //...
                    }


                    and than



                    public ObservableCollection<Model> {get; set;}


                    In my case i used ListView to Bind for this collection and in ItemTemplate set Binding to Model property and it work good.



                    Here is some snippet



                    Windows XAML :



                    <Window.DataContext>
                    <local:ViewModel/>
                    </Window.DataContext>
                    <Grid>
                    <Grid.RowDefinitions>
                    <RowDefinition/>
                    <RowDefinition/>
                    </Grid.RowDefinitions>
                    <ListView
                    Margin="10"
                    BorderBrush="Black"
                    HorizontalAlignment="Center"
                    SelectedItem="{Binding SelectedPerson}"
                    ItemsSource="{Binding Persons}">
                    <ListView.ItemTemplate>
                    <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                    <Label Content="{Binding Name}"/>
                    <Label Content="-"/>
                    <Label Content="{Binding Age}"/>
                    </StackPanel>
                    </DataTemplate>
                    </ListView.ItemTemplate>
                    </ListView>
                    <Grid
                    Grid.Row="1"
                    VerticalAlignment="Center"
                    HorizontalAlignment="Center">
                    <Grid.ColumnDefinitions>
                    <ColumnDefinition/>
                    <ColumnDefinition/>
                    </Grid.ColumnDefinitions>
                    <Grid.RowDefinitions>
                    <RowDefinition/>
                    <RowDefinition/>
                    <RowDefinition/>
                    </Grid.RowDefinitions>
                    <Label
                    VerticalAlignment="Center"
                    Content="Name:"/>
                    <TextBox
                    Text="{Binding SelectedPerson.Name,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
                    Margin="10"
                    Grid.Column="1"
                    Width="100"/>
                    <Label
                    VerticalAlignment="Center"
                    Grid.Row="1"
                    Content="Age:"/>
                    <TextBox
                    Text="{Binding SelectedPerson.Age,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
                    Margin="10"
                    Grid.Row="1"
                    Grid.Column="1"
                    Width="100"/>


                    </Grid>
                    </Grid>


                    Model code example:



                    public class PersonModel:INotifyPropertyChanged
                    {
                    public string Name
                    {
                    get => _name;
                    set
                    {
                    _name = value;
                    OnPropertyChanged();
                    }
                    }

                    public int Age
                    {
                    get => _age;
                    set
                    {
                    _age = value;
                    OnPropertyChanged();
                    }
                    }

                    private string _name;
                    private int _age;
                    //INotifyPropertyChanged implementation
                    public event PropertyChangedEventHandler PropertyChanged;
                    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
                    {
                    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
                    }
                    }


                    And ViewModel implementation:



                     public class ViewModel:INotifyPropertyChanged
                    {
                    public ViewModel()
                    {
                    Persons = new ObservableCollection<PersonModel>
                    {
                    new PersonModel
                    {
                    Name = "Jack",
                    Age = 30
                    },
                    new PersonModel
                    {
                    Name = "Jon",
                    Age = 23
                    },
                    new PersonModel
                    {
                    Name = "Max",
                    Age = 23
                    },
                    };
                    }

                    public ObservableCollection<PersonModel> Persons { get;}

                    public PersonModel SelectedPerson
                    {
                    get => _selectedPerson;
                    set
                    {
                    _selectedPerson = value;
                    OnPropertyChanged();
                    }
                    }

                    //INotifyPropertyChanged Implementation
                    public event PropertyChangedEventHandler PropertyChanged;
                    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
                    {
                    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
                    }

                    private PersonModel _selectedPerson;
                    }





                    share|improve this answer

































                      0














                      Here is my version of the implementation. It checks and throws an error, if the objects in list doesnt implement INotifyPropertyChanged, so can't forget that issue while developing. On the outside you use the ListItemChanged Event do determine whether the list or the list item itself has changed.



                      public class SpecialObservableCollection<T> : ObservableCollection<T>
                      {
                      public SpecialObservableCollection()
                      {
                      this.CollectionChanged += OnCollectionChanged;
                      }

                      void OnCollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
                      {
                      AddOrRemoveListToPropertyChanged(e.NewItems,true);
                      AddOrRemoveListToPropertyChanged(e.OldItems,false);
                      }

                      private void AddOrRemoveListToPropertyChanged(IList list, Boolean add)
                      {
                      if (list == null) { return; }
                      foreach (object item in list)
                      {
                      INotifyPropertyChanged o = item as INotifyPropertyChanged;
                      if (o != null)
                      {
                      if (add) { o.PropertyChanged += ListItemPropertyChanged; }
                      if (!add) { o.PropertyChanged -= ListItemPropertyChanged; }
                      }
                      else
                      {
                      throw new Exception("INotifyPropertyChanged is required");
                      }
                      }
                      }

                      void ListItemPropertyChanged(object sender, PropertyChangedEventArgs e)
                      {
                      OnListItemChanged(this, e);
                      }

                      public delegate void ListItemChangedEventHandler(object sender, PropertyChangedEventArgs e);

                      public event ListItemChangedEventHandler ListItemChanged;

                      private void OnListItemChanged(Object sender, PropertyChangedEventArgs e)
                      {
                      if (ListItemChanged != null) { this.ListItemChanged(this, e); }
                      }


                      }





                      share|improve this answer

































                        0














                        Simple solution in 2 lines of code. Just use the copy constructor.
                        No need to write TrulyObservableCollection etc.



                        Example:



                                speakers.list[0].Status = "offline";
                        speakers.list[0] = new Speaker(speakers.list[0]);


                        Another method without copy constructor. You can use serialization.



                                speakers.list[0].Status = "offline";
                        //speakers.list[0] = new Speaker(speakers.list[0]);
                        var tmp = JsonConvert.SerializeObject(speakers.list[0]);
                        var tmp2 = JsonConvert.DeserializeObject<Speaker>(tmp);
                        speakers.list[0] = tmp2;





                        share|improve this answer

























                          Your Answer






                          StackExchange.ifUsing("editor", function () {
                          StackExchange.using("externalEditor", function () {
                          StackExchange.using("snippets", function () {
                          StackExchange.snippets.init();
                          });
                          });
                          }, "code-snippets");

                          StackExchange.ready(function() {
                          var channelOptions = {
                          tags: "".split(" "),
                          id: "1"
                          };
                          initTagRenderer("".split(" "), "".split(" "), channelOptions);

                          StackExchange.using("externalEditor", function() {
                          // Have to fire editor after snippets, if snippets enabled
                          if (StackExchange.settings.snippets.snippetsEnabled) {
                          StackExchange.using("snippets", function() {
                          createEditor();
                          });
                          }
                          else {
                          createEditor();
                          }
                          });

                          function createEditor() {
                          StackExchange.prepareEditor({
                          heartbeatType: 'answer',
                          autoActivateHeartbeat: false,
                          convertImagesToLinks: true,
                          noModals: true,
                          showLowRepImageUploadWarning: true,
                          reputationToPostImages: 10,
                          bindNavPrevention: true,
                          postfix: "",
                          imageUploader: {
                          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
                          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
                          allowUrls: true
                          },
                          onDemand: true,
                          discardSelector: ".discard-answer"
                          ,immediatelyShowMarkdownHelp:true
                          });


                          }
                          });














                          draft saved

                          draft discarded


















                          StackExchange.ready(
                          function () {
                          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f1427471%2fobservablecollection-not-noticing-when-item-in-it-changes-even-with-inotifyprop%23new-answer', 'question_page');
                          }
                          );

                          Post as a guest















                          Required, but never shown

























                          16 Answers
                          16






                          active

                          oldest

                          votes








                          16 Answers
                          16






                          active

                          oldest

                          votes









                          active

                          oldest

                          votes






                          active

                          oldest

                          votes









                          107














                          The ContentList's Set method will not get called when you change a value inside the collection, instead you should be looking out for the CollectionChanged event firing.



                          public class CollectionViewModel : ViewModelBase
                          {
                          public ObservableCollection<EntityViewModel> ContentList
                          {
                          get { return _contentList; }
                          }

                          public CollectionViewModel()
                          {
                          _contentList = new ObservableCollection<EntityViewModel>();
                          _contentList.CollectionChanged += ContentCollectionChanged;
                          }

                          public void ContentCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
                          {
                          //This will get called when the collection is changed
                          }
                          }




                          Okay, that's twice today I've been bitten by the MSDN documentation being wrong. In the link I gave you it says:




                          Occurs when an item is added, removed,
                          changed, moved, or the entire list is
                          refreshed.




                          But it actually doesn't fire when an item is changed. I guess you'll need a more bruteforce method then:



                          public class CollectionViewModel : ViewModelBase
                          {
                          public ObservableCollection<EntityViewModel> ContentList
                          {
                          get { return _contentList; }
                          }

                          public CollectionViewModel()
                          {
                          _contentList = new ObservableCollection<EntityViewModel>();
                          _contentList.CollectionChanged += ContentCollectionChanged;
                          }

                          public void ContentCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
                          {
                          if (e.Action == NotifyCollectionChangedAction.Remove)
                          {
                          foreach(EntityViewModel item in e.OldItems)
                          {
                          //Removed items
                          item.PropertyChanged -= EntityViewModelPropertyChanged;
                          }
                          }
                          else if (e.Action == NotifyCollectionChangedAction.Add)
                          {
                          foreach(EntityViewModel item in e.NewItems)
                          {
                          //Added items
                          item.PropertyChanged += EntityViewModelPropertyChanged;
                          }
                          }
                          }

                          public void EntityViewModelPropertyChanged(object sender, PropertyChangedEventArgs e)
                          {
                          //This will get called when the property of an object inside the collection changes
                          }
                          }


                          If you are going to need this a lot you may want to subclass your own ObservableCollection that triggers the CollectionChanged event when a member triggers its PropertyChanged event automatically (like it says it should in the documentation...)






                          share|improve this answer





















                          • 30





                            note that if you don't want to implement the event management yourself, you can use a BindingList<EntityViewModel> in place of ObservableCollection<EntityViewModel>. It will then automatically forward EntityViewModel.PropertyChanged events as ListChanged events where ListChangedType == ItemChanged.

                            – mjeanes
                            Sep 15 '09 at 15:35






                          • 14





                            Doesn't this all depend on your understanding of the term changed? This could mean that a property of one of the elements in the collection has changed (which is how I think you are interpreting it) or it could mean that one of the elements of the collection has been changed by replacing it with a different instance (this is my interpretation). Not totally convinced though - will have to look into it further.

                            – belugabob
                            Jul 6 '11 at 11:45






                          • 9





                            What happen if I invoke _contentList.Clear()? No one will unsubscribe from PropertyChanged!

                            – Paolo Moretti
                            Aug 3 '12 at 11:00






                          • 2





                            @Paolo: That's right, ContentCollectionChanged only handles Add/Remove, and not Replace/Reset. I'll try to edit and fix the post. The way simon does it in his answer is correct.

                            – Mike Fuchs
                            Mar 11 '13 at 12:55






                          • 1





                            See also stackoverflow.com/a/4588586/638977

                            – Behzad Ebrahimi
                            Apr 2 '16 at 7:16
















                          107














                          The ContentList's Set method will not get called when you change a value inside the collection, instead you should be looking out for the CollectionChanged event firing.



                          public class CollectionViewModel : ViewModelBase
                          {
                          public ObservableCollection<EntityViewModel> ContentList
                          {
                          get { return _contentList; }
                          }

                          public CollectionViewModel()
                          {
                          _contentList = new ObservableCollection<EntityViewModel>();
                          _contentList.CollectionChanged += ContentCollectionChanged;
                          }

                          public void ContentCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
                          {
                          //This will get called when the collection is changed
                          }
                          }




                          Okay, that's twice today I've been bitten by the MSDN documentation being wrong. In the link I gave you it says:




                          Occurs when an item is added, removed,
                          changed, moved, or the entire list is
                          refreshed.




                          But it actually doesn't fire when an item is changed. I guess you'll need a more bruteforce method then:



                          public class CollectionViewModel : ViewModelBase
                          {
                          public ObservableCollection<EntityViewModel> ContentList
                          {
                          get { return _contentList; }
                          }

                          public CollectionViewModel()
                          {
                          _contentList = new ObservableCollection<EntityViewModel>();
                          _contentList.CollectionChanged += ContentCollectionChanged;
                          }

                          public void ContentCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
                          {
                          if (e.Action == NotifyCollectionChangedAction.Remove)
                          {
                          foreach(EntityViewModel item in e.OldItems)
                          {
                          //Removed items
                          item.PropertyChanged -= EntityViewModelPropertyChanged;
                          }
                          }
                          else if (e.Action == NotifyCollectionChangedAction.Add)
                          {
                          foreach(EntityViewModel item in e.NewItems)
                          {
                          //Added items
                          item.PropertyChanged += EntityViewModelPropertyChanged;
                          }
                          }
                          }

                          public void EntityViewModelPropertyChanged(object sender, PropertyChangedEventArgs e)
                          {
                          //This will get called when the property of an object inside the collection changes
                          }
                          }


                          If you are going to need this a lot you may want to subclass your own ObservableCollection that triggers the CollectionChanged event when a member triggers its PropertyChanged event automatically (like it says it should in the documentation...)






                          share|improve this answer





















                          • 30





                            note that if you don't want to implement the event management yourself, you can use a BindingList<EntityViewModel> in place of ObservableCollection<EntityViewModel>. It will then automatically forward EntityViewModel.PropertyChanged events as ListChanged events where ListChangedType == ItemChanged.

                            – mjeanes
                            Sep 15 '09 at 15:35






                          • 14





                            Doesn't this all depend on your understanding of the term changed? This could mean that a property of one of the elements in the collection has changed (which is how I think you are interpreting it) or it could mean that one of the elements of the collection has been changed by replacing it with a different instance (this is my interpretation). Not totally convinced though - will have to look into it further.

                            – belugabob
                            Jul 6 '11 at 11:45






                          • 9





                            What happen if I invoke _contentList.Clear()? No one will unsubscribe from PropertyChanged!

                            – Paolo Moretti
                            Aug 3 '12 at 11:00






                          • 2





                            @Paolo: That's right, ContentCollectionChanged only handles Add/Remove, and not Replace/Reset. I'll try to edit and fix the post. The way simon does it in his answer is correct.

                            – Mike Fuchs
                            Mar 11 '13 at 12:55






                          • 1





                            See also stackoverflow.com/a/4588586/638977

                            – Behzad Ebrahimi
                            Apr 2 '16 at 7:16














                          107












                          107








                          107







                          The ContentList's Set method will not get called when you change a value inside the collection, instead you should be looking out for the CollectionChanged event firing.



                          public class CollectionViewModel : ViewModelBase
                          {
                          public ObservableCollection<EntityViewModel> ContentList
                          {
                          get { return _contentList; }
                          }

                          public CollectionViewModel()
                          {
                          _contentList = new ObservableCollection<EntityViewModel>();
                          _contentList.CollectionChanged += ContentCollectionChanged;
                          }

                          public void ContentCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
                          {
                          //This will get called when the collection is changed
                          }
                          }




                          Okay, that's twice today I've been bitten by the MSDN documentation being wrong. In the link I gave you it says:




                          Occurs when an item is added, removed,
                          changed, moved, or the entire list is
                          refreshed.




                          But it actually doesn't fire when an item is changed. I guess you'll need a more bruteforce method then:



                          public class CollectionViewModel : ViewModelBase
                          {
                          public ObservableCollection<EntityViewModel> ContentList
                          {
                          get { return _contentList; }
                          }

                          public CollectionViewModel()
                          {
                          _contentList = new ObservableCollection<EntityViewModel>();
                          _contentList.CollectionChanged += ContentCollectionChanged;
                          }

                          public void ContentCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
                          {
                          if (e.Action == NotifyCollectionChangedAction.Remove)
                          {
                          foreach(EntityViewModel item in e.OldItems)
                          {
                          //Removed items
                          item.PropertyChanged -= EntityViewModelPropertyChanged;
                          }
                          }
                          else if (e.Action == NotifyCollectionChangedAction.Add)
                          {
                          foreach(EntityViewModel item in e.NewItems)
                          {
                          //Added items
                          item.PropertyChanged += EntityViewModelPropertyChanged;
                          }
                          }
                          }

                          public void EntityViewModelPropertyChanged(object sender, PropertyChangedEventArgs e)
                          {
                          //This will get called when the property of an object inside the collection changes
                          }
                          }


                          If you are going to need this a lot you may want to subclass your own ObservableCollection that triggers the CollectionChanged event when a member triggers its PropertyChanged event automatically (like it says it should in the documentation...)






                          share|improve this answer















                          The ContentList's Set method will not get called when you change a value inside the collection, instead you should be looking out for the CollectionChanged event firing.



                          public class CollectionViewModel : ViewModelBase
                          {
                          public ObservableCollection<EntityViewModel> ContentList
                          {
                          get { return _contentList; }
                          }

                          public CollectionViewModel()
                          {
                          _contentList = new ObservableCollection<EntityViewModel>();
                          _contentList.CollectionChanged += ContentCollectionChanged;
                          }

                          public void ContentCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
                          {
                          //This will get called when the collection is changed
                          }
                          }




                          Okay, that's twice today I've been bitten by the MSDN documentation being wrong. In the link I gave you it says:




                          Occurs when an item is added, removed,
                          changed, moved, or the entire list is
                          refreshed.




                          But it actually doesn't fire when an item is changed. I guess you'll need a more bruteforce method then:



                          public class CollectionViewModel : ViewModelBase
                          {
                          public ObservableCollection<EntityViewModel> ContentList
                          {
                          get { return _contentList; }
                          }

                          public CollectionViewModel()
                          {
                          _contentList = new ObservableCollection<EntityViewModel>();
                          _contentList.CollectionChanged += ContentCollectionChanged;
                          }

                          public void ContentCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
                          {
                          if (e.Action == NotifyCollectionChangedAction.Remove)
                          {
                          foreach(EntityViewModel item in e.OldItems)
                          {
                          //Removed items
                          item.PropertyChanged -= EntityViewModelPropertyChanged;
                          }
                          }
                          else if (e.Action == NotifyCollectionChangedAction.Add)
                          {
                          foreach(EntityViewModel item in e.NewItems)
                          {
                          //Added items
                          item.PropertyChanged += EntityViewModelPropertyChanged;
                          }
                          }
                          }

                          public void EntityViewModelPropertyChanged(object sender, PropertyChangedEventArgs e)
                          {
                          //This will get called when the property of an object inside the collection changes
                          }
                          }


                          If you are going to need this a lot you may want to subclass your own ObservableCollection that triggers the CollectionChanged event when a member triggers its PropertyChanged event automatically (like it says it should in the documentation...)







                          share|improve this answer














                          share|improve this answer



                          share|improve this answer








                          edited Feb 9 '18 at 23:27









                          Robert Harvey

                          149k33276420




                          149k33276420










                          answered Sep 15 '09 at 14:21









                          Martin HarrisMartin Harris

                          24.5k57992




                          24.5k57992








                          • 30





                            note that if you don't want to implement the event management yourself, you can use a BindingList<EntityViewModel> in place of ObservableCollection<EntityViewModel>. It will then automatically forward EntityViewModel.PropertyChanged events as ListChanged events where ListChangedType == ItemChanged.

                            – mjeanes
                            Sep 15 '09 at 15:35






                          • 14





                            Doesn't this all depend on your understanding of the term changed? This could mean that a property of one of the elements in the collection has changed (which is how I think you are interpreting it) or it could mean that one of the elements of the collection has been changed by replacing it with a different instance (this is my interpretation). Not totally convinced though - will have to look into it further.

                            – belugabob
                            Jul 6 '11 at 11:45






                          • 9





                            What happen if I invoke _contentList.Clear()? No one will unsubscribe from PropertyChanged!

                            – Paolo Moretti
                            Aug 3 '12 at 11:00






                          • 2





                            @Paolo: That's right, ContentCollectionChanged only handles Add/Remove, and not Replace/Reset. I'll try to edit and fix the post. The way simon does it in his answer is correct.

                            – Mike Fuchs
                            Mar 11 '13 at 12:55






                          • 1





                            See also stackoverflow.com/a/4588586/638977

                            – Behzad Ebrahimi
                            Apr 2 '16 at 7:16














                          • 30





                            note that if you don't want to implement the event management yourself, you can use a BindingList<EntityViewModel> in place of ObservableCollection<EntityViewModel>. It will then automatically forward EntityViewModel.PropertyChanged events as ListChanged events where ListChangedType == ItemChanged.

                            – mjeanes
                            Sep 15 '09 at 15:35






                          • 14





                            Doesn't this all depend on your understanding of the term changed? This could mean that a property of one of the elements in the collection has changed (which is how I think you are interpreting it) or it could mean that one of the elements of the collection has been changed by replacing it with a different instance (this is my interpretation). Not totally convinced though - will have to look into it further.

                            – belugabob
                            Jul 6 '11 at 11:45






                          • 9





                            What happen if I invoke _contentList.Clear()? No one will unsubscribe from PropertyChanged!

                            – Paolo Moretti
                            Aug 3 '12 at 11:00






                          • 2





                            @Paolo: That's right, ContentCollectionChanged only handles Add/Remove, and not Replace/Reset. I'll try to edit and fix the post. The way simon does it in his answer is correct.

                            – Mike Fuchs
                            Mar 11 '13 at 12:55






                          • 1





                            See also stackoverflow.com/a/4588586/638977

                            – Behzad Ebrahimi
                            Apr 2 '16 at 7:16








                          30




                          30





                          note that if you don't want to implement the event management yourself, you can use a BindingList<EntityViewModel> in place of ObservableCollection<EntityViewModel>. It will then automatically forward EntityViewModel.PropertyChanged events as ListChanged events where ListChangedType == ItemChanged.

                          – mjeanes
                          Sep 15 '09 at 15:35





                          note that if you don't want to implement the event management yourself, you can use a BindingList<EntityViewModel> in place of ObservableCollection<EntityViewModel>. It will then automatically forward EntityViewModel.PropertyChanged events as ListChanged events where ListChangedType == ItemChanged.

                          – mjeanes
                          Sep 15 '09 at 15:35




                          14




                          14





                          Doesn't this all depend on your understanding of the term changed? This could mean that a property of one of the elements in the collection has changed (which is how I think you are interpreting it) or it could mean that one of the elements of the collection has been changed by replacing it with a different instance (this is my interpretation). Not totally convinced though - will have to look into it further.

                          – belugabob
                          Jul 6 '11 at 11:45





                          Doesn't this all depend on your understanding of the term changed? This could mean that a property of one of the elements in the collection has changed (which is how I think you are interpreting it) or it could mean that one of the elements of the collection has been changed by replacing it with a different instance (this is my interpretation). Not totally convinced though - will have to look into it further.

                          – belugabob
                          Jul 6 '11 at 11:45




                          9




                          9





                          What happen if I invoke _contentList.Clear()? No one will unsubscribe from PropertyChanged!

                          – Paolo Moretti
                          Aug 3 '12 at 11:00





                          What happen if I invoke _contentList.Clear()? No one will unsubscribe from PropertyChanged!

                          – Paolo Moretti
                          Aug 3 '12 at 11:00




                          2




                          2





                          @Paolo: That's right, ContentCollectionChanged only handles Add/Remove, and not Replace/Reset. I'll try to edit and fix the post. The way simon does it in his answer is correct.

                          – Mike Fuchs
                          Mar 11 '13 at 12:55





                          @Paolo: That's right, ContentCollectionChanged only handles Add/Remove, and not Replace/Reset. I'll try to edit and fix the post. The way simon does it in his answer is correct.

                          – Mike Fuchs
                          Mar 11 '13 at 12:55




                          1




                          1





                          See also stackoverflow.com/a/4588586/638977

                          – Behzad Ebrahimi
                          Apr 2 '16 at 7:16





                          See also stackoverflow.com/a/4588586/638977

                          – Behzad Ebrahimi
                          Apr 2 '16 at 7:16













                          169














                          Here is a drop-in class that sub-classes ObservableCollection and actually raises a Reset action when a property on a list item changes. It enforces all items to implement INotifyPropertyChanged.



                          The benefit here is that you can data bind to this class and all of your bindings will update with changes to your item properties.



                          public sealed class TrulyObservableCollection<T> : ObservableCollection<T>
                          where T : INotifyPropertyChanged
                          {
                          public TrulyObservableCollection()
                          {
                          CollectionChanged += FullObservableCollectionCollectionChanged;
                          }

                          public TrulyObservableCollection(IEnumerable<T> pItems) : this()
                          {
                          foreach (var item in pItems)
                          {
                          this.Add(item);
                          }
                          }

                          private void FullObservableCollectionCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
                          {
                          if (e.NewItems != null)
                          {
                          foreach (Object item in e.NewItems)
                          {
                          ((INotifyPropertyChanged)item).PropertyChanged += ItemPropertyChanged;
                          }
                          }
                          if (e.OldItems != null)
                          {
                          foreach (Object item in e.OldItems)
                          {
                          ((INotifyPropertyChanged)item).PropertyChanged -= ItemPropertyChanged;
                          }
                          }
                          }

                          private void ItemPropertyChanged(object sender, PropertyChangedEventArgs e)
                          {
                          NotifyCollectionChangedEventArgs args = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, sender, sender, IndexOf((T)sender));
                          OnCollectionChanged(args);
                          }
                          }





                          share|improve this answer





















                          • 1





                            might be worth short circuiting if e.Action == move?

                            – jk.
                            Jul 29 '11 at 15:56






                          • 4





                            I've had cause to implement something similar myself, however rather than use NotifyCollectionChangedAction.Reset I instead used .Replace: new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, item, item, IndexOf(item)).

                            – Chris
                            Apr 29 '13 at 15:34








                          • 2





                            Awesome solution to my problem - thank you! For those who created their ObservableCollection with a List, you may want to add a constructor that also itterates though all the items and adds PropertyChanged.

                            – Gavin
                            Jun 23 '13 at 8:41








                          • 3





                            There's a potential memory leak here - A Reset event happens when the collection is significantly changed, e.g. on Clear. None of your INPC handlers will be unsubscribed when this happens.

                            – Charles Mager
                            Apr 16 '15 at 6:57






                          • 5





                            this is an OK implementation but it has one major issue - the NotifyCollectionChangedAction.Replace is not a good idea, because then you can't distinguish between an item in fact being replaced or event caused by an item change. It gets much better when you define public event PropertyChangedEventHandler CollectionItemChanged; and then in ItemPropertyChanged do this.CollectionItemChanged?.Invoke(sender, e);

                            – Hristo Yankov
                            Dec 30 '16 at 17:06


















                          169














                          Here is a drop-in class that sub-classes ObservableCollection and actually raises a Reset action when a property on a list item changes. It enforces all items to implement INotifyPropertyChanged.



                          The benefit here is that you can data bind to this class and all of your bindings will update with changes to your item properties.



                          public sealed class TrulyObservableCollection<T> : ObservableCollection<T>
                          where T : INotifyPropertyChanged
                          {
                          public TrulyObservableCollection()
                          {
                          CollectionChanged += FullObservableCollectionCollectionChanged;
                          }

                          public TrulyObservableCollection(IEnumerable<T> pItems) : this()
                          {
                          foreach (var item in pItems)
                          {
                          this.Add(item);
                          }
                          }

                          private void FullObservableCollectionCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
                          {
                          if (e.NewItems != null)
                          {
                          foreach (Object item in e.NewItems)
                          {
                          ((INotifyPropertyChanged)item).PropertyChanged += ItemPropertyChanged;
                          }
                          }
                          if (e.OldItems != null)
                          {
                          foreach (Object item in e.OldItems)
                          {
                          ((INotifyPropertyChanged)item).PropertyChanged -= ItemPropertyChanged;
                          }
                          }
                          }

                          private void ItemPropertyChanged(object sender, PropertyChangedEventArgs e)
                          {
                          NotifyCollectionChangedEventArgs args = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, sender, sender, IndexOf((T)sender));
                          OnCollectionChanged(args);
                          }
                          }





                          share|improve this answer





















                          • 1





                            might be worth short circuiting if e.Action == move?

                            – jk.
                            Jul 29 '11 at 15:56






                          • 4





                            I've had cause to implement something similar myself, however rather than use NotifyCollectionChangedAction.Reset I instead used .Replace: new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, item, item, IndexOf(item)).

                            – Chris
                            Apr 29 '13 at 15:34








                          • 2





                            Awesome solution to my problem - thank you! For those who created their ObservableCollection with a List, you may want to add a constructor that also itterates though all the items and adds PropertyChanged.

                            – Gavin
                            Jun 23 '13 at 8:41








                          • 3





                            There's a potential memory leak here - A Reset event happens when the collection is significantly changed, e.g. on Clear. None of your INPC handlers will be unsubscribed when this happens.

                            – Charles Mager
                            Apr 16 '15 at 6:57






                          • 5





                            this is an OK implementation but it has one major issue - the NotifyCollectionChangedAction.Replace is not a good idea, because then you can't distinguish between an item in fact being replaced or event caused by an item change. It gets much better when you define public event PropertyChangedEventHandler CollectionItemChanged; and then in ItemPropertyChanged do this.CollectionItemChanged?.Invoke(sender, e);

                            – Hristo Yankov
                            Dec 30 '16 at 17:06
















                          169












                          169








                          169







                          Here is a drop-in class that sub-classes ObservableCollection and actually raises a Reset action when a property on a list item changes. It enforces all items to implement INotifyPropertyChanged.



                          The benefit here is that you can data bind to this class and all of your bindings will update with changes to your item properties.



                          public sealed class TrulyObservableCollection<T> : ObservableCollection<T>
                          where T : INotifyPropertyChanged
                          {
                          public TrulyObservableCollection()
                          {
                          CollectionChanged += FullObservableCollectionCollectionChanged;
                          }

                          public TrulyObservableCollection(IEnumerable<T> pItems) : this()
                          {
                          foreach (var item in pItems)
                          {
                          this.Add(item);
                          }
                          }

                          private void FullObservableCollectionCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
                          {
                          if (e.NewItems != null)
                          {
                          foreach (Object item in e.NewItems)
                          {
                          ((INotifyPropertyChanged)item).PropertyChanged += ItemPropertyChanged;
                          }
                          }
                          if (e.OldItems != null)
                          {
                          foreach (Object item in e.OldItems)
                          {
                          ((INotifyPropertyChanged)item).PropertyChanged -= ItemPropertyChanged;
                          }
                          }
                          }

                          private void ItemPropertyChanged(object sender, PropertyChangedEventArgs e)
                          {
                          NotifyCollectionChangedEventArgs args = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, sender, sender, IndexOf((T)sender));
                          OnCollectionChanged(args);
                          }
                          }





                          share|improve this answer















                          Here is a drop-in class that sub-classes ObservableCollection and actually raises a Reset action when a property on a list item changes. It enforces all items to implement INotifyPropertyChanged.



                          The benefit here is that you can data bind to this class and all of your bindings will update with changes to your item properties.



                          public sealed class TrulyObservableCollection<T> : ObservableCollection<T>
                          where T : INotifyPropertyChanged
                          {
                          public TrulyObservableCollection()
                          {
                          CollectionChanged += FullObservableCollectionCollectionChanged;
                          }

                          public TrulyObservableCollection(IEnumerable<T> pItems) : this()
                          {
                          foreach (var item in pItems)
                          {
                          this.Add(item);
                          }
                          }

                          private void FullObservableCollectionCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
                          {
                          if (e.NewItems != null)
                          {
                          foreach (Object item in e.NewItems)
                          {
                          ((INotifyPropertyChanged)item).PropertyChanged += ItemPropertyChanged;
                          }
                          }
                          if (e.OldItems != null)
                          {
                          foreach (Object item in e.OldItems)
                          {
                          ((INotifyPropertyChanged)item).PropertyChanged -= ItemPropertyChanged;
                          }
                          }
                          }

                          private void ItemPropertyChanged(object sender, PropertyChangedEventArgs e)
                          {
                          NotifyCollectionChangedEventArgs args = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, sender, sender, IndexOf((T)sender));
                          OnCollectionChanged(args);
                          }
                          }






                          share|improve this answer














                          share|improve this answer



                          share|improve this answer








                          edited Jul 31 '15 at 4:50









                          Mike de Klerk

                          6,63662857




                          6,63662857










                          answered Mar 10 '11 at 7:47









                          simonsimon

                          2,58021822




                          2,58021822








                          • 1





                            might be worth short circuiting if e.Action == move?

                            – jk.
                            Jul 29 '11 at 15:56






                          • 4





                            I've had cause to implement something similar myself, however rather than use NotifyCollectionChangedAction.Reset I instead used .Replace: new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, item, item, IndexOf(item)).

                            – Chris
                            Apr 29 '13 at 15:34








                          • 2





                            Awesome solution to my problem - thank you! For those who created their ObservableCollection with a List, you may want to add a constructor that also itterates though all the items and adds PropertyChanged.

                            – Gavin
                            Jun 23 '13 at 8:41








                          • 3





                            There's a potential memory leak here - A Reset event happens when the collection is significantly changed, e.g. on Clear. None of your INPC handlers will be unsubscribed when this happens.

                            – Charles Mager
                            Apr 16 '15 at 6:57






                          • 5





                            this is an OK implementation but it has one major issue - the NotifyCollectionChangedAction.Replace is not a good idea, because then you can't distinguish between an item in fact being replaced or event caused by an item change. It gets much better when you define public event PropertyChangedEventHandler CollectionItemChanged; and then in ItemPropertyChanged do this.CollectionItemChanged?.Invoke(sender, e);

                            – Hristo Yankov
                            Dec 30 '16 at 17:06
















                          • 1





                            might be worth short circuiting if e.Action == move?

                            – jk.
                            Jul 29 '11 at 15:56






                          • 4





                            I've had cause to implement something similar myself, however rather than use NotifyCollectionChangedAction.Reset I instead used .Replace: new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, item, item, IndexOf(item)).

                            – Chris
                            Apr 29 '13 at 15:34








                          • 2





                            Awesome solution to my problem - thank you! For those who created their ObservableCollection with a List, you may want to add a constructor that also itterates though all the items and adds PropertyChanged.

                            – Gavin
                            Jun 23 '13 at 8:41








                          • 3





                            There's a potential memory leak here - A Reset event happens when the collection is significantly changed, e.g. on Clear. None of your INPC handlers will be unsubscribed when this happens.

                            – Charles Mager
                            Apr 16 '15 at 6:57






                          • 5





                            this is an OK implementation but it has one major issue - the NotifyCollectionChangedAction.Replace is not a good idea, because then you can't distinguish between an item in fact being replaced or event caused by an item change. It gets much better when you define public event PropertyChangedEventHandler CollectionItemChanged; and then in ItemPropertyChanged do this.CollectionItemChanged?.Invoke(sender, e);

                            – Hristo Yankov
                            Dec 30 '16 at 17:06










                          1




                          1





                          might be worth short circuiting if e.Action == move?

                          – jk.
                          Jul 29 '11 at 15:56





                          might be worth short circuiting if e.Action == move?

                          – jk.
                          Jul 29 '11 at 15:56




                          4




                          4





                          I've had cause to implement something similar myself, however rather than use NotifyCollectionChangedAction.Reset I instead used .Replace: new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, item, item, IndexOf(item)).

                          – Chris
                          Apr 29 '13 at 15:34







                          I've had cause to implement something similar myself, however rather than use NotifyCollectionChangedAction.Reset I instead used .Replace: new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, item, item, IndexOf(item)).

                          – Chris
                          Apr 29 '13 at 15:34






                          2




                          2





                          Awesome solution to my problem - thank you! For those who created their ObservableCollection with a List, you may want to add a constructor that also itterates though all the items and adds PropertyChanged.

                          – Gavin
                          Jun 23 '13 at 8:41







                          Awesome solution to my problem - thank you! For those who created their ObservableCollection with a List, you may want to add a constructor that also itterates though all the items and adds PropertyChanged.

                          – Gavin
                          Jun 23 '13 at 8:41






                          3




                          3





                          There's a potential memory leak here - A Reset event happens when the collection is significantly changed, e.g. on Clear. None of your INPC handlers will be unsubscribed when this happens.

                          – Charles Mager
                          Apr 16 '15 at 6:57





                          There's a potential memory leak here - A Reset event happens when the collection is significantly changed, e.g. on Clear. None of your INPC handlers will be unsubscribed when this happens.

                          – Charles Mager
                          Apr 16 '15 at 6:57




                          5




                          5





                          this is an OK implementation but it has one major issue - the NotifyCollectionChangedAction.Replace is not a good idea, because then you can't distinguish between an item in fact being replaced or event caused by an item change. It gets much better when you define public event PropertyChangedEventHandler CollectionItemChanged; and then in ItemPropertyChanged do this.CollectionItemChanged?.Invoke(sender, e);

                          – Hristo Yankov
                          Dec 30 '16 at 17:06







                          this is an OK implementation but it has one major issue - the NotifyCollectionChangedAction.Replace is not a good idea, because then you can't distinguish between an item in fact being replaced or event caused by an item change. It gets much better when you define public event PropertyChangedEventHandler CollectionItemChanged; and then in ItemPropertyChanged do this.CollectionItemChanged?.Invoke(sender, e);

                          – Hristo Yankov
                          Dec 30 '16 at 17:06













                          18














                          This uses the above ideas but makes it a derived 'more sensitive' collection:



                          using System;
                          using System.Collections.Generic;
                          using System.Linq;
                          using System.Text;
                          using System.ComponentModel;
                          using System.Collections.ObjectModel;
                          using System.Collections.Specialized;
                          using System.Collections;

                          namespace somethingelse
                          {
                          public class ObservableCollectionEx<T> : ObservableCollection<T> where T : INotifyPropertyChanged
                          {
                          // this collection also reacts to changes in its components' properties

                          public ObservableCollectionEx() : base()
                          {
                          this.CollectionChanged +=new System.Collections.Specialized.NotifyCollectionChangedEventHandler(ObservableCollectionEx_CollectionChanged);
                          }

                          void ObservableCollectionEx_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
                          {
                          if (e.Action == NotifyCollectionChangedAction.Remove)
                          {
                          foreach(T item in e.OldItems)
                          {
                          //Removed items
                          item.PropertyChanged -= EntityViewModelPropertyChanged;
                          }
                          }
                          else if (e.Action == NotifyCollectionChangedAction.Add)
                          {
                          foreach(T item in e.NewItems)
                          {
                          //Added items
                          item.PropertyChanged += EntityViewModelPropertyChanged;
                          }
                          }
                          }

                          public void EntityViewModelPropertyChanged(object sender, PropertyChangedEventArgs e)
                          {
                          //This will get called when the property of an object inside the collection changes - note you must make it a 'reset' - dunno why
                          NotifyCollectionChangedEventArgs args = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset);
                          OnCollectionChanged(args);
                          }
                          }
                          }





                          share|improve this answer






























                            18














                            This uses the above ideas but makes it a derived 'more sensitive' collection:



                            using System;
                            using System.Collections.Generic;
                            using System.Linq;
                            using System.Text;
                            using System.ComponentModel;
                            using System.Collections.ObjectModel;
                            using System.Collections.Specialized;
                            using System.Collections;

                            namespace somethingelse
                            {
                            public class ObservableCollectionEx<T> : ObservableCollection<T> where T : INotifyPropertyChanged
                            {
                            // this collection also reacts to changes in its components' properties

                            public ObservableCollectionEx() : base()
                            {
                            this.CollectionChanged +=new System.Collections.Specialized.NotifyCollectionChangedEventHandler(ObservableCollectionEx_CollectionChanged);
                            }

                            void ObservableCollectionEx_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
                            {
                            if (e.Action == NotifyCollectionChangedAction.Remove)
                            {
                            foreach(T item in e.OldItems)
                            {
                            //Removed items
                            item.PropertyChanged -= EntityViewModelPropertyChanged;
                            }
                            }
                            else if (e.Action == NotifyCollectionChangedAction.Add)
                            {
                            foreach(T item in e.NewItems)
                            {
                            //Added items
                            item.PropertyChanged += EntityViewModelPropertyChanged;
                            }
                            }
                            }

                            public void EntityViewModelPropertyChanged(object sender, PropertyChangedEventArgs e)
                            {
                            //This will get called when the property of an object inside the collection changes - note you must make it a 'reset' - dunno why
                            NotifyCollectionChangedEventArgs args = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset);
                            OnCollectionChanged(args);
                            }
                            }
                            }





                            share|improve this answer




























                              18












                              18








                              18







                              This uses the above ideas but makes it a derived 'more sensitive' collection:



                              using System;
                              using System.Collections.Generic;
                              using System.Linq;
                              using System.Text;
                              using System.ComponentModel;
                              using System.Collections.ObjectModel;
                              using System.Collections.Specialized;
                              using System.Collections;

                              namespace somethingelse
                              {
                              public class ObservableCollectionEx<T> : ObservableCollection<T> where T : INotifyPropertyChanged
                              {
                              // this collection also reacts to changes in its components' properties

                              public ObservableCollectionEx() : base()
                              {
                              this.CollectionChanged +=new System.Collections.Specialized.NotifyCollectionChangedEventHandler(ObservableCollectionEx_CollectionChanged);
                              }

                              void ObservableCollectionEx_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
                              {
                              if (e.Action == NotifyCollectionChangedAction.Remove)
                              {
                              foreach(T item in e.OldItems)
                              {
                              //Removed items
                              item.PropertyChanged -= EntityViewModelPropertyChanged;
                              }
                              }
                              else if (e.Action == NotifyCollectionChangedAction.Add)
                              {
                              foreach(T item in e.NewItems)
                              {
                              //Added items
                              item.PropertyChanged += EntityViewModelPropertyChanged;
                              }
                              }
                              }

                              public void EntityViewModelPropertyChanged(object sender, PropertyChangedEventArgs e)
                              {
                              //This will get called when the property of an object inside the collection changes - note you must make it a 'reset' - dunno why
                              NotifyCollectionChangedEventArgs args = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset);
                              OnCollectionChanged(args);
                              }
                              }
                              }





                              share|improve this answer















                              This uses the above ideas but makes it a derived 'more sensitive' collection:



                              using System;
                              using System.Collections.Generic;
                              using System.Linq;
                              using System.Text;
                              using System.ComponentModel;
                              using System.Collections.ObjectModel;
                              using System.Collections.Specialized;
                              using System.Collections;

                              namespace somethingelse
                              {
                              public class ObservableCollectionEx<T> : ObservableCollection<T> where T : INotifyPropertyChanged
                              {
                              // this collection also reacts to changes in its components' properties

                              public ObservableCollectionEx() : base()
                              {
                              this.CollectionChanged +=new System.Collections.Specialized.NotifyCollectionChangedEventHandler(ObservableCollectionEx_CollectionChanged);
                              }

                              void ObservableCollectionEx_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
                              {
                              if (e.Action == NotifyCollectionChangedAction.Remove)
                              {
                              foreach(T item in e.OldItems)
                              {
                              //Removed items
                              item.PropertyChanged -= EntityViewModelPropertyChanged;
                              }
                              }
                              else if (e.Action == NotifyCollectionChangedAction.Add)
                              {
                              foreach(T item in e.NewItems)
                              {
                              //Added items
                              item.PropertyChanged += EntityViewModelPropertyChanged;
                              }
                              }
                              }

                              public void EntityViewModelPropertyChanged(object sender, PropertyChangedEventArgs e)
                              {
                              //This will get called when the property of an object inside the collection changes - note you must make it a 'reset' - dunno why
                              NotifyCollectionChangedEventArgs args = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset);
                              OnCollectionChanged(args);
                              }
                              }
                              }






                              share|improve this answer














                              share|improve this answer



                              share|improve this answer








                              edited Jan 28 '15 at 20:09









                              Nick Miller

                              1,94712045




                              1,94712045










                              answered Nov 24 '10 at 7:03









                              Jack KenyonJack Kenyon

                              18112




                              18112























                                  15














                                  I've put together what I hope is a pretty robust solution, including some of the techniques in other answers. It is a new class derived from ObservableCollection<>, which I'm calling FullyObservableCollection<>



                                  It has the following features:




                                  • It adds a new event, ItemPropertyChanged. I've deliberately kept this separate from the existing CollectionChanged:


                                    • To aid backward compatibility.

                                    • So more relevant detail can be given in the new ItemPropertyChangedEventArgs that accompanies it: the original PropertyChangedEventArgs and the index within the collection.



                                  • It replicates all the constructors from ObservableCollection<>.

                                  • It correctly handles the list being reset (ObservableCollection<>.Clear()), avoiding a possible memory leak.

                                  • It overrides the base class's OnCollectionChanged(), rather than a more resource-intensive subscription to the CollectionChanged event.


                                  Code



                                  The complete .cs file follows. Note that a few features of C# 6 have been used, but it should be fairly simple to backport it:



                                  using System;
                                  using System.Collections.Generic;
                                  using System.Collections.ObjectModel;
                                  using System.Collections.Specialized;
                                  using System.ComponentModel;

                                  namespace Utilities
                                  {
                                  public class FullyObservableCollection<T> : ObservableCollection<T>
                                  where T : INotifyPropertyChanged
                                  {
                                  /// <summary>
                                  /// Occurs when a property is changed within an item.
                                  /// </summary>
                                  public event EventHandler<ItemPropertyChangedEventArgs> ItemPropertyChanged;

                                  public FullyObservableCollection() : base()
                                  { }

                                  public FullyObservableCollection(List<T> list) : base(list)
                                  {
                                  ObserveAll();
                                  }

                                  public FullyObservableCollection(IEnumerable<T> enumerable) : base(enumerable)
                                  {
                                  ObserveAll();
                                  }

                                  protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
                                  {
                                  if (e.Action == NotifyCollectionChangedAction.Remove ||
                                  e.Action == NotifyCollectionChangedAction.Replace)
                                  {
                                  foreach (T item in e.OldItems)
                                  item.PropertyChanged -= ChildPropertyChanged;
                                  }

                                  if (e.Action == NotifyCollectionChangedAction.Add ||
                                  e.Action == NotifyCollectionChangedAction.Replace)
                                  {
                                  foreach (T item in e.NewItems)
                                  item.PropertyChanged += ChildPropertyChanged;
                                  }

                                  base.OnCollectionChanged(e);
                                  }

                                  protected void OnItemPropertyChanged(ItemPropertyChangedEventArgs e)
                                  {
                                  ItemPropertyChanged?.Invoke(this, e);
                                  }

                                  protected void OnItemPropertyChanged(int index, PropertyChangedEventArgs e)
                                  {
                                  OnItemPropertyChanged(new ItemPropertyChangedEventArgs(index, e));
                                  }

                                  protected override void ClearItems()
                                  {
                                  foreach (T item in Items)
                                  item.PropertyChanged -= ChildPropertyChanged;

                                  base.ClearItems();
                                  }

                                  private void ObserveAll()
                                  {
                                  foreach (T item in Items)
                                  item.PropertyChanged += ChildPropertyChanged;
                                  }

                                  private void ChildPropertyChanged(object sender, PropertyChangedEventArgs e)
                                  {
                                  T typedSender = (T)sender;
                                  int i = Items.IndexOf(typedSender);

                                  if (i < 0)
                                  throw new ArgumentException("Received property notification from item not in collection");

                                  OnItemPropertyChanged(i, e);
                                  }
                                  }

                                  /// <summary>
                                  /// Provides data for the <see cref="FullyObservableCollection{T}.ItemPropertyChanged"/> event.
                                  /// </summary>
                                  public class ItemPropertyChangedEventArgs : PropertyChangedEventArgs
                                  {
                                  /// <summary>
                                  /// Gets the index in the collection for which the property change has occurred.
                                  /// </summary>
                                  /// <value>
                                  /// Index in parent collection.
                                  /// </value>
                                  public int CollectionIndex { get; }

                                  /// <summary>
                                  /// Initializes a new instance of the <see cref="ItemPropertyChangedEventArgs"/> class.
                                  /// </summary>
                                  /// <param name="index">The index in the collection of changed item.</param>
                                  /// <param name="name">The name of the property that changed.</param>
                                  public ItemPropertyChangedEventArgs(int index, string name) : base(name)
                                  {
                                  CollectionIndex = index;
                                  }

                                  /// <summary>
                                  /// Initializes a new instance of the <see cref="ItemPropertyChangedEventArgs"/> class.
                                  /// </summary>
                                  /// <param name="index">The index.</param>
                                  /// <param name="args">The <see cref="PropertyChangedEventArgs"/> instance containing the event data.</param>
                                  public ItemPropertyChangedEventArgs(int index, PropertyChangedEventArgs args) : this(index, args.PropertyName)
                                  { }
                                  }
                                  }


                                  NUnit Tests



                                  So you can check changes you might make (and see what I tested in the first place!), I've also included my NUnit test class. Obviously, the following code is not necessary just to use FullyObservableCollection<T> in your project.



                                  NB The test class uses BindableBase from PRISM to implement INotifyPropertyChanged. There is no dependency on PRISM from the main code.



                                  using NUnit.Framework;
                                  using Utilities;
                                  using Microsoft.Practices.Prism.Mvvm;
                                  using System.Collections.Specialized;
                                  using System.Collections.Generic;

                                  namespace Test_Utilities
                                  {
                                  [TestFixture]
                                  public class Test_FullyObservableCollection : AssertionHelper
                                  {
                                  public class NotifyingTestClass : BindableBase
                                  {
                                  public int Id
                                  {
                                  get { return _Id; }
                                  set { SetProperty(ref _Id, value); }
                                  }
                                  private int _Id;

                                  public string Name
                                  {
                                  get { return _Name; }
                                  set { SetProperty(ref _Name, value); }
                                  }
                                  private string _Name;

                                  }

                                  FullyObservableCollection<NotifyingTestClass> TestCollection;
                                  NotifyingTestClass Fred;
                                  NotifyingTestClass Betty;
                                  List<NotifyCollectionChangedEventArgs> CollectionEventList;
                                  List<ItemPropertyChangedEventArgs> ItemEventList;

                                  [SetUp]
                                  public void Init()
                                  {
                                  Fred = new NotifyingTestClass() { Id = 1, Name = "Fred" };
                                  Betty = new NotifyingTestClass() { Id = 4, Name = "Betty" };

                                  TestCollection = new FullyObservableCollection<NotifyingTestClass>()
                                  {
                                  Fred,
                                  new NotifyingTestClass() {Id = 2, Name = "Barney" },
                                  new NotifyingTestClass() {Id = 3, Name = "Wilma" }
                                  };

                                  CollectionEventList = new List<NotifyCollectionChangedEventArgs>();
                                  ItemEventList = new List<ItemPropertyChangedEventArgs>();
                                  TestCollection.CollectionChanged += (o, e) => CollectionEventList.Add(e);
                                  TestCollection.ItemPropertyChanged += (o, e) => ItemEventList.Add(e);
                                  }

                                  // Change existing member property: just ItemPropertyChanged(IPC) should fire
                                  [Test]
                                  public void DetectMemberPropertyChange()
                                  {
                                  TestCollection[0].Id = 7;

                                  Expect(CollectionEventList.Count, Is.EqualTo(0));

                                  Expect(ItemEventList.Count, Is.EqualTo(1), "IPC count");
                                  Expect(ItemEventList[0].PropertyName, Is.EqualTo(nameof(Fred.Id)), "Field Name");
                                  Expect(ItemEventList[0].CollectionIndex, Is.EqualTo(0), "Collection Index");
                                  }


                                  // Add new member, change property: CollectionPropertyChanged (CPC) and IPC should fire
                                  [Test]
                                  public void DetectNewMemberPropertyChange()
                                  {
                                  TestCollection.Add(Betty);

                                  Expect(TestCollection.Count, Is.EqualTo(4));
                                  Expect(TestCollection[3].Name, Is.EqualTo("Betty"));

                                  Expect(ItemEventList.Count, Is.EqualTo(0), "Item Event count");

                                  Expect(CollectionEventList.Count, Is.EqualTo(1), "Collection Event count");
                                  Expect(CollectionEventList[0].Action, Is.EqualTo(NotifyCollectionChangedAction.Add), "Action (add)");
                                  Expect(CollectionEventList[0].OldItems, Is.Null, "OldItems count");
                                  Expect(CollectionEventList[0].NewItems.Count, Is.EqualTo(1), "NewItems count");
                                  Expect(CollectionEventList[0].NewItems[0], Is.EqualTo(Betty), "NewItems[0] dereference");

                                  CollectionEventList.Clear(); // Empty for next operation
                                  ItemEventList.Clear();

                                  TestCollection[3].Id = 7;
                                  Expect(CollectionEventList.Count, Is.EqualTo(0), "Collection Event count");

                                  Expect(ItemEventList.Count, Is.EqualTo(1), "Item Event count");
                                  Expect(TestCollection[ItemEventList[0].CollectionIndex], Is.EqualTo(Betty), "Collection Index dereference");
                                  }


                                  // Remove member, change property: CPC should fire for removel, neither CPC nor IPC should fire for change
                                  [Test]
                                  public void CeaseListentingWhenMemberRemoved()
                                  {
                                  TestCollection.Remove(Fred);

                                  Expect(TestCollection.Count, Is.EqualTo(2));
                                  Expect(TestCollection.IndexOf(Fred), Is.Negative);

                                  Expect(ItemEventList.Count, Is.EqualTo(0), "Item Event count (pre change)");

                                  Expect(CollectionEventList.Count, Is.EqualTo(1), "Collection Event count (pre change)");
                                  Expect(CollectionEventList[0].Action, Is.EqualTo(NotifyCollectionChangedAction.Remove), "Action (remove)");
                                  Expect(CollectionEventList[0].OldItems.Count, Is.EqualTo(1), "OldItems count");
                                  Expect(CollectionEventList[0].NewItems, Is.Null, "NewItems count");
                                  Expect(CollectionEventList[0].OldItems[0], Is.EqualTo(Fred), "OldItems[0] dereference");

                                  CollectionEventList.Clear(); // Empty for next operation
                                  ItemEventList.Clear();

                                  Fred.Id = 7;
                                  Expect(CollectionEventList.Count, Is.EqualTo(0), "Collection Event count (post change)");
                                  Expect(ItemEventList.Count, Is.EqualTo(0), "Item Event count (post change)");
                                  }


                                  // Move member in list, change property: CPC should fire for move, IPC should fire for change
                                  [Test]
                                  public void MoveMember()
                                  {
                                  TestCollection.Move(0, 1);

                                  Expect(TestCollection.Count, Is.EqualTo(3));
                                  Expect(TestCollection.IndexOf(Fred), Is.GreaterThan(0));

                                  Expect(ItemEventList.Count, Is.EqualTo(0), "Item Event count (pre change)");

                                  Expect(CollectionEventList.Count, Is.EqualTo(1), "Collection Event count (pre change)");
                                  Expect(CollectionEventList[0].Action, Is.EqualTo(NotifyCollectionChangedAction.Move), "Action (move)");
                                  Expect(CollectionEventList[0].OldItems.Count, Is.EqualTo(1), "OldItems count");
                                  Expect(CollectionEventList[0].NewItems.Count, Is.EqualTo(1), "NewItems count");
                                  Expect(CollectionEventList[0].OldItems[0], Is.EqualTo(Fred), "OldItems[0] dereference");
                                  Expect(CollectionEventList[0].NewItems[0], Is.EqualTo(Fred), "NewItems[0] dereference");

                                  CollectionEventList.Clear(); // Empty for next operation
                                  ItemEventList.Clear();

                                  Fred.Id = 7;
                                  Expect(CollectionEventList.Count, Is.EqualTo(0), "Collection Event count (post change)");

                                  Expect(ItemEventList.Count, Is.EqualTo(1), "Item Event count (post change)");
                                  Expect(TestCollection[ItemEventList[0].CollectionIndex], Is.EqualTo(Fred), "Collection Index dereference");
                                  }


                                  // Clear list, chnage property: only CPC should fire for clear and neither for property change
                                  [Test]
                                  public void ClearList()
                                  {
                                  TestCollection.Clear();

                                  Expect(TestCollection.Count, Is.EqualTo(0));

                                  Expect(ItemEventList.Count, Is.EqualTo(0), "Item Event count (pre change)");

                                  Expect(CollectionEventList.Count, Is.EqualTo(1), "Collection Event count (pre change)");
                                  Expect(CollectionEventList[0].Action, Is.EqualTo(NotifyCollectionChangedAction.Reset), "Action (reset)");
                                  Expect(CollectionEventList[0].OldItems, Is.Null, "OldItems count");
                                  Expect(CollectionEventList[0].NewItems, Is.Null, "NewItems count");

                                  CollectionEventList.Clear(); // Empty for next operation
                                  ItemEventList.Clear();

                                  Fred.Id = 7;
                                  Expect(CollectionEventList.Count, Is.EqualTo(0), "Collection Event count (post change)");
                                  Expect(ItemEventList.Count, Is.EqualTo(0), "Item Event count (post change)");
                                  }
                                  }
                                  }





                                  share|improve this answer


























                                  • I don't know what I am doing wrong, but this doesn't work for me. I'm binding my ListView to your collection but when I update the properties of the items inside, the ListView doesn't update, even tho' I can see all the events firing up. I'm also using the PRISM library...

                                    – Renato Parreira
                                    Feb 24 '17 at 15:20











                                  • @Renato, have you done anything with the new event? ListView will respond to CollectionChanged events because it knows about them. ItemPropertyChanged is a non-standard addition, so you need to teach it about that. As a quick and dirty fix, you could try just firing the CollectionChanged event as well as (or even instead of) ItemPropertyChanged in OnItemPropertyChanged(). I kept them separate for reasons stated in the answer, but for your use-case it might just do what you need.

                                    – Bob Sammers
                                    Mar 2 '17 at 18:13


















                                  15














                                  I've put together what I hope is a pretty robust solution, including some of the techniques in other answers. It is a new class derived from ObservableCollection<>, which I'm calling FullyObservableCollection<>



                                  It has the following features:




                                  • It adds a new event, ItemPropertyChanged. I've deliberately kept this separate from the existing CollectionChanged:


                                    • To aid backward compatibility.

                                    • So more relevant detail can be given in the new ItemPropertyChangedEventArgs that accompanies it: the original PropertyChangedEventArgs and the index within the collection.



                                  • It replicates all the constructors from ObservableCollection<>.

                                  • It correctly handles the list being reset (ObservableCollection<>.Clear()), avoiding a possible memory leak.

                                  • It overrides the base class's OnCollectionChanged(), rather than a more resource-intensive subscription to the CollectionChanged event.


                                  Code



                                  The complete .cs file follows. Note that a few features of C# 6 have been used, but it should be fairly simple to backport it:



                                  using System;
                                  using System.Collections.Generic;
                                  using System.Collections.ObjectModel;
                                  using System.Collections.Specialized;
                                  using System.ComponentModel;

                                  namespace Utilities
                                  {
                                  public class FullyObservableCollection<T> : ObservableCollection<T>
                                  where T : INotifyPropertyChanged
                                  {
                                  /// <summary>
                                  /// Occurs when a property is changed within an item.
                                  /// </summary>
                                  public event EventHandler<ItemPropertyChangedEventArgs> ItemPropertyChanged;

                                  public FullyObservableCollection() : base()
                                  { }

                                  public FullyObservableCollection(List<T> list) : base(list)
                                  {
                                  ObserveAll();
                                  }

                                  public FullyObservableCollection(IEnumerable<T> enumerable) : base(enumerable)
                                  {
                                  ObserveAll();
                                  }

                                  protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
                                  {
                                  if (e.Action == NotifyCollectionChangedAction.Remove ||
                                  e.Action == NotifyCollectionChangedAction.Replace)
                                  {
                                  foreach (T item in e.OldItems)
                                  item.PropertyChanged -= ChildPropertyChanged;
                                  }

                                  if (e.Action == NotifyCollectionChangedAction.Add ||
                                  e.Action == NotifyCollectionChangedAction.Replace)
                                  {
                                  foreach (T item in e.NewItems)
                                  item.PropertyChanged += ChildPropertyChanged;
                                  }

                                  base.OnCollectionChanged(e);
                                  }

                                  protected void OnItemPropertyChanged(ItemPropertyChangedEventArgs e)
                                  {
                                  ItemPropertyChanged?.Invoke(this, e);
                                  }

                                  protected void OnItemPropertyChanged(int index, PropertyChangedEventArgs e)
                                  {
                                  OnItemPropertyChanged(new ItemPropertyChangedEventArgs(index, e));
                                  }

                                  protected override void ClearItems()
                                  {
                                  foreach (T item in Items)
                                  item.PropertyChanged -= ChildPropertyChanged;

                                  base.ClearItems();
                                  }

                                  private void ObserveAll()
                                  {
                                  foreach (T item in Items)
                                  item.PropertyChanged += ChildPropertyChanged;
                                  }

                                  private void ChildPropertyChanged(object sender, PropertyChangedEventArgs e)
                                  {
                                  T typedSender = (T)sender;
                                  int i = Items.IndexOf(typedSender);

                                  if (i < 0)
                                  throw new ArgumentException("Received property notification from item not in collection");

                                  OnItemPropertyChanged(i, e);
                                  }
                                  }

                                  /// <summary>
                                  /// Provides data for the <see cref="FullyObservableCollection{T}.ItemPropertyChanged"/> event.
                                  /// </summary>
                                  public class ItemPropertyChangedEventArgs : PropertyChangedEventArgs
                                  {
                                  /// <summary>
                                  /// Gets the index in the collection for which the property change has occurred.
                                  /// </summary>
                                  /// <value>
                                  /// Index in parent collection.
                                  /// </value>
                                  public int CollectionIndex { get; }

                                  /// <summary>
                                  /// Initializes a new instance of the <see cref="ItemPropertyChangedEventArgs"/> class.
                                  /// </summary>
                                  /// <param name="index">The index in the collection of changed item.</param>
                                  /// <param name="name">The name of the property that changed.</param>
                                  public ItemPropertyChangedEventArgs(int index, string name) : base(name)
                                  {
                                  CollectionIndex = index;
                                  }

                                  /// <summary>
                                  /// Initializes a new instance of the <see cref="ItemPropertyChangedEventArgs"/> class.
                                  /// </summary>
                                  /// <param name="index">The index.</param>
                                  /// <param name="args">The <see cref="PropertyChangedEventArgs"/> instance containing the event data.</param>
                                  public ItemPropertyChangedEventArgs(int index, PropertyChangedEventArgs args) : this(index, args.PropertyName)
                                  { }
                                  }
                                  }


                                  NUnit Tests



                                  So you can check changes you might make (and see what I tested in the first place!), I've also included my NUnit test class. Obviously, the following code is not necessary just to use FullyObservableCollection<T> in your project.



                                  NB The test class uses BindableBase from PRISM to implement INotifyPropertyChanged. There is no dependency on PRISM from the main code.



                                  using NUnit.Framework;
                                  using Utilities;
                                  using Microsoft.Practices.Prism.Mvvm;
                                  using System.Collections.Specialized;
                                  using System.Collections.Generic;

                                  namespace Test_Utilities
                                  {
                                  [TestFixture]
                                  public class Test_FullyObservableCollection : AssertionHelper
                                  {
                                  public class NotifyingTestClass : BindableBase
                                  {
                                  public int Id
                                  {
                                  get { return _Id; }
                                  set { SetProperty(ref _Id, value); }
                                  }
                                  private int _Id;

                                  public string Name
                                  {
                                  get { return _Name; }
                                  set { SetProperty(ref _Name, value); }
                                  }
                                  private string _Name;

                                  }

                                  FullyObservableCollection<NotifyingTestClass> TestCollection;
                                  NotifyingTestClass Fred;
                                  NotifyingTestClass Betty;
                                  List<NotifyCollectionChangedEventArgs> CollectionEventList;
                                  List<ItemPropertyChangedEventArgs> ItemEventList;

                                  [SetUp]
                                  public void Init()
                                  {
                                  Fred = new NotifyingTestClass() { Id = 1, Name = "Fred" };
                                  Betty = new NotifyingTestClass() { Id = 4, Name = "Betty" };

                                  TestCollection = new FullyObservableCollection<NotifyingTestClass>()
                                  {
                                  Fred,
                                  new NotifyingTestClass() {Id = 2, Name = "Barney" },
                                  new NotifyingTestClass() {Id = 3, Name = "Wilma" }
                                  };

                                  CollectionEventList = new List<NotifyCollectionChangedEventArgs>();
                                  ItemEventList = new List<ItemPropertyChangedEventArgs>();
                                  TestCollection.CollectionChanged += (o, e) => CollectionEventList.Add(e);
                                  TestCollection.ItemPropertyChanged += (o, e) => ItemEventList.Add(e);
                                  }

                                  // Change existing member property: just ItemPropertyChanged(IPC) should fire
                                  [Test]
                                  public void DetectMemberPropertyChange()
                                  {
                                  TestCollection[0].Id = 7;

                                  Expect(CollectionEventList.Count, Is.EqualTo(0));

                                  Expect(ItemEventList.Count, Is.EqualTo(1), "IPC count");
                                  Expect(ItemEventList[0].PropertyName, Is.EqualTo(nameof(Fred.Id)), "Field Name");
                                  Expect(ItemEventList[0].CollectionIndex, Is.EqualTo(0), "Collection Index");
                                  }


                                  // Add new member, change property: CollectionPropertyChanged (CPC) and IPC should fire
                                  [Test]
                                  public void DetectNewMemberPropertyChange()
                                  {
                                  TestCollection.Add(Betty);

                                  Expect(TestCollection.Count, Is.EqualTo(4));
                                  Expect(TestCollection[3].Name, Is.EqualTo("Betty"));

                                  Expect(ItemEventList.Count, Is.EqualTo(0), "Item Event count");

                                  Expect(CollectionEventList.Count, Is.EqualTo(1), "Collection Event count");
                                  Expect(CollectionEventList[0].Action, Is.EqualTo(NotifyCollectionChangedAction.Add), "Action (add)");
                                  Expect(CollectionEventList[0].OldItems, Is.Null, "OldItems count");
                                  Expect(CollectionEventList[0].NewItems.Count, Is.EqualTo(1), "NewItems count");
                                  Expect(CollectionEventList[0].NewItems[0], Is.EqualTo(Betty), "NewItems[0] dereference");

                                  CollectionEventList.Clear(); // Empty for next operation
                                  ItemEventList.Clear();

                                  TestCollection[3].Id = 7;
                                  Expect(CollectionEventList.Count, Is.EqualTo(0), "Collection Event count");

                                  Expect(ItemEventList.Count, Is.EqualTo(1), "Item Event count");
                                  Expect(TestCollection[ItemEventList[0].CollectionIndex], Is.EqualTo(Betty), "Collection Index dereference");
                                  }


                                  // Remove member, change property: CPC should fire for removel, neither CPC nor IPC should fire for change
                                  [Test]
                                  public void CeaseListentingWhenMemberRemoved()
                                  {
                                  TestCollection.Remove(Fred);

                                  Expect(TestCollection.Count, Is.EqualTo(2));
                                  Expect(TestCollection.IndexOf(Fred), Is.Negative);

                                  Expect(ItemEventList.Count, Is.EqualTo(0), "Item Event count (pre change)");

                                  Expect(CollectionEventList.Count, Is.EqualTo(1), "Collection Event count (pre change)");
                                  Expect(CollectionEventList[0].Action, Is.EqualTo(NotifyCollectionChangedAction.Remove), "Action (remove)");
                                  Expect(CollectionEventList[0].OldItems.Count, Is.EqualTo(1), "OldItems count");
                                  Expect(CollectionEventList[0].NewItems, Is.Null, "NewItems count");
                                  Expect(CollectionEventList[0].OldItems[0], Is.EqualTo(Fred), "OldItems[0] dereference");

                                  CollectionEventList.Clear(); // Empty for next operation
                                  ItemEventList.Clear();

                                  Fred.Id = 7;
                                  Expect(CollectionEventList.Count, Is.EqualTo(0), "Collection Event count (post change)");
                                  Expect(ItemEventList.Count, Is.EqualTo(0), "Item Event count (post change)");
                                  }


                                  // Move member in list, change property: CPC should fire for move, IPC should fire for change
                                  [Test]
                                  public void MoveMember()
                                  {
                                  TestCollection.Move(0, 1);

                                  Expect(TestCollection.Count, Is.EqualTo(3));
                                  Expect(TestCollection.IndexOf(Fred), Is.GreaterThan(0));

                                  Expect(ItemEventList.Count, Is.EqualTo(0), "Item Event count (pre change)");

                                  Expect(CollectionEventList.Count, Is.EqualTo(1), "Collection Event count (pre change)");
                                  Expect(CollectionEventList[0].Action, Is.EqualTo(NotifyCollectionChangedAction.Move), "Action (move)");
                                  Expect(CollectionEventList[0].OldItems.Count, Is.EqualTo(1), "OldItems count");
                                  Expect(CollectionEventList[0].NewItems.Count, Is.EqualTo(1), "NewItems count");
                                  Expect(CollectionEventList[0].OldItems[0], Is.EqualTo(Fred), "OldItems[0] dereference");
                                  Expect(CollectionEventList[0].NewItems[0], Is.EqualTo(Fred), "NewItems[0] dereference");

                                  CollectionEventList.Clear(); // Empty for next operation
                                  ItemEventList.Clear();

                                  Fred.Id = 7;
                                  Expect(CollectionEventList.Count, Is.EqualTo(0), "Collection Event count (post change)");

                                  Expect(ItemEventList.Count, Is.EqualTo(1), "Item Event count (post change)");
                                  Expect(TestCollection[ItemEventList[0].CollectionIndex], Is.EqualTo(Fred), "Collection Index dereference");
                                  }


                                  // Clear list, chnage property: only CPC should fire for clear and neither for property change
                                  [Test]
                                  public void ClearList()
                                  {
                                  TestCollection.Clear();

                                  Expect(TestCollection.Count, Is.EqualTo(0));

                                  Expect(ItemEventList.Count, Is.EqualTo(0), "Item Event count (pre change)");

                                  Expect(CollectionEventList.Count, Is.EqualTo(1), "Collection Event count (pre change)");
                                  Expect(CollectionEventList[0].Action, Is.EqualTo(NotifyCollectionChangedAction.Reset), "Action (reset)");
                                  Expect(CollectionEventList[0].OldItems, Is.Null, "OldItems count");
                                  Expect(CollectionEventList[0].NewItems, Is.Null, "NewItems count");

                                  CollectionEventList.Clear(); // Empty for next operation
                                  ItemEventList.Clear();

                                  Fred.Id = 7;
                                  Expect(CollectionEventList.Count, Is.EqualTo(0), "Collection Event count (post change)");
                                  Expect(ItemEventList.Count, Is.EqualTo(0), "Item Event count (post change)");
                                  }
                                  }
                                  }





                                  share|improve this answer


























                                  • I don't know what I am doing wrong, but this doesn't work for me. I'm binding my ListView to your collection but when I update the properties of the items inside, the ListView doesn't update, even tho' I can see all the events firing up. I'm also using the PRISM library...

                                    – Renato Parreira
                                    Feb 24 '17 at 15:20











                                  • @Renato, have you done anything with the new event? ListView will respond to CollectionChanged events because it knows about them. ItemPropertyChanged is a non-standard addition, so you need to teach it about that. As a quick and dirty fix, you could try just firing the CollectionChanged event as well as (or even instead of) ItemPropertyChanged in OnItemPropertyChanged(). I kept them separate for reasons stated in the answer, but for your use-case it might just do what you need.

                                    – Bob Sammers
                                    Mar 2 '17 at 18:13
















                                  15












                                  15








                                  15







                                  I've put together what I hope is a pretty robust solution, including some of the techniques in other answers. It is a new class derived from ObservableCollection<>, which I'm calling FullyObservableCollection<>



                                  It has the following features:




                                  • It adds a new event, ItemPropertyChanged. I've deliberately kept this separate from the existing CollectionChanged:


                                    • To aid backward compatibility.

                                    • So more relevant detail can be given in the new ItemPropertyChangedEventArgs that accompanies it: the original PropertyChangedEventArgs and the index within the collection.



                                  • It replicates all the constructors from ObservableCollection<>.

                                  • It correctly handles the list being reset (ObservableCollection<>.Clear()), avoiding a possible memory leak.

                                  • It overrides the base class's OnCollectionChanged(), rather than a more resource-intensive subscription to the CollectionChanged event.


                                  Code



                                  The complete .cs file follows. Note that a few features of C# 6 have been used, but it should be fairly simple to backport it:



                                  using System;
                                  using System.Collections.Generic;
                                  using System.Collections.ObjectModel;
                                  using System.Collections.Specialized;
                                  using System.ComponentModel;

                                  namespace Utilities
                                  {
                                  public class FullyObservableCollection<T> : ObservableCollection<T>
                                  where T : INotifyPropertyChanged
                                  {
                                  /// <summary>
                                  /// Occurs when a property is changed within an item.
                                  /// </summary>
                                  public event EventHandler<ItemPropertyChangedEventArgs> ItemPropertyChanged;

                                  public FullyObservableCollection() : base()
                                  { }

                                  public FullyObservableCollection(List<T> list) : base(list)
                                  {
                                  ObserveAll();
                                  }

                                  public FullyObservableCollection(IEnumerable<T> enumerable) : base(enumerable)
                                  {
                                  ObserveAll();
                                  }

                                  protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
                                  {
                                  if (e.Action == NotifyCollectionChangedAction.Remove ||
                                  e.Action == NotifyCollectionChangedAction.Replace)
                                  {
                                  foreach (T item in e.OldItems)
                                  item.PropertyChanged -= ChildPropertyChanged;
                                  }

                                  if (e.Action == NotifyCollectionChangedAction.Add ||
                                  e.Action == NotifyCollectionChangedAction.Replace)
                                  {
                                  foreach (T item in e.NewItems)
                                  item.PropertyChanged += ChildPropertyChanged;
                                  }

                                  base.OnCollectionChanged(e);
                                  }

                                  protected void OnItemPropertyChanged(ItemPropertyChangedEventArgs e)
                                  {
                                  ItemPropertyChanged?.Invoke(this, e);
                                  }

                                  protected void OnItemPropertyChanged(int index, PropertyChangedEventArgs e)
                                  {
                                  OnItemPropertyChanged(new ItemPropertyChangedEventArgs(index, e));
                                  }

                                  protected override void ClearItems()
                                  {
                                  foreach (T item in Items)
                                  item.PropertyChanged -= ChildPropertyChanged;

                                  base.ClearItems();
                                  }

                                  private void ObserveAll()
                                  {
                                  foreach (T item in Items)
                                  item.PropertyChanged += ChildPropertyChanged;
                                  }

                                  private void ChildPropertyChanged(object sender, PropertyChangedEventArgs e)
                                  {
                                  T typedSender = (T)sender;
                                  int i = Items.IndexOf(typedSender);

                                  if (i < 0)
                                  throw new ArgumentException("Received property notification from item not in collection");

                                  OnItemPropertyChanged(i, e);
                                  }
                                  }

                                  /// <summary>
                                  /// Provides data for the <see cref="FullyObservableCollection{T}.ItemPropertyChanged"/> event.
                                  /// </summary>
                                  public class ItemPropertyChangedEventArgs : PropertyChangedEventArgs
                                  {
                                  /// <summary>
                                  /// Gets the index in the collection for which the property change has occurred.
                                  /// </summary>
                                  /// <value>
                                  /// Index in parent collection.
                                  /// </value>
                                  public int CollectionIndex { get; }

                                  /// <summary>
                                  /// Initializes a new instance of the <see cref="ItemPropertyChangedEventArgs"/> class.
                                  /// </summary>
                                  /// <param name="index">The index in the collection of changed item.</param>
                                  /// <param name="name">The name of the property that changed.</param>
                                  public ItemPropertyChangedEventArgs(int index, string name) : base(name)
                                  {
                                  CollectionIndex = index;
                                  }

                                  /// <summary>
                                  /// Initializes a new instance of the <see cref="ItemPropertyChangedEventArgs"/> class.
                                  /// </summary>
                                  /// <param name="index">The index.</param>
                                  /// <param name="args">The <see cref="PropertyChangedEventArgs"/> instance containing the event data.</param>
                                  public ItemPropertyChangedEventArgs(int index, PropertyChangedEventArgs args) : this(index, args.PropertyName)
                                  { }
                                  }
                                  }


                                  NUnit Tests



                                  So you can check changes you might make (and see what I tested in the first place!), I've also included my NUnit test class. Obviously, the following code is not necessary just to use FullyObservableCollection<T> in your project.



                                  NB The test class uses BindableBase from PRISM to implement INotifyPropertyChanged. There is no dependency on PRISM from the main code.



                                  using NUnit.Framework;
                                  using Utilities;
                                  using Microsoft.Practices.Prism.Mvvm;
                                  using System.Collections.Specialized;
                                  using System.Collections.Generic;

                                  namespace Test_Utilities
                                  {
                                  [TestFixture]
                                  public class Test_FullyObservableCollection : AssertionHelper
                                  {
                                  public class NotifyingTestClass : BindableBase
                                  {
                                  public int Id
                                  {
                                  get { return _Id; }
                                  set { SetProperty(ref _Id, value); }
                                  }
                                  private int _Id;

                                  public string Name
                                  {
                                  get { return _Name; }
                                  set { SetProperty(ref _Name, value); }
                                  }
                                  private string _Name;

                                  }

                                  FullyObservableCollection<NotifyingTestClass> TestCollection;
                                  NotifyingTestClass Fred;
                                  NotifyingTestClass Betty;
                                  List<NotifyCollectionChangedEventArgs> CollectionEventList;
                                  List<ItemPropertyChangedEventArgs> ItemEventList;

                                  [SetUp]
                                  public void Init()
                                  {
                                  Fred = new NotifyingTestClass() { Id = 1, Name = "Fred" };
                                  Betty = new NotifyingTestClass() { Id = 4, Name = "Betty" };

                                  TestCollection = new FullyObservableCollection<NotifyingTestClass>()
                                  {
                                  Fred,
                                  new NotifyingTestClass() {Id = 2, Name = "Barney" },
                                  new NotifyingTestClass() {Id = 3, Name = "Wilma" }
                                  };

                                  CollectionEventList = new List<NotifyCollectionChangedEventArgs>();
                                  ItemEventList = new List<ItemPropertyChangedEventArgs>();
                                  TestCollection.CollectionChanged += (o, e) => CollectionEventList.Add(e);
                                  TestCollection.ItemPropertyChanged += (o, e) => ItemEventList.Add(e);
                                  }

                                  // Change existing member property: just ItemPropertyChanged(IPC) should fire
                                  [Test]
                                  public void DetectMemberPropertyChange()
                                  {
                                  TestCollection[0].Id = 7;

                                  Expect(CollectionEventList.Count, Is.EqualTo(0));

                                  Expect(ItemEventList.Count, Is.EqualTo(1), "IPC count");
                                  Expect(ItemEventList[0].PropertyName, Is.EqualTo(nameof(Fred.Id)), "Field Name");
                                  Expect(ItemEventList[0].CollectionIndex, Is.EqualTo(0), "Collection Index");
                                  }


                                  // Add new member, change property: CollectionPropertyChanged (CPC) and IPC should fire
                                  [Test]
                                  public void DetectNewMemberPropertyChange()
                                  {
                                  TestCollection.Add(Betty);

                                  Expect(TestCollection.Count, Is.EqualTo(4));
                                  Expect(TestCollection[3].Name, Is.EqualTo("Betty"));

                                  Expect(ItemEventList.Count, Is.EqualTo(0), "Item Event count");

                                  Expect(CollectionEventList.Count, Is.EqualTo(1), "Collection Event count");
                                  Expect(CollectionEventList[0].Action, Is.EqualTo(NotifyCollectionChangedAction.Add), "Action (add)");
                                  Expect(CollectionEventList[0].OldItems, Is.Null, "OldItems count");
                                  Expect(CollectionEventList[0].NewItems.Count, Is.EqualTo(1), "NewItems count");
                                  Expect(CollectionEventList[0].NewItems[0], Is.EqualTo(Betty), "NewItems[0] dereference");

                                  CollectionEventList.Clear(); // Empty for next operation
                                  ItemEventList.Clear();

                                  TestCollection[3].Id = 7;
                                  Expect(CollectionEventList.Count, Is.EqualTo(0), "Collection Event count");

                                  Expect(ItemEventList.Count, Is.EqualTo(1), "Item Event count");
                                  Expect(TestCollection[ItemEventList[0].CollectionIndex], Is.EqualTo(Betty), "Collection Index dereference");
                                  }


                                  // Remove member, change property: CPC should fire for removel, neither CPC nor IPC should fire for change
                                  [Test]
                                  public void CeaseListentingWhenMemberRemoved()
                                  {
                                  TestCollection.Remove(Fred);

                                  Expect(TestCollection.Count, Is.EqualTo(2));
                                  Expect(TestCollection.IndexOf(Fred), Is.Negative);

                                  Expect(ItemEventList.Count, Is.EqualTo(0), "Item Event count (pre change)");

                                  Expect(CollectionEventList.Count, Is.EqualTo(1), "Collection Event count (pre change)");
                                  Expect(CollectionEventList[0].Action, Is.EqualTo(NotifyCollectionChangedAction.Remove), "Action (remove)");
                                  Expect(CollectionEventList[0].OldItems.Count, Is.EqualTo(1), "OldItems count");
                                  Expect(CollectionEventList[0].NewItems, Is.Null, "NewItems count");
                                  Expect(CollectionEventList[0].OldItems[0], Is.EqualTo(Fred), "OldItems[0] dereference");

                                  CollectionEventList.Clear(); // Empty for next operation
                                  ItemEventList.Clear();

                                  Fred.Id = 7;
                                  Expect(CollectionEventList.Count, Is.EqualTo(0), "Collection Event count (post change)");
                                  Expect(ItemEventList.Count, Is.EqualTo(0), "Item Event count (post change)");
                                  }


                                  // Move member in list, change property: CPC should fire for move, IPC should fire for change
                                  [Test]
                                  public void MoveMember()
                                  {
                                  TestCollection.Move(0, 1);

                                  Expect(TestCollection.Count, Is.EqualTo(3));
                                  Expect(TestCollection.IndexOf(Fred), Is.GreaterThan(0));

                                  Expect(ItemEventList.Count, Is.EqualTo(0), "Item Event count (pre change)");

                                  Expect(CollectionEventList.Count, Is.EqualTo(1), "Collection Event count (pre change)");
                                  Expect(CollectionEventList[0].Action, Is.EqualTo(NotifyCollectionChangedAction.Move), "Action (move)");
                                  Expect(CollectionEventList[0].OldItems.Count, Is.EqualTo(1), "OldItems count");
                                  Expect(CollectionEventList[0].NewItems.Count, Is.EqualTo(1), "NewItems count");
                                  Expect(CollectionEventList[0].OldItems[0], Is.EqualTo(Fred), "OldItems[0] dereference");
                                  Expect(CollectionEventList[0].NewItems[0], Is.EqualTo(Fred), "NewItems[0] dereference");

                                  CollectionEventList.Clear(); // Empty for next operation
                                  ItemEventList.Clear();

                                  Fred.Id = 7;
                                  Expect(CollectionEventList.Count, Is.EqualTo(0), "Collection Event count (post change)");

                                  Expect(ItemEventList.Count, Is.EqualTo(1), "Item Event count (post change)");
                                  Expect(TestCollection[ItemEventList[0].CollectionIndex], Is.EqualTo(Fred), "Collection Index dereference");
                                  }


                                  // Clear list, chnage property: only CPC should fire for clear and neither for property change
                                  [Test]
                                  public void ClearList()
                                  {
                                  TestCollection.Clear();

                                  Expect(TestCollection.Count, Is.EqualTo(0));

                                  Expect(ItemEventList.Count, Is.EqualTo(0), "Item Event count (pre change)");

                                  Expect(CollectionEventList.Count, Is.EqualTo(1), "Collection Event count (pre change)");
                                  Expect(CollectionEventList[0].Action, Is.EqualTo(NotifyCollectionChangedAction.Reset), "Action (reset)");
                                  Expect(CollectionEventList[0].OldItems, Is.Null, "OldItems count");
                                  Expect(CollectionEventList[0].NewItems, Is.Null, "NewItems count");

                                  CollectionEventList.Clear(); // Empty for next operation
                                  ItemEventList.Clear();

                                  Fred.Id = 7;
                                  Expect(CollectionEventList.Count, Is.EqualTo(0), "Collection Event count (post change)");
                                  Expect(ItemEventList.Count, Is.EqualTo(0), "Item Event count (post change)");
                                  }
                                  }
                                  }





                                  share|improve this answer















                                  I've put together what I hope is a pretty robust solution, including some of the techniques in other answers. It is a new class derived from ObservableCollection<>, which I'm calling FullyObservableCollection<>



                                  It has the following features:




                                  • It adds a new event, ItemPropertyChanged. I've deliberately kept this separate from the existing CollectionChanged:


                                    • To aid backward compatibility.

                                    • So more relevant detail can be given in the new ItemPropertyChangedEventArgs that accompanies it: the original PropertyChangedEventArgs and the index within the collection.



                                  • It replicates all the constructors from ObservableCollection<>.

                                  • It correctly handles the list being reset (ObservableCollection<>.Clear()), avoiding a possible memory leak.

                                  • It overrides the base class's OnCollectionChanged(), rather than a more resource-intensive subscription to the CollectionChanged event.


                                  Code



                                  The complete .cs file follows. Note that a few features of C# 6 have been used, but it should be fairly simple to backport it:



                                  using System;
                                  using System.Collections.Generic;
                                  using System.Collections.ObjectModel;
                                  using System.Collections.Specialized;
                                  using System.ComponentModel;

                                  namespace Utilities
                                  {
                                  public class FullyObservableCollection<T> : ObservableCollection<T>
                                  where T : INotifyPropertyChanged
                                  {
                                  /// <summary>
                                  /// Occurs when a property is changed within an item.
                                  /// </summary>
                                  public event EventHandler<ItemPropertyChangedEventArgs> ItemPropertyChanged;

                                  public FullyObservableCollection() : base()
                                  { }

                                  public FullyObservableCollection(List<T> list) : base(list)
                                  {
                                  ObserveAll();
                                  }

                                  public FullyObservableCollection(IEnumerable<T> enumerable) : base(enumerable)
                                  {
                                  ObserveAll();
                                  }

                                  protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
                                  {
                                  if (e.Action == NotifyCollectionChangedAction.Remove ||
                                  e.Action == NotifyCollectionChangedAction.Replace)
                                  {
                                  foreach (T item in e.OldItems)
                                  item.PropertyChanged -= ChildPropertyChanged;
                                  }

                                  if (e.Action == NotifyCollectionChangedAction.Add ||
                                  e.Action == NotifyCollectionChangedAction.Replace)
                                  {
                                  foreach (T item in e.NewItems)
                                  item.PropertyChanged += ChildPropertyChanged;
                                  }

                                  base.OnCollectionChanged(e);
                                  }

                                  protected void OnItemPropertyChanged(ItemPropertyChangedEventArgs e)
                                  {
                                  ItemPropertyChanged?.Invoke(this, e);
                                  }

                                  protected void OnItemPropertyChanged(int index, PropertyChangedEventArgs e)
                                  {
                                  OnItemPropertyChanged(new ItemPropertyChangedEventArgs(index, e));
                                  }

                                  protected override void ClearItems()
                                  {
                                  foreach (T item in Items)
                                  item.PropertyChanged -= ChildPropertyChanged;

                                  base.ClearItems();
                                  }

                                  private void ObserveAll()
                                  {
                                  foreach (T item in Items)
                                  item.PropertyChanged += ChildPropertyChanged;
                                  }

                                  private void ChildPropertyChanged(object sender, PropertyChangedEventArgs e)
                                  {
                                  T typedSender = (T)sender;
                                  int i = Items.IndexOf(typedSender);

                                  if (i < 0)
                                  throw new ArgumentException("Received property notification from item not in collection");

                                  OnItemPropertyChanged(i, e);
                                  }
                                  }

                                  /// <summary>
                                  /// Provides data for the <see cref="FullyObservableCollection{T}.ItemPropertyChanged"/> event.
                                  /// </summary>
                                  public class ItemPropertyChangedEventArgs : PropertyChangedEventArgs
                                  {
                                  /// <summary>
                                  /// Gets the index in the collection for which the property change has occurred.
                                  /// </summary>
                                  /// <value>
                                  /// Index in parent collection.
                                  /// </value>
                                  public int CollectionIndex { get; }

                                  /// <summary>
                                  /// Initializes a new instance of the <see cref="ItemPropertyChangedEventArgs"/> class.
                                  /// </summary>
                                  /// <param name="index">The index in the collection of changed item.</param>
                                  /// <param name="name">The name of the property that changed.</param>
                                  public ItemPropertyChangedEventArgs(int index, string name) : base(name)
                                  {
                                  CollectionIndex = index;
                                  }

                                  /// <summary>
                                  /// Initializes a new instance of the <see cref="ItemPropertyChangedEventArgs"/> class.
                                  /// </summary>
                                  /// <param name="index">The index.</param>
                                  /// <param name="args">The <see cref="PropertyChangedEventArgs"/> instance containing the event data.</param>
                                  public ItemPropertyChangedEventArgs(int index, PropertyChangedEventArgs args) : this(index, args.PropertyName)
                                  { }
                                  }
                                  }


                                  NUnit Tests



                                  So you can check changes you might make (and see what I tested in the first place!), I've also included my NUnit test class. Obviously, the following code is not necessary just to use FullyObservableCollection<T> in your project.



                                  NB The test class uses BindableBase from PRISM to implement INotifyPropertyChanged. There is no dependency on PRISM from the main code.



                                  using NUnit.Framework;
                                  using Utilities;
                                  using Microsoft.Practices.Prism.Mvvm;
                                  using System.Collections.Specialized;
                                  using System.Collections.Generic;

                                  namespace Test_Utilities
                                  {
                                  [TestFixture]
                                  public class Test_FullyObservableCollection : AssertionHelper
                                  {
                                  public class NotifyingTestClass : BindableBase
                                  {
                                  public int Id
                                  {
                                  get { return _Id; }
                                  set { SetProperty(ref _Id, value); }
                                  }
                                  private int _Id;

                                  public string Name
                                  {
                                  get { return _Name; }
                                  set { SetProperty(ref _Name, value); }
                                  }
                                  private string _Name;

                                  }

                                  FullyObservableCollection<NotifyingTestClass> TestCollection;
                                  NotifyingTestClass Fred;
                                  NotifyingTestClass Betty;
                                  List<NotifyCollectionChangedEventArgs> CollectionEventList;
                                  List<ItemPropertyChangedEventArgs> ItemEventList;

                                  [SetUp]
                                  public void Init()
                                  {
                                  Fred = new NotifyingTestClass() { Id = 1, Name = "Fred" };
                                  Betty = new NotifyingTestClass() { Id = 4, Name = "Betty" };

                                  TestCollection = new FullyObservableCollection<NotifyingTestClass>()
                                  {
                                  Fred,
                                  new NotifyingTestClass() {Id = 2, Name = "Barney" },
                                  new NotifyingTestClass() {Id = 3, Name = "Wilma" }
                                  };

                                  CollectionEventList = new List<NotifyCollectionChangedEventArgs>();
                                  ItemEventList = new List<ItemPropertyChangedEventArgs>();
                                  TestCollection.CollectionChanged += (o, e) => CollectionEventList.Add(e);
                                  TestCollection.ItemPropertyChanged += (o, e) => ItemEventList.Add(e);
                                  }

                                  // Change existing member property: just ItemPropertyChanged(IPC) should fire
                                  [Test]
                                  public void DetectMemberPropertyChange()
                                  {
                                  TestCollection[0].Id = 7;

                                  Expect(CollectionEventList.Count, Is.EqualTo(0));

                                  Expect(ItemEventList.Count, Is.EqualTo(1), "IPC count");
                                  Expect(ItemEventList[0].PropertyName, Is.EqualTo(nameof(Fred.Id)), "Field Name");
                                  Expect(ItemEventList[0].CollectionIndex, Is.EqualTo(0), "Collection Index");
                                  }


                                  // Add new member, change property: CollectionPropertyChanged (CPC) and IPC should fire
                                  [Test]
                                  public void DetectNewMemberPropertyChange()
                                  {
                                  TestCollection.Add(Betty);

                                  Expect(TestCollection.Count, Is.EqualTo(4));
                                  Expect(TestCollection[3].Name, Is.EqualTo("Betty"));

                                  Expect(ItemEventList.Count, Is.EqualTo(0), "Item Event count");

                                  Expect(CollectionEventList.Count, Is.EqualTo(1), "Collection Event count");
                                  Expect(CollectionEventList[0].Action, Is.EqualTo(NotifyCollectionChangedAction.Add), "Action (add)");
                                  Expect(CollectionEventList[0].OldItems, Is.Null, "OldItems count");
                                  Expect(CollectionEventList[0].NewItems.Count, Is.EqualTo(1), "NewItems count");
                                  Expect(CollectionEventList[0].NewItems[0], Is.EqualTo(Betty), "NewItems[0] dereference");

                                  CollectionEventList.Clear(); // Empty for next operation
                                  ItemEventList.Clear();

                                  TestCollection[3].Id = 7;
                                  Expect(CollectionEventList.Count, Is.EqualTo(0), "Collection Event count");

                                  Expect(ItemEventList.Count, Is.EqualTo(1), "Item Event count");
                                  Expect(TestCollection[ItemEventList[0].CollectionIndex], Is.EqualTo(Betty), "Collection Index dereference");
                                  }


                                  // Remove member, change property: CPC should fire for removel, neither CPC nor IPC should fire for change
                                  [Test]
                                  public void CeaseListentingWhenMemberRemoved()
                                  {
                                  TestCollection.Remove(Fred);

                                  Expect(TestCollection.Count, Is.EqualTo(2));
                                  Expect(TestCollection.IndexOf(Fred), Is.Negative);

                                  Expect(ItemEventList.Count, Is.EqualTo(0), "Item Event count (pre change)");

                                  Expect(CollectionEventList.Count, Is.EqualTo(1), "Collection Event count (pre change)");
                                  Expect(CollectionEventList[0].Action, Is.EqualTo(NotifyCollectionChangedAction.Remove), "Action (remove)");
                                  Expect(CollectionEventList[0].OldItems.Count, Is.EqualTo(1), "OldItems count");
                                  Expect(CollectionEventList[0].NewItems, Is.Null, "NewItems count");
                                  Expect(CollectionEventList[0].OldItems[0], Is.EqualTo(Fred), "OldItems[0] dereference");

                                  CollectionEventList.Clear(); // Empty for next operation
                                  ItemEventList.Clear();

                                  Fred.Id = 7;
                                  Expect(CollectionEventList.Count, Is.EqualTo(0), "Collection Event count (post change)");
                                  Expect(ItemEventList.Count, Is.EqualTo(0), "Item Event count (post change)");
                                  }


                                  // Move member in list, change property: CPC should fire for move, IPC should fire for change
                                  [Test]
                                  public void MoveMember()
                                  {
                                  TestCollection.Move(0, 1);

                                  Expect(TestCollection.Count, Is.EqualTo(3));
                                  Expect(TestCollection.IndexOf(Fred), Is.GreaterThan(0));

                                  Expect(ItemEventList.Count, Is.EqualTo(0), "Item Event count (pre change)");

                                  Expect(CollectionEventList.Count, Is.EqualTo(1), "Collection Event count (pre change)");
                                  Expect(CollectionEventList[0].Action, Is.EqualTo(NotifyCollectionChangedAction.Move), "Action (move)");
                                  Expect(CollectionEventList[0].OldItems.Count, Is.EqualTo(1), "OldItems count");
                                  Expect(CollectionEventList[0].NewItems.Count, Is.EqualTo(1), "NewItems count");
                                  Expect(CollectionEventList[0].OldItems[0], Is.EqualTo(Fred), "OldItems[0] dereference");
                                  Expect(CollectionEventList[0].NewItems[0], Is.EqualTo(Fred), "NewItems[0] dereference");

                                  CollectionEventList.Clear(); // Empty for next operation
                                  ItemEventList.Clear();

                                  Fred.Id = 7;
                                  Expect(CollectionEventList.Count, Is.EqualTo(0), "Collection Event count (post change)");

                                  Expect(ItemEventList.Count, Is.EqualTo(1), "Item Event count (post change)");
                                  Expect(TestCollection[ItemEventList[0].CollectionIndex], Is.EqualTo(Fred), "Collection Index dereference");
                                  }


                                  // Clear list, chnage property: only CPC should fire for clear and neither for property change
                                  [Test]
                                  public void ClearList()
                                  {
                                  TestCollection.Clear();

                                  Expect(TestCollection.Count, Is.EqualTo(0));

                                  Expect(ItemEventList.Count, Is.EqualTo(0), "Item Event count (pre change)");

                                  Expect(CollectionEventList.Count, Is.EqualTo(1), "Collection Event count (pre change)");
                                  Expect(CollectionEventList[0].Action, Is.EqualTo(NotifyCollectionChangedAction.Reset), "Action (reset)");
                                  Expect(CollectionEventList[0].OldItems, Is.Null, "OldItems count");
                                  Expect(CollectionEventList[0].NewItems, Is.Null, "NewItems count");

                                  CollectionEventList.Clear(); // Empty for next operation
                                  ItemEventList.Clear();

                                  Fred.Id = 7;
                                  Expect(CollectionEventList.Count, Is.EqualTo(0), "Collection Event count (post change)");
                                  Expect(ItemEventList.Count, Is.EqualTo(0), "Item Event count (post change)");
                                  }
                                  }
                                  }






                                  share|improve this answer














                                  share|improve this answer



                                  share|improve this answer








                                  edited Aug 21 '18 at 13:19

























                                  answered Aug 14 '15 at 15:29









                                  Bob SammersBob Sammers

                                  1,7841623




                                  1,7841623













                                  • I don't know what I am doing wrong, but this doesn't work for me. I'm binding my ListView to your collection but when I update the properties of the items inside, the ListView doesn't update, even tho' I can see all the events firing up. I'm also using the PRISM library...

                                    – Renato Parreira
                                    Feb 24 '17 at 15:20











                                  • @Renato, have you done anything with the new event? ListView will respond to CollectionChanged events because it knows about them. ItemPropertyChanged is a non-standard addition, so you need to teach it about that. As a quick and dirty fix, you could try just firing the CollectionChanged event as well as (or even instead of) ItemPropertyChanged in OnItemPropertyChanged(). I kept them separate for reasons stated in the answer, but for your use-case it might just do what you need.

                                    – Bob Sammers
                                    Mar 2 '17 at 18:13





















                                  • I don't know what I am doing wrong, but this doesn't work for me. I'm binding my ListView to your collection but when I update the properties of the items inside, the ListView doesn't update, even tho' I can see all the events firing up. I'm also using the PRISM library...

                                    – Renato Parreira
                                    Feb 24 '17 at 15:20











                                  • @Renato, have you done anything with the new event? ListView will respond to CollectionChanged events because it knows about them. ItemPropertyChanged is a non-standard addition, so you need to teach it about that. As a quick and dirty fix, you could try just firing the CollectionChanged event as well as (or even instead of) ItemPropertyChanged in OnItemPropertyChanged(). I kept them separate for reasons stated in the answer, but for your use-case it might just do what you need.

                                    – Bob Sammers
                                    Mar 2 '17 at 18:13



















                                  I don't know what I am doing wrong, but this doesn't work for me. I'm binding my ListView to your collection but when I update the properties of the items inside, the ListView doesn't update, even tho' I can see all the events firing up. I'm also using the PRISM library...

                                  – Renato Parreira
                                  Feb 24 '17 at 15:20





                                  I don't know what I am doing wrong, but this doesn't work for me. I'm binding my ListView to your collection but when I update the properties of the items inside, the ListView doesn't update, even tho' I can see all the events firing up. I'm also using the PRISM library...

                                  – Renato Parreira
                                  Feb 24 '17 at 15:20













                                  @Renato, have you done anything with the new event? ListView will respond to CollectionChanged events because it knows about them. ItemPropertyChanged is a non-standard addition, so you need to teach it about that. As a quick and dirty fix, you could try just firing the CollectionChanged event as well as (or even instead of) ItemPropertyChanged in OnItemPropertyChanged(). I kept them separate for reasons stated in the answer, but for your use-case it might just do what you need.

                                  – Bob Sammers
                                  Mar 2 '17 at 18:13







                                  @Renato, have you done anything with the new event? ListView will respond to CollectionChanged events because it knows about them. ItemPropertyChanged is a non-standard addition, so you need to teach it about that. As a quick and dirty fix, you could try just firing the CollectionChanged event as well as (or even instead of) ItemPropertyChanged in OnItemPropertyChanged(). I kept them separate for reasons stated in the answer, but for your use-case it might just do what you need.

                                  – Bob Sammers
                                  Mar 2 '17 at 18:13













                                  10














                                  ObservableCollection will not propagate individual item changes as CollectionChanged events. You will either need to subscribe to each event and forward it manually, or you can check out the BindingList[T] class, which will do this for you.






                                  share|improve this answer




























                                    10














                                    ObservableCollection will not propagate individual item changes as CollectionChanged events. You will either need to subscribe to each event and forward it manually, or you can check out the BindingList[T] class, which will do this for you.






                                    share|improve this answer


























                                      10












                                      10








                                      10







                                      ObservableCollection will not propagate individual item changes as CollectionChanged events. You will either need to subscribe to each event and forward it manually, or you can check out the BindingList[T] class, which will do this for you.






                                      share|improve this answer













                                      ObservableCollection will not propagate individual item changes as CollectionChanged events. You will either need to subscribe to each event and forward it manually, or you can check out the BindingList[T] class, which will do this for you.







                                      share|improve this answer












                                      share|improve this answer



                                      share|improve this answer










                                      answered Sep 15 '09 at 15:13









                                      mjeanesmjeanes

                                      1,35686




                                      1,35686























                                          7














                                          Added to TruelyObservableCollection event "ItemPropertyChanged":



                                          using System;
                                          using System.Collections.Generic;
                                          using System.Collections.ObjectModel; // ObservableCollection
                                          using System.ComponentModel; // INotifyPropertyChanged
                                          using System.Collections.Specialized; // NotifyCollectionChangedEventHandler
                                          using System.Linq;
                                          using System.Text;
                                          using System.Threading.Tasks;

                                          namespace ObservableCollectionTest
                                          {
                                          class Program
                                          {
                                          static void Main(string args)
                                          {
                                          // ATTN: Please note it's a "TrulyObservableCollection" that's instantiated. Otherwise, "Trades[0].Qty = 999" will NOT trigger event handler "Trades_CollectionChanged" in main.
                                          // REF: http://stackoverflow.com/questions/8490533/notify-observablecollection-when-item-changes
                                          TrulyObservableCollection<Trade> Trades = new TrulyObservableCollection<Trade>();
                                          Trades.Add(new Trade { Symbol = "APPL", Qty = 123 });
                                          Trades.Add(new Trade { Symbol = "IBM", Qty = 456});
                                          Trades.Add(new Trade { Symbol = "CSCO", Qty = 789 });

                                          Trades.CollectionChanged += Trades_CollectionChanged;
                                          Trades.ItemPropertyChanged += PropertyChangedHandler;
                                          Trades.RemoveAt(2);

                                          Trades[0].Qty = 999;

                                          Console.WriteLine("Hit any key to exit");
                                          Console.ReadLine();

                                          return;
                                          }

                                          static void PropertyChangedHandler(object sender, PropertyChangedEventArgs e)
                                          {
                                          Console.WriteLine(DateTime.Now.ToString() + ", Property changed: " + e.PropertyName + ", Symbol: " + ((Trade) sender).Symbol + ", Qty: " + ((Trade) sender).Qty);
                                          return;
                                          }

                                          static void Trades_CollectionChanged(object sender, EventArgs e)
                                          {
                                          Console.WriteLine(DateTime.Now.ToString() + ", Collection changed");
                                          return;
                                          }
                                          }

                                          #region TrulyObservableCollection
                                          public class TrulyObservableCollection<T> : ObservableCollection<T>
                                          where T : INotifyPropertyChanged
                                          {
                                          public event PropertyChangedEventHandler ItemPropertyChanged;

                                          public TrulyObservableCollection()
                                          : base()
                                          {
                                          CollectionChanged += new NotifyCollectionChangedEventHandler(TrulyObservableCollection_CollectionChanged);
                                          }

                                          void TrulyObservableCollection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
                                          {
                                          if (e.NewItems != null)
                                          {
                                          foreach (Object item in e.NewItems)
                                          {
                                          (item as INotifyPropertyChanged).PropertyChanged += new PropertyChangedEventHandler(item_PropertyChanged);
                                          }
                                          }
                                          if (e.OldItems != null)
                                          {
                                          foreach (Object item in e.OldItems)
                                          {
                                          (item as INotifyPropertyChanged).PropertyChanged -= new PropertyChangedEventHandler(item_PropertyChanged);
                                          }
                                          }
                                          }

                                          void item_PropertyChanged(object sender, PropertyChangedEventArgs e)
                                          {
                                          NotifyCollectionChangedEventArgs a = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset);
                                          OnCollectionChanged(a);

                                          if (ItemPropertyChanged != null)
                                          {
                                          ItemPropertyChanged(sender, e);
                                          }
                                          }
                                          }
                                          #endregion

                                          #region Sample entity
                                          class Trade : INotifyPropertyChanged
                                          {
                                          protected string _Symbol;
                                          protected int _Qty = 0;
                                          protected DateTime _OrderPlaced = DateTime.Now;

                                          public DateTime OrderPlaced
                                          {
                                          get { return _OrderPlaced; }
                                          }

                                          public string Symbol
                                          {
                                          get
                                          {
                                          return _Symbol;
                                          }
                                          set
                                          {
                                          _Symbol = value;
                                          NotifyPropertyChanged("Symbol");
                                          }
                                          }

                                          public int Qty
                                          {
                                          get
                                          {
                                          return _Qty;
                                          }
                                          set
                                          {
                                          _Qty = value;
                                          NotifyPropertyChanged("Qty");
                                          }
                                          }

                                          public event PropertyChangedEventHandler PropertyChanged;

                                          private void NotifyPropertyChanged(String propertyName = "")
                                          {
                                          if (PropertyChanged != null)
                                          {
                                          PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
                                          }
                                          }
                                          }
                                          #endregion
                                          }





                                          share|improve this answer
























                                          • You could use PropertyChanged from ObservableCollection directly, since it implements INotifyPropertyChanged.

                                            – Dieter Meemken
                                            Jun 3 '16 at 14:23
















                                          7














                                          Added to TruelyObservableCollection event "ItemPropertyChanged":



                                          using System;
                                          using System.Collections.Generic;
                                          using System.Collections.ObjectModel; // ObservableCollection
                                          using System.ComponentModel; // INotifyPropertyChanged
                                          using System.Collections.Specialized; // NotifyCollectionChangedEventHandler
                                          using System.Linq;
                                          using System.Text;
                                          using System.Threading.Tasks;

                                          namespace ObservableCollectionTest
                                          {
                                          class Program
                                          {
                                          static void Main(string args)
                                          {
                                          // ATTN: Please note it's a "TrulyObservableCollection" that's instantiated. Otherwise, "Trades[0].Qty = 999" will NOT trigger event handler "Trades_CollectionChanged" in main.
                                          // REF: http://stackoverflow.com/questions/8490533/notify-observablecollection-when-item-changes
                                          TrulyObservableCollection<Trade> Trades = new TrulyObservableCollection<Trade>();
                                          Trades.Add(new Trade { Symbol = "APPL", Qty = 123 });
                                          Trades.Add(new Trade { Symbol = "IBM", Qty = 456});
                                          Trades.Add(new Trade { Symbol = "CSCO", Qty = 789 });

                                          Trades.CollectionChanged += Trades_CollectionChanged;
                                          Trades.ItemPropertyChanged += PropertyChangedHandler;
                                          Trades.RemoveAt(2);

                                          Trades[0].Qty = 999;

                                          Console.WriteLine("Hit any key to exit");
                                          Console.ReadLine();

                                          return;
                                          }

                                          static void PropertyChangedHandler(object sender, PropertyChangedEventArgs e)
                                          {
                                          Console.WriteLine(DateTime.Now.ToString() + ", Property changed: " + e.PropertyName + ", Symbol: " + ((Trade) sender).Symbol + ", Qty: " + ((Trade) sender).Qty);
                                          return;
                                          }

                                          static void Trades_CollectionChanged(object sender, EventArgs e)
                                          {
                                          Console.WriteLine(DateTime.Now.ToString() + ", Collection changed");
                                          return;
                                          }
                                          }

                                          #region TrulyObservableCollection
                                          public class TrulyObservableCollection<T> : ObservableCollection<T>
                                          where T : INotifyPropertyChanged
                                          {
                                          public event PropertyChangedEventHandler ItemPropertyChanged;

                                          public TrulyObservableCollection()
                                          : base()
                                          {
                                          CollectionChanged += new NotifyCollectionChangedEventHandler(TrulyObservableCollection_CollectionChanged);
                                          }

                                          void TrulyObservableCollection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
                                          {
                                          if (e.NewItems != null)
                                          {
                                          foreach (Object item in e.NewItems)
                                          {
                                          (item as INotifyPropertyChanged).PropertyChanged += new PropertyChangedEventHandler(item_PropertyChanged);
                                          }
                                          }
                                          if (e.OldItems != null)
                                          {
                                          foreach (Object item in e.OldItems)
                                          {
                                          (item as INotifyPropertyChanged).PropertyChanged -= new PropertyChangedEventHandler(item_PropertyChanged);
                                          }
                                          }
                                          }

                                          void item_PropertyChanged(object sender, PropertyChangedEventArgs e)
                                          {
                                          NotifyCollectionChangedEventArgs a = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset);
                                          OnCollectionChanged(a);

                                          if (ItemPropertyChanged != null)
                                          {
                                          ItemPropertyChanged(sender, e);
                                          }
                                          }
                                          }
                                          #endregion

                                          #region Sample entity
                                          class Trade : INotifyPropertyChanged
                                          {
                                          protected string _Symbol;
                                          protected int _Qty = 0;
                                          protected DateTime _OrderPlaced = DateTime.Now;

                                          public DateTime OrderPlaced
                                          {
                                          get { return _OrderPlaced; }
                                          }

                                          public string Symbol
                                          {
                                          get
                                          {
                                          return _Symbol;
                                          }
                                          set
                                          {
                                          _Symbol = value;
                                          NotifyPropertyChanged("Symbol");
                                          }
                                          }

                                          public int Qty
                                          {
                                          get
                                          {
                                          return _Qty;
                                          }
                                          set
                                          {
                                          _Qty = value;
                                          NotifyPropertyChanged("Qty");
                                          }
                                          }

                                          public event PropertyChangedEventHandler PropertyChanged;

                                          private void NotifyPropertyChanged(String propertyName = "")
                                          {
                                          if (PropertyChanged != null)
                                          {
                                          PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
                                          }
                                          }
                                          }
                                          #endregion
                                          }





                                          share|improve this answer
























                                          • You could use PropertyChanged from ObservableCollection directly, since it implements INotifyPropertyChanged.

                                            – Dieter Meemken
                                            Jun 3 '16 at 14:23














                                          7












                                          7








                                          7







                                          Added to TruelyObservableCollection event "ItemPropertyChanged":



                                          using System;
                                          using System.Collections.Generic;
                                          using System.Collections.ObjectModel; // ObservableCollection
                                          using System.ComponentModel; // INotifyPropertyChanged
                                          using System.Collections.Specialized; // NotifyCollectionChangedEventHandler
                                          using System.Linq;
                                          using System.Text;
                                          using System.Threading.Tasks;

                                          namespace ObservableCollectionTest
                                          {
                                          class Program
                                          {
                                          static void Main(string args)
                                          {
                                          // ATTN: Please note it's a "TrulyObservableCollection" that's instantiated. Otherwise, "Trades[0].Qty = 999" will NOT trigger event handler "Trades_CollectionChanged" in main.
                                          // REF: http://stackoverflow.com/questions/8490533/notify-observablecollection-when-item-changes
                                          TrulyObservableCollection<Trade> Trades = new TrulyObservableCollection<Trade>();
                                          Trades.Add(new Trade { Symbol = "APPL", Qty = 123 });
                                          Trades.Add(new Trade { Symbol = "IBM", Qty = 456});
                                          Trades.Add(new Trade { Symbol = "CSCO", Qty = 789 });

                                          Trades.CollectionChanged += Trades_CollectionChanged;
                                          Trades.ItemPropertyChanged += PropertyChangedHandler;
                                          Trades.RemoveAt(2);

                                          Trades[0].Qty = 999;

                                          Console.WriteLine("Hit any key to exit");
                                          Console.ReadLine();

                                          return;
                                          }

                                          static void PropertyChangedHandler(object sender, PropertyChangedEventArgs e)
                                          {
                                          Console.WriteLine(DateTime.Now.ToString() + ", Property changed: " + e.PropertyName + ", Symbol: " + ((Trade) sender).Symbol + ", Qty: " + ((Trade) sender).Qty);
                                          return;
                                          }

                                          static void Trades_CollectionChanged(object sender, EventArgs e)
                                          {
                                          Console.WriteLine(DateTime.Now.ToString() + ", Collection changed");
                                          return;
                                          }
                                          }

                                          #region TrulyObservableCollection
                                          public class TrulyObservableCollection<T> : ObservableCollection<T>
                                          where T : INotifyPropertyChanged
                                          {
                                          public event PropertyChangedEventHandler ItemPropertyChanged;

                                          public TrulyObservableCollection()
                                          : base()
                                          {
                                          CollectionChanged += new NotifyCollectionChangedEventHandler(TrulyObservableCollection_CollectionChanged);
                                          }

                                          void TrulyObservableCollection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
                                          {
                                          if (e.NewItems != null)
                                          {
                                          foreach (Object item in e.NewItems)
                                          {
                                          (item as INotifyPropertyChanged).PropertyChanged += new PropertyChangedEventHandler(item_PropertyChanged);
                                          }
                                          }
                                          if (e.OldItems != null)
                                          {
                                          foreach (Object item in e.OldItems)
                                          {
                                          (item as INotifyPropertyChanged).PropertyChanged -= new PropertyChangedEventHandler(item_PropertyChanged);
                                          }
                                          }
                                          }

                                          void item_PropertyChanged(object sender, PropertyChangedEventArgs e)
                                          {
                                          NotifyCollectionChangedEventArgs a = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset);
                                          OnCollectionChanged(a);

                                          if (ItemPropertyChanged != null)
                                          {
                                          ItemPropertyChanged(sender, e);
                                          }
                                          }
                                          }
                                          #endregion

                                          #region Sample entity
                                          class Trade : INotifyPropertyChanged
                                          {
                                          protected string _Symbol;
                                          protected int _Qty = 0;
                                          protected DateTime _OrderPlaced = DateTime.Now;

                                          public DateTime OrderPlaced
                                          {
                                          get { return _OrderPlaced; }
                                          }

                                          public string Symbol
                                          {
                                          get
                                          {
                                          return _Symbol;
                                          }
                                          set
                                          {
                                          _Symbol = value;
                                          NotifyPropertyChanged("Symbol");
                                          }
                                          }

                                          public int Qty
                                          {
                                          get
                                          {
                                          return _Qty;
                                          }
                                          set
                                          {
                                          _Qty = value;
                                          NotifyPropertyChanged("Qty");
                                          }
                                          }

                                          public event PropertyChangedEventHandler PropertyChanged;

                                          private void NotifyPropertyChanged(String propertyName = "")
                                          {
                                          if (PropertyChanged != null)
                                          {
                                          PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
                                          }
                                          }
                                          }
                                          #endregion
                                          }





                                          share|improve this answer













                                          Added to TruelyObservableCollection event "ItemPropertyChanged":



                                          using System;
                                          using System.Collections.Generic;
                                          using System.Collections.ObjectModel; // ObservableCollection
                                          using System.ComponentModel; // INotifyPropertyChanged
                                          using System.Collections.Specialized; // NotifyCollectionChangedEventHandler
                                          using System.Linq;
                                          using System.Text;
                                          using System.Threading.Tasks;

                                          namespace ObservableCollectionTest
                                          {
                                          class Program
                                          {
                                          static void Main(string args)
                                          {
                                          // ATTN: Please note it's a "TrulyObservableCollection" that's instantiated. Otherwise, "Trades[0].Qty = 999" will NOT trigger event handler "Trades_CollectionChanged" in main.
                                          // REF: http://stackoverflow.com/questions/8490533/notify-observablecollection-when-item-changes
                                          TrulyObservableCollection<Trade> Trades = new TrulyObservableCollection<Trade>();
                                          Trades.Add(new Trade { Symbol = "APPL", Qty = 123 });
                                          Trades.Add(new Trade { Symbol = "IBM", Qty = 456});
                                          Trades.Add(new Trade { Symbol = "CSCO", Qty = 789 });

                                          Trades.CollectionChanged += Trades_CollectionChanged;
                                          Trades.ItemPropertyChanged += PropertyChangedHandler;
                                          Trades.RemoveAt(2);

                                          Trades[0].Qty = 999;

                                          Console.WriteLine("Hit any key to exit");
                                          Console.ReadLine();

                                          return;
                                          }

                                          static void PropertyChangedHandler(object sender, PropertyChangedEventArgs e)
                                          {
                                          Console.WriteLine(DateTime.Now.ToString() + ", Property changed: " + e.PropertyName + ", Symbol: " + ((Trade) sender).Symbol + ", Qty: " + ((Trade) sender).Qty);
                                          return;
                                          }

                                          static void Trades_CollectionChanged(object sender, EventArgs e)
                                          {
                                          Console.WriteLine(DateTime.Now.ToString() + ", Collection changed");
                                          return;
                                          }
                                          }

                                          #region TrulyObservableCollection
                                          public class TrulyObservableCollection<T> : ObservableCollection<T>
                                          where T : INotifyPropertyChanged
                                          {
                                          public event PropertyChangedEventHandler ItemPropertyChanged;

                                          public TrulyObservableCollection()
                                          : base()
                                          {
                                          CollectionChanged += new NotifyCollectionChangedEventHandler(TrulyObservableCollection_CollectionChanged);
                                          }

                                          void TrulyObservableCollection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
                                          {
                                          if (e.NewItems != null)
                                          {
                                          foreach (Object item in e.NewItems)
                                          {
                                          (item as INotifyPropertyChanged).PropertyChanged += new PropertyChangedEventHandler(item_PropertyChanged);
                                          }
                                          }
                                          if (e.OldItems != null)
                                          {
                                          foreach (Object item in e.OldItems)
                                          {
                                          (item as INotifyPropertyChanged).PropertyChanged -= new PropertyChangedEventHandler(item_PropertyChanged);
                                          }
                                          }
                                          }

                                          void item_PropertyChanged(object sender, PropertyChangedEventArgs e)
                                          {
                                          NotifyCollectionChangedEventArgs a = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset);
                                          OnCollectionChanged(a);

                                          if (ItemPropertyChanged != null)
                                          {
                                          ItemPropertyChanged(sender, e);
                                          }
                                          }
                                          }
                                          #endregion

                                          #region Sample entity
                                          class Trade : INotifyPropertyChanged
                                          {
                                          protected string _Symbol;
                                          protected int _Qty = 0;
                                          protected DateTime _OrderPlaced = DateTime.Now;

                                          public DateTime OrderPlaced
                                          {
                                          get { return _OrderPlaced; }
                                          }

                                          public string Symbol
                                          {
                                          get
                                          {
                                          return _Symbol;
                                          }
                                          set
                                          {
                                          _Symbol = value;
                                          NotifyPropertyChanged("Symbol");
                                          }
                                          }

                                          public int Qty
                                          {
                                          get
                                          {
                                          return _Qty;
                                          }
                                          set
                                          {
                                          _Qty = value;
                                          NotifyPropertyChanged("Qty");
                                          }
                                          }

                                          public event PropertyChangedEventHandler PropertyChanged;

                                          private void NotifyPropertyChanged(String propertyName = "")
                                          {
                                          if (PropertyChanged != null)
                                          {
                                          PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
                                          }
                                          }
                                          }
                                          #endregion
                                          }






                                          share|improve this answer












                                          share|improve this answer



                                          share|improve this answer










                                          answered Feb 17 '13 at 8:01









                                          Swab.JatSwab.Jat

                                          7831917




                                          7831917













                                          • You could use PropertyChanged from ObservableCollection directly, since it implements INotifyPropertyChanged.

                                            – Dieter Meemken
                                            Jun 3 '16 at 14:23



















                                          • You could use PropertyChanged from ObservableCollection directly, since it implements INotifyPropertyChanged.

                                            – Dieter Meemken
                                            Jun 3 '16 at 14:23

















                                          You could use PropertyChanged from ObservableCollection directly, since it implements INotifyPropertyChanged.

                                          – Dieter Meemken
                                          Jun 3 '16 at 14:23





                                          You could use PropertyChanged from ObservableCollection directly, since it implements INotifyPropertyChanged.

                                          – Dieter Meemken
                                          Jun 3 '16 at 14:23











                                          6














                                          I used Jack Kenyons answer to implement my own OC, but I'd like to point out one change i had to make to make it work. Instead of:



                                              if (e.Action == NotifyCollectionChangedAction.Remove)
                                          {
                                          foreach(T item in e.NewItems)
                                          {
                                          //Removed items
                                          item.PropertyChanged -= EntityViewModelPropertyChanged;
                                          }
                                          }


                                          I used this:



                                              if (e.Action == NotifyCollectionChangedAction.Remove)
                                          {
                                          foreach(T item in e.OldItems)
                                          {
                                          //Removed items
                                          item.PropertyChanged -= EntityViewModelPropertyChanged;
                                          }
                                          }


                                          It seems that the "e.NewItems" produces null if action is .Remove.






                                          share|improve this answer
























                                          • I think it needs further changes as well what if e.Action == replace

                                            – jk.
                                            Jul 29 '11 at 15:53
















                                          6














                                          I used Jack Kenyons answer to implement my own OC, but I'd like to point out one change i had to make to make it work. Instead of:



                                              if (e.Action == NotifyCollectionChangedAction.Remove)
                                          {
                                          foreach(T item in e.NewItems)
                                          {
                                          //Removed items
                                          item.PropertyChanged -= EntityViewModelPropertyChanged;
                                          }
                                          }


                                          I used this:



                                              if (e.Action == NotifyCollectionChangedAction.Remove)
                                          {
                                          foreach(T item in e.OldItems)
                                          {
                                          //Removed items
                                          item.PropertyChanged -= EntityViewModelPropertyChanged;
                                          }
                                          }


                                          It seems that the "e.NewItems" produces null if action is .Remove.






                                          share|improve this answer
























                                          • I think it needs further changes as well what if e.Action == replace

                                            – jk.
                                            Jul 29 '11 at 15:53














                                          6












                                          6








                                          6







                                          I used Jack Kenyons answer to implement my own OC, but I'd like to point out one change i had to make to make it work. Instead of:



                                              if (e.Action == NotifyCollectionChangedAction.Remove)
                                          {
                                          foreach(T item in e.NewItems)
                                          {
                                          //Removed items
                                          item.PropertyChanged -= EntityViewModelPropertyChanged;
                                          }
                                          }


                                          I used this:



                                              if (e.Action == NotifyCollectionChangedAction.Remove)
                                          {
                                          foreach(T item in e.OldItems)
                                          {
                                          //Removed items
                                          item.PropertyChanged -= EntityViewModelPropertyChanged;
                                          }
                                          }


                                          It seems that the "e.NewItems" produces null if action is .Remove.






                                          share|improve this answer













                                          I used Jack Kenyons answer to implement my own OC, but I'd like to point out one change i had to make to make it work. Instead of:



                                              if (e.Action == NotifyCollectionChangedAction.Remove)
                                          {
                                          foreach(T item in e.NewItems)
                                          {
                                          //Removed items
                                          item.PropertyChanged -= EntityViewModelPropertyChanged;
                                          }
                                          }


                                          I used this:



                                              if (e.Action == NotifyCollectionChangedAction.Remove)
                                          {
                                          foreach(T item in e.OldItems)
                                          {
                                          //Removed items
                                          item.PropertyChanged -= EntityViewModelPropertyChanged;
                                          }
                                          }


                                          It seems that the "e.NewItems" produces null if action is .Remove.







                                          share|improve this answer












                                          share|improve this answer



                                          share|improve this answer










                                          answered Jan 12 '11 at 23:35









                                          triazotantriazotan

                                          1,82712232




                                          1,82712232













                                          • I think it needs further changes as well what if e.Action == replace

                                            – jk.
                                            Jul 29 '11 at 15:53



















                                          • I think it needs further changes as well what if e.Action == replace

                                            – jk.
                                            Jul 29 '11 at 15:53

















                                          I think it needs further changes as well what if e.Action == replace

                                          – jk.
                                          Jul 29 '11 at 15:53





                                          I think it needs further changes as well what if e.Action == replace

                                          – jk.
                                          Jul 29 '11 at 15:53











                                          6














                                          Just adding my 2 cents on this topic. Felt the TrulyObservableCollection required the two other constructors as found with ObservableCollection:



                                          public TrulyObservableCollection()
                                          : base()
                                          {
                                          HookupCollectionChangedEvent();
                                          }

                                          public TrulyObservableCollection(IEnumerable<T> collection)
                                          : base(collection)
                                          {
                                          foreach (T item in collection)
                                          item.PropertyChanged += ItemPropertyChanged;

                                          HookupCollectionChangedEvent();
                                          }

                                          public TrulyObservableCollection(List<T> list)
                                          : base(list)
                                          {
                                          list.ForEach(item => item.PropertyChanged += ItemPropertyChanged);

                                          HookupCollectionChangedEvent();
                                          }

                                          private void HookupCollectionChangedEvent()
                                          {
                                          CollectionChanged += new NotifyCollectionChangedEventHandler(TrulyObservableCollectionChanged);
                                          }





                                          share|improve this answer




























                                            6














                                            Just adding my 2 cents on this topic. Felt the TrulyObservableCollection required the two other constructors as found with ObservableCollection:



                                            public TrulyObservableCollection()
                                            : base()
                                            {
                                            HookupCollectionChangedEvent();
                                            }

                                            public TrulyObservableCollection(IEnumerable<T> collection)
                                            : base(collection)
                                            {
                                            foreach (T item in collection)
                                            item.PropertyChanged += ItemPropertyChanged;

                                            HookupCollectionChangedEvent();
                                            }

                                            public TrulyObservableCollection(List<T> list)
                                            : base(list)
                                            {
                                            list.ForEach(item => item.PropertyChanged += ItemPropertyChanged);

                                            HookupCollectionChangedEvent();
                                            }

                                            private void HookupCollectionChangedEvent()
                                            {
                                            CollectionChanged += new NotifyCollectionChangedEventHandler(TrulyObservableCollectionChanged);
                                            }





                                            share|improve this answer


























                                              6












                                              6








                                              6







                                              Just adding my 2 cents on this topic. Felt the TrulyObservableCollection required the two other constructors as found with ObservableCollection:



                                              public TrulyObservableCollection()
                                              : base()
                                              {
                                              HookupCollectionChangedEvent();
                                              }

                                              public TrulyObservableCollection(IEnumerable<T> collection)
                                              : base(collection)
                                              {
                                              foreach (T item in collection)
                                              item.PropertyChanged += ItemPropertyChanged;

                                              HookupCollectionChangedEvent();
                                              }

                                              public TrulyObservableCollection(List<T> list)
                                              : base(list)
                                              {
                                              list.ForEach(item => item.PropertyChanged += ItemPropertyChanged);

                                              HookupCollectionChangedEvent();
                                              }

                                              private void HookupCollectionChangedEvent()
                                              {
                                              CollectionChanged += new NotifyCollectionChangedEventHandler(TrulyObservableCollectionChanged);
                                              }





                                              share|improve this answer













                                              Just adding my 2 cents on this topic. Felt the TrulyObservableCollection required the two other constructors as found with ObservableCollection:



                                              public TrulyObservableCollection()
                                              : base()
                                              {
                                              HookupCollectionChangedEvent();
                                              }

                                              public TrulyObservableCollection(IEnumerable<T> collection)
                                              : base(collection)
                                              {
                                              foreach (T item in collection)
                                              item.PropertyChanged += ItemPropertyChanged;

                                              HookupCollectionChangedEvent();
                                              }

                                              public TrulyObservableCollection(List<T> list)
                                              : base(list)
                                              {
                                              list.ForEach(item => item.PropertyChanged += ItemPropertyChanged);

                                              HookupCollectionChangedEvent();
                                              }

                                              private void HookupCollectionChangedEvent()
                                              {
                                              CollectionChanged += new NotifyCollectionChangedEventHandler(TrulyObservableCollectionChanged);
                                              }






                                              share|improve this answer












                                              share|improve this answer



                                              share|improve this answer










                                              answered Aug 2 '13 at 9:36









                                              pjdupreezpjdupreez

                                              4841614




                                              4841614























                                                  5














                                                  I know that I'm too late for this party, but maybe - it will help to someone..



                                                  Here you can find my implementation of ObservableCollectionEx. It has some features:




                                                  • it supports everything from ObservableCollection

                                                  • it's thread safe

                                                  • it supports ItemPropertyChanged event (it raises each time when Item.PropertyChanged item is fired)

                                                  • it supports filters (so, you could create ObservableCollectionEx, pass another collection as Source to it, and Filter with simple predicate. Very useful in WPF, I use this feature a lot in my applications). Even more - filter tracks changes of items via INotifyPropertyChanged interface.


                                                  Of course, any comments are appreciated ;)






                                                  share|improve this answer



















                                                  • 1





                                                    Большое спасибо! Many thanks for sharing that! You saved me numerous hours by not having to write my own implementation! :)

                                                    – Alexander
                                                    Jul 7 '13 at 6:23













                                                  • @Alexander you're very wellcome :)

                                                    – chopikadze
                                                    Jul 7 '13 at 12:02













                                                  • @chopikadze, i am unable to download the cs file of your ObservableCollectionEx can you kindly fix it. Thanks

                                                    – Shax
                                                    Jan 11 '17 at 8:06











                                                  • The link is dead.

                                                    – user2655904
                                                    Jul 31 '17 at 5:39
















                                                  5














                                                  I know that I'm too late for this party, but maybe - it will help to someone..



                                                  Here you can find my implementation of ObservableCollectionEx. It has some features:




                                                  • it supports everything from ObservableCollection

                                                  • it's thread safe

                                                  • it supports ItemPropertyChanged event (it raises each time when Item.PropertyChanged item is fired)

                                                  • it supports filters (so, you could create ObservableCollectionEx, pass another collection as Source to it, and Filter with simple predicate. Very useful in WPF, I use this feature a lot in my applications). Even more - filter tracks changes of items via INotifyPropertyChanged interface.


                                                  Of course, any comments are appreciated ;)






                                                  share|improve this answer



















                                                  • 1





                                                    Большое спасибо! Many thanks for sharing that! You saved me numerous hours by not having to write my own implementation! :)

                                                    – Alexander
                                                    Jul 7 '13 at 6:23













                                                  • @Alexander you're very wellcome :)

                                                    – chopikadze
                                                    Jul 7 '13 at 12:02













                                                  • @chopikadze, i am unable to download the cs file of your ObservableCollectionEx can you kindly fix it. Thanks

                                                    – Shax
                                                    Jan 11 '17 at 8:06











                                                  • The link is dead.

                                                    – user2655904
                                                    Jul 31 '17 at 5:39














                                                  5












                                                  5








                                                  5







                                                  I know that I'm too late for this party, but maybe - it will help to someone..



                                                  Here you can find my implementation of ObservableCollectionEx. It has some features:




                                                  • it supports everything from ObservableCollection

                                                  • it's thread safe

                                                  • it supports ItemPropertyChanged event (it raises each time when Item.PropertyChanged item is fired)

                                                  • it supports filters (so, you could create ObservableCollectionEx, pass another collection as Source to it, and Filter with simple predicate. Very useful in WPF, I use this feature a lot in my applications). Even more - filter tracks changes of items via INotifyPropertyChanged interface.


                                                  Of course, any comments are appreciated ;)






                                                  share|improve this answer













                                                  I know that I'm too late for this party, but maybe - it will help to someone..



                                                  Here you can find my implementation of ObservableCollectionEx. It has some features:




                                                  • it supports everything from ObservableCollection

                                                  • it's thread safe

                                                  • it supports ItemPropertyChanged event (it raises each time when Item.PropertyChanged item is fired)

                                                  • it supports filters (so, you could create ObservableCollectionEx, pass another collection as Source to it, and Filter with simple predicate. Very useful in WPF, I use this feature a lot in my applications). Even more - filter tracks changes of items via INotifyPropertyChanged interface.


                                                  Of course, any comments are appreciated ;)







                                                  share|improve this answer












                                                  share|improve this answer



                                                  share|improve this answer










                                                  answered Apr 27 '13 at 10:20









                                                  chopikadzechopikadze

                                                  3,5311827




                                                  3,5311827








                                                  • 1





                                                    Большое спасибо! Many thanks for sharing that! You saved me numerous hours by not having to write my own implementation! :)

                                                    – Alexander
                                                    Jul 7 '13 at 6:23













                                                  • @Alexander you're very wellcome :)

                                                    – chopikadze
                                                    Jul 7 '13 at 12:02













                                                  • @chopikadze, i am unable to download the cs file of your ObservableCollectionEx can you kindly fix it. Thanks

                                                    – Shax
                                                    Jan 11 '17 at 8:06











                                                  • The link is dead.

                                                    – user2655904
                                                    Jul 31 '17 at 5:39














                                                  • 1





                                                    Большое спасибо! Many thanks for sharing that! You saved me numerous hours by not having to write my own implementation! :)

                                                    – Alexander
                                                    Jul 7 '13 at 6:23













                                                  • @Alexander you're very wellcome :)

                                                    – chopikadze
                                                    Jul 7 '13 at 12:02













                                                  • @chopikadze, i am unable to download the cs file of your ObservableCollectionEx can you kindly fix it. Thanks

                                                    – Shax
                                                    Jan 11 '17 at 8:06











                                                  • The link is dead.

                                                    – user2655904
                                                    Jul 31 '17 at 5:39








                                                  1




                                                  1





                                                  Большое спасибо! Many thanks for sharing that! You saved me numerous hours by not having to write my own implementation! :)

                                                  – Alexander
                                                  Jul 7 '13 at 6:23







                                                  Большое спасибо! Many thanks for sharing that! You saved me numerous hours by not having to write my own implementation! :)

                                                  – Alexander
                                                  Jul 7 '13 at 6:23















                                                  @Alexander you're very wellcome :)

                                                  – chopikadze
                                                  Jul 7 '13 at 12:02







                                                  @Alexander you're very wellcome :)

                                                  – chopikadze
                                                  Jul 7 '13 at 12:02















                                                  @chopikadze, i am unable to download the cs file of your ObservableCollectionEx can you kindly fix it. Thanks

                                                  – Shax
                                                  Jan 11 '17 at 8:06





                                                  @chopikadze, i am unable to download the cs file of your ObservableCollectionEx can you kindly fix it. Thanks

                                                  – Shax
                                                  Jan 11 '17 at 8:06













                                                  The link is dead.

                                                  – user2655904
                                                  Jul 31 '17 at 5:39





                                                  The link is dead.

                                                  – user2655904
                                                  Jul 31 '17 at 5:39











                                                  1














                                                  Simple solution for standard observablecollection that I've used:



                                                  DO NOT ADD to your property OR CHANGE it's inner items DIRECTLY, instead, create some temp collection like this



                                                  ObservableCollection<EntityViewModel> tmpList= new ObservableCollection<EntityViewModel>();


                                                  and add items or make changes to tmpList,



                                                  tmpList.Add(new EntityViewModel(){IsRowChecked=false}); //Example
                                                  tmpList[0].IsRowChecked= true; //Example
                                                  ...


                                                  then pass it to your actual property by assignment.



                                                  ContentList=tmpList;


                                                  this will change whole property which causes notice the INotifyPropertyChanged as you need.






                                                  share|improve this answer






























                                                    1














                                                    Simple solution for standard observablecollection that I've used:



                                                    DO NOT ADD to your property OR CHANGE it's inner items DIRECTLY, instead, create some temp collection like this



                                                    ObservableCollection<EntityViewModel> tmpList= new ObservableCollection<EntityViewModel>();


                                                    and add items or make changes to tmpList,



                                                    tmpList.Add(new EntityViewModel(){IsRowChecked=false}); //Example
                                                    tmpList[0].IsRowChecked= true; //Example
                                                    ...


                                                    then pass it to your actual property by assignment.



                                                    ContentList=tmpList;


                                                    this will change whole property which causes notice the INotifyPropertyChanged as you need.






                                                    share|improve this answer




























                                                      1












                                                      1








                                                      1







                                                      Simple solution for standard observablecollection that I've used:



                                                      DO NOT ADD to your property OR CHANGE it's inner items DIRECTLY, instead, create some temp collection like this



                                                      ObservableCollection<EntityViewModel> tmpList= new ObservableCollection<EntityViewModel>();


                                                      and add items or make changes to tmpList,



                                                      tmpList.Add(new EntityViewModel(){IsRowChecked=false}); //Example
                                                      tmpList[0].IsRowChecked= true; //Example
                                                      ...


                                                      then pass it to your actual property by assignment.



                                                      ContentList=tmpList;


                                                      this will change whole property which causes notice the INotifyPropertyChanged as you need.






                                                      share|improve this answer















                                                      Simple solution for standard observablecollection that I've used:



                                                      DO NOT ADD to your property OR CHANGE it's inner items DIRECTLY, instead, create some temp collection like this



                                                      ObservableCollection<EntityViewModel> tmpList= new ObservableCollection<EntityViewModel>();


                                                      and add items or make changes to tmpList,



                                                      tmpList.Add(new EntityViewModel(){IsRowChecked=false}); //Example
                                                      tmpList[0].IsRowChecked= true; //Example
                                                      ...


                                                      then pass it to your actual property by assignment.



                                                      ContentList=tmpList;


                                                      this will change whole property which causes notice the INotifyPropertyChanged as you need.







                                                      share|improve this answer














                                                      share|improve this answer



                                                      share|improve this answer








                                                      edited Mar 15 '14 at 10:24

























                                                      answered Mar 15 '14 at 10:17









                                                      thinksomidthinksomid

                                                      193




                                                      193























                                                          1














                                                          I try this solution, but only works for me like a RaisePropertyChange("SourceGroupeGridView") when collection changed, that fired for each item add or changed.



                                                          The problem is in:



                                                          public void EntityViewModelPropertyChanged(object sender, PropertyChangedEventArgs e)
                                                          {
                                                          NotifyCollectionChangedEventArgs args = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset);
                                                          OnCollectionChanged(args);
                                                          }


                                                          NotifyCollectionChangedAction.Reset this action make a complete rebind of all items in groupedgrid, is equivalent at RaisePropertyChanged. When you use it all groups of gridview refreshed.



                                                          IF you, only want to refresh in UI the group of the new item, you don't use Reset action, you will need simulate a Add action in itemproperty with something like this:



                                                          void item_PropertyChanged(object sender, PropertyChangedEventArgs e)
                                                          {
                                                          var index = this.IndexOf((T)sender);

                                                          this.RemoveAt(index);
                                                          this.Insert(index, (T)sender);

                                                          var a = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, sender);
                                                          OnCollectionChanged(a);
                                                          }


                                                          Sorry by my english, and thanks for the base code :),
                                                          I hope this helps someone ^_^



                                                          Enjoi!!






                                                          share|improve this answer






























                                                            1














                                                            I try this solution, but only works for me like a RaisePropertyChange("SourceGroupeGridView") when collection changed, that fired for each item add or changed.



                                                            The problem is in:



                                                            public void EntityViewModelPropertyChanged(object sender, PropertyChangedEventArgs e)
                                                            {
                                                            NotifyCollectionChangedEventArgs args = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset);
                                                            OnCollectionChanged(args);
                                                            }


                                                            NotifyCollectionChangedAction.Reset this action make a complete rebind of all items in groupedgrid, is equivalent at RaisePropertyChanged. When you use it all groups of gridview refreshed.



                                                            IF you, only want to refresh in UI the group of the new item, you don't use Reset action, you will need simulate a Add action in itemproperty with something like this:



                                                            void item_PropertyChanged(object sender, PropertyChangedEventArgs e)
                                                            {
                                                            var index = this.IndexOf((T)sender);

                                                            this.RemoveAt(index);
                                                            this.Insert(index, (T)sender);

                                                            var a = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, sender);
                                                            OnCollectionChanged(a);
                                                            }


                                                            Sorry by my english, and thanks for the base code :),
                                                            I hope this helps someone ^_^



                                                            Enjoi!!






                                                            share|improve this answer




























                                                              1












                                                              1








                                                              1







                                                              I try this solution, but only works for me like a RaisePropertyChange("SourceGroupeGridView") when collection changed, that fired for each item add or changed.



                                                              The problem is in:



                                                              public void EntityViewModelPropertyChanged(object sender, PropertyChangedEventArgs e)
                                                              {
                                                              NotifyCollectionChangedEventArgs args = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset);
                                                              OnCollectionChanged(args);
                                                              }


                                                              NotifyCollectionChangedAction.Reset this action make a complete rebind of all items in groupedgrid, is equivalent at RaisePropertyChanged. When you use it all groups of gridview refreshed.



                                                              IF you, only want to refresh in UI the group of the new item, you don't use Reset action, you will need simulate a Add action in itemproperty with something like this:



                                                              void item_PropertyChanged(object sender, PropertyChangedEventArgs e)
                                                              {
                                                              var index = this.IndexOf((T)sender);

                                                              this.RemoveAt(index);
                                                              this.Insert(index, (T)sender);

                                                              var a = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, sender);
                                                              OnCollectionChanged(a);
                                                              }


                                                              Sorry by my english, and thanks for the base code :),
                                                              I hope this helps someone ^_^



                                                              Enjoi!!






                                                              share|improve this answer















                                                              I try this solution, but only works for me like a RaisePropertyChange("SourceGroupeGridView") when collection changed, that fired for each item add or changed.



                                                              The problem is in:



                                                              public void EntityViewModelPropertyChanged(object sender, PropertyChangedEventArgs e)
                                                              {
                                                              NotifyCollectionChangedEventArgs args = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset);
                                                              OnCollectionChanged(args);
                                                              }


                                                              NotifyCollectionChangedAction.Reset this action make a complete rebind of all items in groupedgrid, is equivalent at RaisePropertyChanged. When you use it all groups of gridview refreshed.



                                                              IF you, only want to refresh in UI the group of the new item, you don't use Reset action, you will need simulate a Add action in itemproperty with something like this:



                                                              void item_PropertyChanged(object sender, PropertyChangedEventArgs e)
                                                              {
                                                              var index = this.IndexOf((T)sender);

                                                              this.RemoveAt(index);
                                                              this.Insert(index, (T)sender);

                                                              var a = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, sender);
                                                              OnCollectionChanged(a);
                                                              }


                                                              Sorry by my english, and thanks for the base code :),
                                                              I hope this helps someone ^_^



                                                              Enjoi!!







                                                              share|improve this answer














                                                              share|improve this answer



                                                              share|improve this answer








                                                              edited May 31 '17 at 8:59









                                                              slavoo

                                                              3,978122936




                                                              3,978122936










                                                              answered Sep 18 '14 at 11:06









                                                              alberto sainzalberto sainz

                                                              111




                                                              111























                                                                  1














                                                                  Here's an extension method for the above solution...



                                                                  public static TrulyObservableCollection<T> ToTrulyObservableCollection<T>(this List<T> list)
                                                                  where T : INotifyPropertyChanged
                                                                  {
                                                                  var newList = new TrulyObservableCollection<T>();

                                                                  if (list != null)
                                                                  {
                                                                  list.ForEach(o => newList.Add(o));
                                                                  }

                                                                  return newList;
                                                                  }





                                                                  share|improve this answer


























                                                                  • You may want to explain the answer

                                                                    – geedubb
                                                                    Oct 23 '18 at 15:43






                                                                  • 1





                                                                    Here's a link that describes extension methods. docs.microsoft.com/en-us/dotnet/csharp/programming-guide/…

                                                                    – LawMan
                                                                    Oct 23 '18 at 19:18


















                                                                  1














                                                                  Here's an extension method for the above solution...



                                                                  public static TrulyObservableCollection<T> ToTrulyObservableCollection<T>(this List<T> list)
                                                                  where T : INotifyPropertyChanged
                                                                  {
                                                                  var newList = new TrulyObservableCollection<T>();

                                                                  if (list != null)
                                                                  {
                                                                  list.ForEach(o => newList.Add(o));
                                                                  }

                                                                  return newList;
                                                                  }





                                                                  share|improve this answer


























                                                                  • You may want to explain the answer

                                                                    – geedubb
                                                                    Oct 23 '18 at 15:43






                                                                  • 1





                                                                    Here's a link that describes extension methods. docs.microsoft.com/en-us/dotnet/csharp/programming-guide/…

                                                                    – LawMan
                                                                    Oct 23 '18 at 19:18
















                                                                  1












                                                                  1








                                                                  1







                                                                  Here's an extension method for the above solution...



                                                                  public static TrulyObservableCollection<T> ToTrulyObservableCollection<T>(this List<T> list)
                                                                  where T : INotifyPropertyChanged
                                                                  {
                                                                  var newList = new TrulyObservableCollection<T>();

                                                                  if (list != null)
                                                                  {
                                                                  list.ForEach(o => newList.Add(o));
                                                                  }

                                                                  return newList;
                                                                  }





                                                                  share|improve this answer















                                                                  Here's an extension method for the above solution...



                                                                  public static TrulyObservableCollection<T> ToTrulyObservableCollection<T>(this List<T> list)
                                                                  where T : INotifyPropertyChanged
                                                                  {
                                                                  var newList = new TrulyObservableCollection<T>();

                                                                  if (list != null)
                                                                  {
                                                                  list.ForEach(o => newList.Add(o));
                                                                  }

                                                                  return newList;
                                                                  }






                                                                  share|improve this answer














                                                                  share|improve this answer



                                                                  share|improve this answer








                                                                  edited May 31 '17 at 9:00









                                                                  slavoo

                                                                  3,978122936




                                                                  3,978122936










                                                                  answered Aug 7 '14 at 13:32









                                                                  LawManLawMan

                                                                  2,5002123




                                                                  2,5002123













                                                                  • You may want to explain the answer

                                                                    – geedubb
                                                                    Oct 23 '18 at 15:43






                                                                  • 1





                                                                    Here's a link that describes extension methods. docs.microsoft.com/en-us/dotnet/csharp/programming-guide/…

                                                                    – LawMan
                                                                    Oct 23 '18 at 19:18





















                                                                  • You may want to explain the answer

                                                                    – geedubb
                                                                    Oct 23 '18 at 15:43






                                                                  • 1





                                                                    Here's a link that describes extension methods. docs.microsoft.com/en-us/dotnet/csharp/programming-guide/…

                                                                    – LawMan
                                                                    Oct 23 '18 at 19:18



















                                                                  You may want to explain the answer

                                                                  – geedubb
                                                                  Oct 23 '18 at 15:43





                                                                  You may want to explain the answer

                                                                  – geedubb
                                                                  Oct 23 '18 at 15:43




                                                                  1




                                                                  1





                                                                  Here's a link that describes extension methods. docs.microsoft.com/en-us/dotnet/csharp/programming-guide/…

                                                                  – LawMan
                                                                  Oct 23 '18 at 19:18







                                                                  Here's a link that describes extension methods. docs.microsoft.com/en-us/dotnet/csharp/programming-guide/…

                                                                  – LawMan
                                                                  Oct 23 '18 at 19:18













                                                                  1














                                                                  Instead of an ObservableCollection or TrulyObservableCollection, consider using a BindingList and calling the ResetBindings method.



                                                                  For example:



                                                                  private BindingList<TfsFile> _tfsFiles;

                                                                  public BindingList<TfsFile> TfsFiles
                                                                  {
                                                                  get { return _tfsFiles; }
                                                                  set
                                                                  {
                                                                  _tfsFiles = value;
                                                                  NotifyPropertyChanged();
                                                                  }
                                                                  }


                                                                  Given an event, such as a click your code would look like this:



                                                                  foreach (var file in TfsFiles)
                                                                  {
                                                                  SelectedFile = file;
                                                                  file.Name = "Different Text";
                                                                  TfsFiles.ResetBindings();
                                                                  }


                                                                  My model looked like this:



                                                                  namespace Models
                                                                  {
                                                                  public class TfsFile
                                                                  {
                                                                  public string ImagePath { get; set; }

                                                                  public string FullPath { get; set; }

                                                                  public string Name { get; set; }

                                                                  public string Text { get; set; }

                                                                  }
                                                                  }





                                                                  share|improve this answer





















                                                                  • 1





                                                                    Good info on this method of BindingList, but there is a limitation to this approach that the other answers overcome: this technique relies on the value being changed in code and where a call to ResetBindings() can be added. Most of the other answers will work if the list's objects are altered through other means, such as unalterable code or from a binding to a second control.

                                                                    – Bob Sammers
                                                                    Mar 2 '17 at 18:44
















                                                                  1














                                                                  Instead of an ObservableCollection or TrulyObservableCollection, consider using a BindingList and calling the ResetBindings method.



                                                                  For example:



                                                                  private BindingList<TfsFile> _tfsFiles;

                                                                  public BindingList<TfsFile> TfsFiles
                                                                  {
                                                                  get { return _tfsFiles; }
                                                                  set
                                                                  {
                                                                  _tfsFiles = value;
                                                                  NotifyPropertyChanged();
                                                                  }
                                                                  }


                                                                  Given an event, such as a click your code would look like this:



                                                                  foreach (var file in TfsFiles)
                                                                  {
                                                                  SelectedFile = file;
                                                                  file.Name = "Different Text";
                                                                  TfsFiles.ResetBindings();
                                                                  }


                                                                  My model looked like this:



                                                                  namespace Models
                                                                  {
                                                                  public class TfsFile
                                                                  {
                                                                  public string ImagePath { get; set; }

                                                                  public string FullPath { get; set; }

                                                                  public string Name { get; set; }

                                                                  public string Text { get; set; }

                                                                  }
                                                                  }





                                                                  share|improve this answer





















                                                                  • 1





                                                                    Good info on this method of BindingList, but there is a limitation to this approach that the other answers overcome: this technique relies on the value being changed in code and where a call to ResetBindings() can be added. Most of the other answers will work if the list's objects are altered through other means, such as unalterable code or from a binding to a second control.

                                                                    – Bob Sammers
                                                                    Mar 2 '17 at 18:44














                                                                  1












                                                                  1








                                                                  1







                                                                  Instead of an ObservableCollection or TrulyObservableCollection, consider using a BindingList and calling the ResetBindings method.



                                                                  For example:



                                                                  private BindingList<TfsFile> _tfsFiles;

                                                                  public BindingList<TfsFile> TfsFiles
                                                                  {
                                                                  get { return _tfsFiles; }
                                                                  set
                                                                  {
                                                                  _tfsFiles = value;
                                                                  NotifyPropertyChanged();
                                                                  }
                                                                  }


                                                                  Given an event, such as a click your code would look like this:



                                                                  foreach (var file in TfsFiles)
                                                                  {
                                                                  SelectedFile = file;
                                                                  file.Name = "Different Text";
                                                                  TfsFiles.ResetBindings();
                                                                  }


                                                                  My model looked like this:



                                                                  namespace Models
                                                                  {
                                                                  public class TfsFile
                                                                  {
                                                                  public string ImagePath { get; set; }

                                                                  public string FullPath { get; set; }

                                                                  public string Name { get; set; }

                                                                  public string Text { get; set; }

                                                                  }
                                                                  }





                                                                  share|improve this answer















                                                                  Instead of an ObservableCollection or TrulyObservableCollection, consider using a BindingList and calling the ResetBindings method.



                                                                  For example:



                                                                  private BindingList<TfsFile> _tfsFiles;

                                                                  public BindingList<TfsFile> TfsFiles
                                                                  {
                                                                  get { return _tfsFiles; }
                                                                  set
                                                                  {
                                                                  _tfsFiles = value;
                                                                  NotifyPropertyChanged();
                                                                  }
                                                                  }


                                                                  Given an event, such as a click your code would look like this:



                                                                  foreach (var file in TfsFiles)
                                                                  {
                                                                  SelectedFile = file;
                                                                  file.Name = "Different Text";
                                                                  TfsFiles.ResetBindings();
                                                                  }


                                                                  My model looked like this:



                                                                  namespace Models
                                                                  {
                                                                  public class TfsFile
                                                                  {
                                                                  public string ImagePath { get; set; }

                                                                  public string FullPath { get; set; }

                                                                  public string Name { get; set; }

                                                                  public string Text { get; set; }

                                                                  }
                                                                  }






                                                                  share|improve this answer














                                                                  share|improve this answer



                                                                  share|improve this answer








                                                                  edited May 31 '17 at 9:01









                                                                  slavoo

                                                                  3,978122936




                                                                  3,978122936










                                                                  answered Jan 12 '17 at 23:33









                                                                  ClubbieTimClubbieTim

                                                                  10712




                                                                  10712








                                                                  • 1





                                                                    Good info on this method of BindingList, but there is a limitation to this approach that the other answers overcome: this technique relies on the value being changed in code and where a call to ResetBindings() can be added. Most of the other answers will work if the list's objects are altered through other means, such as unalterable code or from a binding to a second control.

                                                                    – Bob Sammers
                                                                    Mar 2 '17 at 18:44














                                                                  • 1





                                                                    Good info on this method of BindingList, but there is a limitation to this approach that the other answers overcome: this technique relies on the value being changed in code and where a call to ResetBindings() can be added. Most of the other answers will work if the list's objects are altered through other means, such as unalterable code or from a binding to a second control.

                                                                    – Bob Sammers
                                                                    Mar 2 '17 at 18:44








                                                                  1




                                                                  1





                                                                  Good info on this method of BindingList, but there is a limitation to this approach that the other answers overcome: this technique relies on the value being changed in code and where a call to ResetBindings() can be added. Most of the other answers will work if the list's objects are altered through other means, such as unalterable code or from a binding to a second control.

                                                                  – Bob Sammers
                                                                  Mar 2 '17 at 18:44





                                                                  Good info on this method of BindingList, but there is a limitation to this approach that the other answers overcome: this technique relies on the value being changed in code and where a call to ResetBindings() can be added. Most of the other answers will work if the list's objects are altered through other means, such as unalterable code or from a binding to a second control.

                                                                  – Bob Sammers
                                                                  Mar 2 '17 at 18:44











                                                                  1














                                                                  If i know ObservableCollection make event only when we add/delete or move items in our collection. When we simly update some properties in collection items collection don`t signalize about it and UI will not be updated.



                                                                  You can simly implement INotifyPropertyChange in your Model class.
                                                                  And than when we update some propery in collection item it automatically will update UI.



                                                                  public class Model:INotifyPropertyChange
                                                                  {
                                                                  //...
                                                                  }


                                                                  and than



                                                                  public ObservableCollection<Model> {get; set;}


                                                                  In my case i used ListView to Bind for this collection and in ItemTemplate set Binding to Model property and it work good.



                                                                  Here is some snippet



                                                                  Windows XAML :



                                                                  <Window.DataContext>
                                                                  <local:ViewModel/>
                                                                  </Window.DataContext>
                                                                  <Grid>
                                                                  <Grid.RowDefinitions>
                                                                  <RowDefinition/>
                                                                  <RowDefinition/>
                                                                  </Grid.RowDefinitions>
                                                                  <ListView
                                                                  Margin="10"
                                                                  BorderBrush="Black"
                                                                  HorizontalAlignment="Center"
                                                                  SelectedItem="{Binding SelectedPerson}"
                                                                  ItemsSource="{Binding Persons}">
                                                                  <ListView.ItemTemplate>
                                                                  <DataTemplate>
                                                                  <StackPanel Orientation="Horizontal">
                                                                  <Label Content="{Binding Name}"/>
                                                                  <Label Content="-"/>
                                                                  <Label Content="{Binding Age}"/>
                                                                  </StackPanel>
                                                                  </DataTemplate>
                                                                  </ListView.ItemTemplate>
                                                                  </ListView>
                                                                  <Grid
                                                                  Grid.Row="1"
                                                                  VerticalAlignment="Center"
                                                                  HorizontalAlignment="Center">
                                                                  <Grid.ColumnDefinitions>
                                                                  <ColumnDefinition/>
                                                                  <ColumnDefinition/>
                                                                  </Grid.ColumnDefinitions>
                                                                  <Grid.RowDefinitions>
                                                                  <RowDefinition/>
                                                                  <RowDefinition/>
                                                                  <RowDefinition/>
                                                                  </Grid.RowDefinitions>
                                                                  <Label
                                                                  VerticalAlignment="Center"
                                                                  Content="Name:"/>
                                                                  <TextBox
                                                                  Text="{Binding SelectedPerson.Name,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
                                                                  Margin="10"
                                                                  Grid.Column="1"
                                                                  Width="100"/>
                                                                  <Label
                                                                  VerticalAlignment="Center"
                                                                  Grid.Row="1"
                                                                  Content="Age:"/>
                                                                  <TextBox
                                                                  Text="{Binding SelectedPerson.Age,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
                                                                  Margin="10"
                                                                  Grid.Row="1"
                                                                  Grid.Column="1"
                                                                  Width="100"/>


                                                                  </Grid>
                                                                  </Grid>


                                                                  Model code example:



                                                                  public class PersonModel:INotifyPropertyChanged
                                                                  {
                                                                  public string Name
                                                                  {
                                                                  get => _name;
                                                                  set
                                                                  {
                                                                  _name = value;
                                                                  OnPropertyChanged();
                                                                  }
                                                                  }

                                                                  public int Age
                                                                  {
                                                                  get => _age;
                                                                  set
                                                                  {
                                                                  _age = value;
                                                                  OnPropertyChanged();
                                                                  }
                                                                  }

                                                                  private string _name;
                                                                  private int _age;
                                                                  //INotifyPropertyChanged implementation
                                                                  public event PropertyChangedEventHandler PropertyChanged;
                                                                  protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
                                                                  {
                                                                  PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
                                                                  }
                                                                  }


                                                                  And ViewModel implementation:



                                                                   public class ViewModel:INotifyPropertyChanged
                                                                  {
                                                                  public ViewModel()
                                                                  {
                                                                  Persons = new ObservableCollection<PersonModel>
                                                                  {
                                                                  new PersonModel
                                                                  {
                                                                  Name = "Jack",
                                                                  Age = 30
                                                                  },
                                                                  new PersonModel
                                                                  {
                                                                  Name = "Jon",
                                                                  Age = 23
                                                                  },
                                                                  new PersonModel
                                                                  {
                                                                  Name = "Max",
                                                                  Age = 23
                                                                  },
                                                                  };
                                                                  }

                                                                  public ObservableCollection<PersonModel> Persons { get;}

                                                                  public PersonModel SelectedPerson
                                                                  {
                                                                  get => _selectedPerson;
                                                                  set
                                                                  {
                                                                  _selectedPerson = value;
                                                                  OnPropertyChanged();
                                                                  }
                                                                  }

                                                                  //INotifyPropertyChanged Implementation
                                                                  public event PropertyChangedEventHandler PropertyChanged;
                                                                  protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
                                                                  {
                                                                  PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
                                                                  }

                                                                  private PersonModel _selectedPerson;
                                                                  }





                                                                  share|improve this answer






























                                                                    1














                                                                    If i know ObservableCollection make event only when we add/delete or move items in our collection. When we simly update some properties in collection items collection don`t signalize about it and UI will not be updated.



                                                                    You can simly implement INotifyPropertyChange in your Model class.
                                                                    And than when we update some propery in collection item it automatically will update UI.



                                                                    public class Model:INotifyPropertyChange
                                                                    {
                                                                    //...
                                                                    }


                                                                    and than



                                                                    public ObservableCollection<Model> {get; set;}


                                                                    In my case i used ListView to Bind for this collection and in ItemTemplate set Binding to Model property and it work good.



                                                                    Here is some snippet



                                                                    Windows XAML :



                                                                    <Window.DataContext>
                                                                    <local:ViewModel/>
                                                                    </Window.DataContext>
                                                                    <Grid>
                                                                    <Grid.RowDefinitions>
                                                                    <RowDefinition/>
                                                                    <RowDefinition/>
                                                                    </Grid.RowDefinitions>
                                                                    <ListView
                                                                    Margin="10"
                                                                    BorderBrush="Black"
                                                                    HorizontalAlignment="Center"
                                                                    SelectedItem="{Binding SelectedPerson}"
                                                                    ItemsSource="{Binding Persons}">
                                                                    <ListView.ItemTemplate>
                                                                    <DataTemplate>
                                                                    <StackPanel Orientation="Horizontal">
                                                                    <Label Content="{Binding Name}"/>
                                                                    <Label Content="-"/>
                                                                    <Label Content="{Binding Age}"/>
                                                                    </StackPanel>
                                                                    </DataTemplate>
                                                                    </ListView.ItemTemplate>
                                                                    </ListView>
                                                                    <Grid
                                                                    Grid.Row="1"
                                                                    VerticalAlignment="Center"
                                                                    HorizontalAlignment="Center">
                                                                    <Grid.ColumnDefinitions>
                                                                    <ColumnDefinition/>
                                                                    <ColumnDefinition/>
                                                                    </Grid.ColumnDefinitions>
                                                                    <Grid.RowDefinitions>
                                                                    <RowDefinition/>
                                                                    <RowDefinition/>
                                                                    <RowDefinition/>
                                                                    </Grid.RowDefinitions>
                                                                    <Label
                                                                    VerticalAlignment="Center"
                                                                    Content="Name:"/>
                                                                    <TextBox
                                                                    Text="{Binding SelectedPerson.Name,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
                                                                    Margin="10"
                                                                    Grid.Column="1"
                                                                    Width="100"/>
                                                                    <Label
                                                                    VerticalAlignment="Center"
                                                                    Grid.Row="1"
                                                                    Content="Age:"/>
                                                                    <TextBox
                                                                    Text="{Binding SelectedPerson.Age,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
                                                                    Margin="10"
                                                                    Grid.Row="1"
                                                                    Grid.Column="1"
                                                                    Width="100"/>


                                                                    </Grid>
                                                                    </Grid>


                                                                    Model code example:



                                                                    public class PersonModel:INotifyPropertyChanged
                                                                    {
                                                                    public string Name
                                                                    {
                                                                    get => _name;
                                                                    set
                                                                    {
                                                                    _name = value;
                                                                    OnPropertyChanged();
                                                                    }
                                                                    }

                                                                    public int Age
                                                                    {
                                                                    get => _age;
                                                                    set
                                                                    {
                                                                    _age = value;
                                                                    OnPropertyChanged();
                                                                    }
                                                                    }

                                                                    private string _name;
                                                                    private int _age;
                                                                    //INotifyPropertyChanged implementation
                                                                    public event PropertyChangedEventHandler PropertyChanged;
                                                                    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
                                                                    {
                                                                    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
                                                                    }
                                                                    }


                                                                    And ViewModel implementation:



                                                                     public class ViewModel:INotifyPropertyChanged
                                                                    {
                                                                    public ViewModel()
                                                                    {
                                                                    Persons = new ObservableCollection<PersonModel>
                                                                    {
                                                                    new PersonModel
                                                                    {
                                                                    Name = "Jack",
                                                                    Age = 30
                                                                    },
                                                                    new PersonModel
                                                                    {
                                                                    Name = "Jon",
                                                                    Age = 23
                                                                    },
                                                                    new PersonModel
                                                                    {
                                                                    Name = "Max",
                                                                    Age = 23
                                                                    },
                                                                    };
                                                                    }

                                                                    public ObservableCollection<PersonModel> Persons { get;}

                                                                    public PersonModel SelectedPerson
                                                                    {
                                                                    get => _selectedPerson;
                                                                    set
                                                                    {
                                                                    _selectedPerson = value;
                                                                    OnPropertyChanged();
                                                                    }
                                                                    }

                                                                    //INotifyPropertyChanged Implementation
                                                                    public event PropertyChangedEventHandler PropertyChanged;
                                                                    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
                                                                    {
                                                                    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
                                                                    }

                                                                    private PersonModel _selectedPerson;
                                                                    }





                                                                    share|improve this answer




























                                                                      1












                                                                      1








                                                                      1







                                                                      If i know ObservableCollection make event only when we add/delete or move items in our collection. When we simly update some properties in collection items collection don`t signalize about it and UI will not be updated.



                                                                      You can simly implement INotifyPropertyChange in your Model class.
                                                                      And than when we update some propery in collection item it automatically will update UI.



                                                                      public class Model:INotifyPropertyChange
                                                                      {
                                                                      //...
                                                                      }


                                                                      and than



                                                                      public ObservableCollection<Model> {get; set;}


                                                                      In my case i used ListView to Bind for this collection and in ItemTemplate set Binding to Model property and it work good.



                                                                      Here is some snippet



                                                                      Windows XAML :



                                                                      <Window.DataContext>
                                                                      <local:ViewModel/>
                                                                      </Window.DataContext>
                                                                      <Grid>
                                                                      <Grid.RowDefinitions>
                                                                      <RowDefinition/>
                                                                      <RowDefinition/>
                                                                      </Grid.RowDefinitions>
                                                                      <ListView
                                                                      Margin="10"
                                                                      BorderBrush="Black"
                                                                      HorizontalAlignment="Center"
                                                                      SelectedItem="{Binding SelectedPerson}"
                                                                      ItemsSource="{Binding Persons}">
                                                                      <ListView.ItemTemplate>
                                                                      <DataTemplate>
                                                                      <StackPanel Orientation="Horizontal">
                                                                      <Label Content="{Binding Name}"/>
                                                                      <Label Content="-"/>
                                                                      <Label Content="{Binding Age}"/>
                                                                      </StackPanel>
                                                                      </DataTemplate>
                                                                      </ListView.ItemTemplate>
                                                                      </ListView>
                                                                      <Grid
                                                                      Grid.Row="1"
                                                                      VerticalAlignment="Center"
                                                                      HorizontalAlignment="Center">
                                                                      <Grid.ColumnDefinitions>
                                                                      <ColumnDefinition/>
                                                                      <ColumnDefinition/>
                                                                      </Grid.ColumnDefinitions>
                                                                      <Grid.RowDefinitions>
                                                                      <RowDefinition/>
                                                                      <RowDefinition/>
                                                                      <RowDefinition/>
                                                                      </Grid.RowDefinitions>
                                                                      <Label
                                                                      VerticalAlignment="Center"
                                                                      Content="Name:"/>
                                                                      <TextBox
                                                                      Text="{Binding SelectedPerson.Name,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
                                                                      Margin="10"
                                                                      Grid.Column="1"
                                                                      Width="100"/>
                                                                      <Label
                                                                      VerticalAlignment="Center"
                                                                      Grid.Row="1"
                                                                      Content="Age:"/>
                                                                      <TextBox
                                                                      Text="{Binding SelectedPerson.Age,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
                                                                      Margin="10"
                                                                      Grid.Row="1"
                                                                      Grid.Column="1"
                                                                      Width="100"/>


                                                                      </Grid>
                                                                      </Grid>


                                                                      Model code example:



                                                                      public class PersonModel:INotifyPropertyChanged
                                                                      {
                                                                      public string Name
                                                                      {
                                                                      get => _name;
                                                                      set
                                                                      {
                                                                      _name = value;
                                                                      OnPropertyChanged();
                                                                      }
                                                                      }

                                                                      public int Age
                                                                      {
                                                                      get => _age;
                                                                      set
                                                                      {
                                                                      _age = value;
                                                                      OnPropertyChanged();
                                                                      }
                                                                      }

                                                                      private string _name;
                                                                      private int _age;
                                                                      //INotifyPropertyChanged implementation
                                                                      public event PropertyChangedEventHandler PropertyChanged;
                                                                      protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
                                                                      {
                                                                      PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
                                                                      }
                                                                      }


                                                                      And ViewModel implementation:



                                                                       public class ViewModel:INotifyPropertyChanged
                                                                      {
                                                                      public ViewModel()
                                                                      {
                                                                      Persons = new ObservableCollection<PersonModel>
                                                                      {
                                                                      new PersonModel
                                                                      {
                                                                      Name = "Jack",
                                                                      Age = 30
                                                                      },
                                                                      new PersonModel
                                                                      {
                                                                      Name = "Jon",
                                                                      Age = 23
                                                                      },
                                                                      new PersonModel
                                                                      {
                                                                      Name = "Max",
                                                                      Age = 23
                                                                      },
                                                                      };
                                                                      }

                                                                      public ObservableCollection<PersonModel> Persons { get;}

                                                                      public PersonModel SelectedPerson
                                                                      {
                                                                      get => _selectedPerson;
                                                                      set
                                                                      {
                                                                      _selectedPerson = value;
                                                                      OnPropertyChanged();
                                                                      }
                                                                      }

                                                                      //INotifyPropertyChanged Implementation
                                                                      public event PropertyChangedEventHandler PropertyChanged;
                                                                      protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
                                                                      {
                                                                      PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
                                                                      }

                                                                      private PersonModel _selectedPerson;
                                                                      }





                                                                      share|improve this answer















                                                                      If i know ObservableCollection make event only when we add/delete or move items in our collection. When we simly update some properties in collection items collection don`t signalize about it and UI will not be updated.



                                                                      You can simly implement INotifyPropertyChange in your Model class.
                                                                      And than when we update some propery in collection item it automatically will update UI.



                                                                      public class Model:INotifyPropertyChange
                                                                      {
                                                                      //...
                                                                      }


                                                                      and than



                                                                      public ObservableCollection<Model> {get; set;}


                                                                      In my case i used ListView to Bind for this collection and in ItemTemplate set Binding to Model property and it work good.



                                                                      Here is some snippet



                                                                      Windows XAML :



                                                                      <Window.DataContext>
                                                                      <local:ViewModel/>
                                                                      </Window.DataContext>
                                                                      <Grid>
                                                                      <Grid.RowDefinitions>
                                                                      <RowDefinition/>
                                                                      <RowDefinition/>
                                                                      </Grid.RowDefinitions>
                                                                      <ListView
                                                                      Margin="10"
                                                                      BorderBrush="Black"
                                                                      HorizontalAlignment="Center"
                                                                      SelectedItem="{Binding SelectedPerson}"
                                                                      ItemsSource="{Binding Persons}">
                                                                      <ListView.ItemTemplate>
                                                                      <DataTemplate>
                                                                      <StackPanel Orientation="Horizontal">
                                                                      <Label Content="{Binding Name}"/>
                                                                      <Label Content="-"/>
                                                                      <Label Content="{Binding Age}"/>
                                                                      </StackPanel>
                                                                      </DataTemplate>
                                                                      </ListView.ItemTemplate>
                                                                      </ListView>
                                                                      <Grid
                                                                      Grid.Row="1"
                                                                      VerticalAlignment="Center"
                                                                      HorizontalAlignment="Center">
                                                                      <Grid.ColumnDefinitions>
                                                                      <ColumnDefinition/>
                                                                      <ColumnDefinition/>
                                                                      </Grid.ColumnDefinitions>
                                                                      <Grid.RowDefinitions>
                                                                      <RowDefinition/>
                                                                      <RowDefinition/>
                                                                      <RowDefinition/>
                                                                      </Grid.RowDefinitions>
                                                                      <Label
                                                                      VerticalAlignment="Center"
                                                                      Content="Name:"/>
                                                                      <TextBox
                                                                      Text="{Binding SelectedPerson.Name,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
                                                                      Margin="10"
                                                                      Grid.Column="1"
                                                                      Width="100"/>
                                                                      <Label
                                                                      VerticalAlignment="Center"
                                                                      Grid.Row="1"
                                                                      Content="Age:"/>
                                                                      <TextBox
                                                                      Text="{Binding SelectedPerson.Age,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
                                                                      Margin="10"
                                                                      Grid.Row="1"
                                                                      Grid.Column="1"
                                                                      Width="100"/>


                                                                      </Grid>
                                                                      </Grid>


                                                                      Model code example:



                                                                      public class PersonModel:INotifyPropertyChanged
                                                                      {
                                                                      public string Name
                                                                      {
                                                                      get => _name;
                                                                      set
                                                                      {
                                                                      _name = value;
                                                                      OnPropertyChanged();
                                                                      }
                                                                      }

                                                                      public int Age
                                                                      {
                                                                      get => _age;
                                                                      set
                                                                      {
                                                                      _age = value;
                                                                      OnPropertyChanged();
                                                                      }
                                                                      }

                                                                      private string _name;
                                                                      private int _age;
                                                                      //INotifyPropertyChanged implementation
                                                                      public event PropertyChangedEventHandler PropertyChanged;
                                                                      protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
                                                                      {
                                                                      PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
                                                                      }
                                                                      }


                                                                      And ViewModel implementation:



                                                                       public class ViewModel:INotifyPropertyChanged
                                                                      {
                                                                      public ViewModel()
                                                                      {
                                                                      Persons = new ObservableCollection<PersonModel>
                                                                      {
                                                                      new PersonModel
                                                                      {
                                                                      Name = "Jack",
                                                                      Age = 30
                                                                      },
                                                                      new PersonModel
                                                                      {
                                                                      Name = "Jon",
                                                                      Age = 23
                                                                      },
                                                                      new PersonModel
                                                                      {
                                                                      Name = "Max",
                                                                      Age = 23
                                                                      },
                                                                      };
                                                                      }

                                                                      public ObservableCollection<PersonModel> Persons { get;}

                                                                      public PersonModel SelectedPerson
                                                                      {
                                                                      get => _selectedPerson;
                                                                      set
                                                                      {
                                                                      _selectedPerson = value;
                                                                      OnPropertyChanged();
                                                                      }
                                                                      }

                                                                      //INotifyPropertyChanged Implementation
                                                                      public event PropertyChangedEventHandler PropertyChanged;
                                                                      protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
                                                                      {
                                                                      PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
                                                                      }

                                                                      private PersonModel _selectedPerson;
                                                                      }






                                                                      share|improve this answer














                                                                      share|improve this answer



                                                                      share|improve this answer








                                                                      edited Sep 4 '17 at 16:30

























                                                                      answered Sep 4 '17 at 13:24









                                                                      Sviatoslav KindratSviatoslav Kindrat

                                                                      112




                                                                      112























                                                                          0














                                                                          Here is my version of the implementation. It checks and throws an error, if the objects in list doesnt implement INotifyPropertyChanged, so can't forget that issue while developing. On the outside you use the ListItemChanged Event do determine whether the list or the list item itself has changed.



                                                                          public class SpecialObservableCollection<T> : ObservableCollection<T>
                                                                          {
                                                                          public SpecialObservableCollection()
                                                                          {
                                                                          this.CollectionChanged += OnCollectionChanged;
                                                                          }

                                                                          void OnCollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
                                                                          {
                                                                          AddOrRemoveListToPropertyChanged(e.NewItems,true);
                                                                          AddOrRemoveListToPropertyChanged(e.OldItems,false);
                                                                          }

                                                                          private void AddOrRemoveListToPropertyChanged(IList list, Boolean add)
                                                                          {
                                                                          if (list == null) { return; }
                                                                          foreach (object item in list)
                                                                          {
                                                                          INotifyPropertyChanged o = item as INotifyPropertyChanged;
                                                                          if (o != null)
                                                                          {
                                                                          if (add) { o.PropertyChanged += ListItemPropertyChanged; }
                                                                          if (!add) { o.PropertyChanged -= ListItemPropertyChanged; }
                                                                          }
                                                                          else
                                                                          {
                                                                          throw new Exception("INotifyPropertyChanged is required");
                                                                          }
                                                                          }
                                                                          }

                                                                          void ListItemPropertyChanged(object sender, PropertyChangedEventArgs e)
                                                                          {
                                                                          OnListItemChanged(this, e);
                                                                          }

                                                                          public delegate void ListItemChangedEventHandler(object sender, PropertyChangedEventArgs e);

                                                                          public event ListItemChangedEventHandler ListItemChanged;

                                                                          private void OnListItemChanged(Object sender, PropertyChangedEventArgs e)
                                                                          {
                                                                          if (ListItemChanged != null) { this.ListItemChanged(this, e); }
                                                                          }


                                                                          }





                                                                          share|improve this answer






























                                                                            0














                                                                            Here is my version of the implementation. It checks and throws an error, if the objects in list doesnt implement INotifyPropertyChanged, so can't forget that issue while developing. On the outside you use the ListItemChanged Event do determine whether the list or the list item itself has changed.



                                                                            public class SpecialObservableCollection<T> : ObservableCollection<T>
                                                                            {
                                                                            public SpecialObservableCollection()
                                                                            {
                                                                            this.CollectionChanged += OnCollectionChanged;
                                                                            }

                                                                            void OnCollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
                                                                            {
                                                                            AddOrRemoveListToPropertyChanged(e.NewItems,true);
                                                                            AddOrRemoveListToPropertyChanged(e.OldItems,false);
                                                                            }

                                                                            private void AddOrRemoveListToPropertyChanged(IList list, Boolean add)
                                                                            {
                                                                            if (list == null) { return; }
                                                                            foreach (object item in list)
                                                                            {
                                                                            INotifyPropertyChanged o = item as INotifyPropertyChanged;
                                                                            if (o != null)
                                                                            {
                                                                            if (add) { o.PropertyChanged += ListItemPropertyChanged; }
                                                                            if (!add) { o.PropertyChanged -= ListItemPropertyChanged; }
                                                                            }
                                                                            else
                                                                            {
                                                                            throw new Exception("INotifyPropertyChanged is required");
                                                                            }
                                                                            }
                                                                            }

                                                                            void ListItemPropertyChanged(object sender, PropertyChangedEventArgs e)
                                                                            {
                                                                            OnListItemChanged(this, e);
                                                                            }

                                                                            public delegate void ListItemChangedEventHandler(object sender, PropertyChangedEventArgs e);

                                                                            public event ListItemChangedEventHandler ListItemChanged;

                                                                            private void OnListItemChanged(Object sender, PropertyChangedEventArgs e)
                                                                            {
                                                                            if (ListItemChanged != null) { this.ListItemChanged(this, e); }
                                                                            }


                                                                            }





                                                                            share|improve this answer




























                                                                              0












                                                                              0








                                                                              0







                                                                              Here is my version of the implementation. It checks and throws an error, if the objects in list doesnt implement INotifyPropertyChanged, so can't forget that issue while developing. On the outside you use the ListItemChanged Event do determine whether the list or the list item itself has changed.



                                                                              public class SpecialObservableCollection<T> : ObservableCollection<T>
                                                                              {
                                                                              public SpecialObservableCollection()
                                                                              {
                                                                              this.CollectionChanged += OnCollectionChanged;
                                                                              }

                                                                              void OnCollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
                                                                              {
                                                                              AddOrRemoveListToPropertyChanged(e.NewItems,true);
                                                                              AddOrRemoveListToPropertyChanged(e.OldItems,false);
                                                                              }

                                                                              private void AddOrRemoveListToPropertyChanged(IList list, Boolean add)
                                                                              {
                                                                              if (list == null) { return; }
                                                                              foreach (object item in list)
                                                                              {
                                                                              INotifyPropertyChanged o = item as INotifyPropertyChanged;
                                                                              if (o != null)
                                                                              {
                                                                              if (add) { o.PropertyChanged += ListItemPropertyChanged; }
                                                                              if (!add) { o.PropertyChanged -= ListItemPropertyChanged; }
                                                                              }
                                                                              else
                                                                              {
                                                                              throw new Exception("INotifyPropertyChanged is required");
                                                                              }
                                                                              }
                                                                              }

                                                                              void ListItemPropertyChanged(object sender, PropertyChangedEventArgs e)
                                                                              {
                                                                              OnListItemChanged(this, e);
                                                                              }

                                                                              public delegate void ListItemChangedEventHandler(object sender, PropertyChangedEventArgs e);

                                                                              public event ListItemChangedEventHandler ListItemChanged;

                                                                              private void OnListItemChanged(Object sender, PropertyChangedEventArgs e)
                                                                              {
                                                                              if (ListItemChanged != null) { this.ListItemChanged(this, e); }
                                                                              }


                                                                              }





                                                                              share|improve this answer















                                                                              Here is my version of the implementation. It checks and throws an error, if the objects in list doesnt implement INotifyPropertyChanged, so can't forget that issue while developing. On the outside you use the ListItemChanged Event do determine whether the list or the list item itself has changed.



                                                                              public class SpecialObservableCollection<T> : ObservableCollection<T>
                                                                              {
                                                                              public SpecialObservableCollection()
                                                                              {
                                                                              this.CollectionChanged += OnCollectionChanged;
                                                                              }

                                                                              void OnCollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
                                                                              {
                                                                              AddOrRemoveListToPropertyChanged(e.NewItems,true);
                                                                              AddOrRemoveListToPropertyChanged(e.OldItems,false);
                                                                              }

                                                                              private void AddOrRemoveListToPropertyChanged(IList list, Boolean add)
                                                                              {
                                                                              if (list == null) { return; }
                                                                              foreach (object item in list)
                                                                              {
                                                                              INotifyPropertyChanged o = item as INotifyPropertyChanged;
                                                                              if (o != null)
                                                                              {
                                                                              if (add) { o.PropertyChanged += ListItemPropertyChanged; }
                                                                              if (!add) { o.PropertyChanged -= ListItemPropertyChanged; }
                                                                              }
                                                                              else
                                                                              {
                                                                              throw new Exception("INotifyPropertyChanged is required");
                                                                              }
                                                                              }
                                                                              }

                                                                              void ListItemPropertyChanged(object sender, PropertyChangedEventArgs e)
                                                                              {
                                                                              OnListItemChanged(this, e);
                                                                              }

                                                                              public delegate void ListItemChangedEventHandler(object sender, PropertyChangedEventArgs e);

                                                                              public event ListItemChangedEventHandler ListItemChanged;

                                                                              private void OnListItemChanged(Object sender, PropertyChangedEventArgs e)
                                                                              {
                                                                              if (ListItemChanged != null) { this.ListItemChanged(this, e); }
                                                                              }


                                                                              }






                                                                              share|improve this answer














                                                                              share|improve this answer



                                                                              share|improve this answer








                                                                              edited Apr 16 '15 at 2:31

























                                                                              answered Apr 16 '15 at 2:25









                                                                              MichaelMichael

                                                                              546624




                                                                              546624























                                                                                  0














                                                                                  Simple solution in 2 lines of code. Just use the copy constructor.
                                                                                  No need to write TrulyObservableCollection etc.



                                                                                  Example:



                                                                                          speakers.list[0].Status = "offline";
                                                                                  speakers.list[0] = new Speaker(speakers.list[0]);


                                                                                  Another method without copy constructor. You can use serialization.



                                                                                          speakers.list[0].Status = "offline";
                                                                                  //speakers.list[0] = new Speaker(speakers.list[0]);
                                                                                  var tmp = JsonConvert.SerializeObject(speakers.list[0]);
                                                                                  var tmp2 = JsonConvert.DeserializeObject<Speaker>(tmp);
                                                                                  speakers.list[0] = tmp2;





                                                                                  share|improve this answer






























                                                                                    0














                                                                                    Simple solution in 2 lines of code. Just use the copy constructor.
                                                                                    No need to write TrulyObservableCollection etc.



                                                                                    Example:



                                                                                            speakers.list[0].Status = "offline";
                                                                                    speakers.list[0] = new Speaker(speakers.list[0]);


                                                                                    Another method without copy constructor. You can use serialization.



                                                                                            speakers.list[0].Status = "offline";
                                                                                    //speakers.list[0] = new Speaker(speakers.list[0]);
                                                                                    var tmp = JsonConvert.SerializeObject(speakers.list[0]);
                                                                                    var tmp2 = JsonConvert.DeserializeObject<Speaker>(tmp);
                                                                                    speakers.list[0] = tmp2;





                                                                                    share|improve this answer




























                                                                                      0












                                                                                      0








                                                                                      0







                                                                                      Simple solution in 2 lines of code. Just use the copy constructor.
                                                                                      No need to write TrulyObservableCollection etc.



                                                                                      Example:



                                                                                              speakers.list[0].Status = "offline";
                                                                                      speakers.list[0] = new Speaker(speakers.list[0]);


                                                                                      Another method without copy constructor. You can use serialization.



                                                                                              speakers.list[0].Status = "offline";
                                                                                      //speakers.list[0] = new Speaker(speakers.list[0]);
                                                                                      var tmp = JsonConvert.SerializeObject(speakers.list[0]);
                                                                                      var tmp2 = JsonConvert.DeserializeObject<Speaker>(tmp);
                                                                                      speakers.list[0] = tmp2;





                                                                                      share|improve this answer















                                                                                      Simple solution in 2 lines of code. Just use the copy constructor.
                                                                                      No need to write TrulyObservableCollection etc.



                                                                                      Example:



                                                                                              speakers.list[0].Status = "offline";
                                                                                      speakers.list[0] = new Speaker(speakers.list[0]);


                                                                                      Another method without copy constructor. You can use serialization.



                                                                                              speakers.list[0].Status = "offline";
                                                                                      //speakers.list[0] = new Speaker(speakers.list[0]);
                                                                                      var tmp = JsonConvert.SerializeObject(speakers.list[0]);
                                                                                      var tmp2 = JsonConvert.DeserializeObject<Speaker>(tmp);
                                                                                      speakers.list[0] = tmp2;






                                                                                      share|improve this answer














                                                                                      share|improve this answer



                                                                                      share|improve this answer








                                                                                      edited Apr 1 '18 at 17:21

























                                                                                      answered Apr 1 '18 at 16:54









                                                                                      singapore saravanansingapore saravanan

                                                                                      288




                                                                                      288






























                                                                                          draft saved

                                                                                          draft discarded




















































                                                                                          Thanks for contributing an answer to Stack Overflow!


                                                                                          • Please be sure to answer the question. Provide details and share your research!

                                                                                          But avoid



                                                                                          • Asking for help, clarification, or responding to other answers.

                                                                                          • Making statements based on opinion; back them up with references or personal experience.


                                                                                          To learn more, see our tips on writing great answers.




                                                                                          draft saved


                                                                                          draft discarded














                                                                                          StackExchange.ready(
                                                                                          function () {
                                                                                          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f1427471%2fobservablecollection-not-noticing-when-item-in-it-changes-even-with-inotifyprop%23new-answer', 'question_page');
                                                                                          }
                                                                                          );

                                                                                          Post as a guest















                                                                                          Required, but never shown





















































                                                                                          Required, but never shown














                                                                                          Required, but never shown












                                                                                          Required, but never shown







                                                                                          Required, but never shown

































                                                                                          Required, but never shown














                                                                                          Required, but never shown












                                                                                          Required, but never shown







                                                                                          Required, but never shown







                                                                                          Popular posts from this blog

                                                                                          MongoDB - Not Authorized To Execute Command

                                                                                          in spring boot 2.1 many test slices are not allowed anymore due to multiple @BootstrapWith

                                                                                          Npm cannot find a required file even through it is in the searched directory