简体   繁体   中英

Why does ObservableCollection<T> implement INotifyPropertyChanged?

In .NET 4.0, there isn't a single property defined by ObservableCollection<T> nor does it override any property of its parent or interfaces. So why does ObservableCollection<T> implement INotifyPropertyChanged ?

One reason I can think of is that it makes it easier for subclasses to define their own properties and use the OnPropertyChanged method implemented by ObservableCollection<T> . But is this the main reason?

Both Count and Item[] changes are notified. Here's a sample (using C# 6 just for the string interpolation):

using System;
using System.ComponentModel;
using System.Collections.ObjectModel;

class Test
{
    static void Main(string[] args)
    {
        var collection = new ObservableCollection<string>();
        ((INotifyPropertyChanged)collection).PropertyChanged += (sender, e) =>
        {
            Console.WriteLine($"  {e.PropertyName} changed");
        };

        Console.WriteLine("Adding");
        collection.Add("Item");
        Console.WriteLine("Adding");
        collection.Add("Other item");
        Console.WriteLine("Removing");
        collection.RemoveAt(0);
        Console.WriteLine("Changing");
        collection[0] = "Different";
    }
}

Output:

Adding
  Count changed
  Item[] changed
Adding
  Count changed
  Item[] changed
Removing
  Count changed
  Item[] changed
Changing
  Item[] changed

Of the properties Item , Items and Count , only Item actually has a setter, so there is no need to override Items or Count since you can't set them, there is no need to raise an event from it. They only change in response to some other method (like Add or Remove ) and those methods will raise the necessary property changed events (actually if you look at the source, ObservableCollection<T> doesn't override those methods either, but instead overrides protected methods that are called by Add and Remove in the base class).

Now for Item , the property isn't overriden, but if you look at the source for the SetItem method:

/// <summary>
/// Called by base class Collection&lt;T&gt; when an item is set in list;
/// raises a CollectionChanged event to any listeners.
/// </summary>
protected override void SetItem(int index, T item)
{
    CheckReentrancy();
    T originalItem = this[index];
    base.SetItem(index, item);

    OnPropertyChanged(IndexerName);
    OnCollectionChanged(NotifyCollectionChangedAction.Replace, originalItem, item, index);
}

You'll note from the comment that this is called by the base class when an Item is set and you'll also note that it fires off the OnPropertyChanged event.

If you look at the source for Collection<T> you can confirm that this is the case:

    public T this[int index] {
#if !FEATURE_CORECLR
        [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
#endif
        get { return items[index]; }
        set {
            if( items.IsReadOnly) {
                ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection);
            }

            if (index < 0 || index >= items.Count) {
                ThrowHelper.ThrowArgumentOutOfRangeException();
            }

            SetItem(index, value);
        }
    }

So in summary, Item in Collection<T> calls SetItem that is overridden in ObservableCollection<T> which triggers the PropertyChanged event.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM