为什么 ObservableCollection 实现 INotifyPropertyChanged

本文关键字:实现 INotifyPropertyChanged ObservableCollection 为什么 | 更新日期: 2023-09-27 18:01:59

在 .NET 4.0 中,没有由 ObservableCollection<T> 定义的单个属性,也不会覆盖其父级或接口的任何属性。那么ObservableCollection<T>为什么要实施INotifyPropertyChanged呢?

我能想到的一个原因是,它使子类更容易定义自己的属性并使用ObservableCollection<T>实现的OnPropertyChanged方法。但这是主要原因吗?

为什么 ObservableCollection<T> 实现 INotifyPropertyChanged

CountItem[]更改都会收到通知。下面是一个示例(仅将 C# 6 用于字符串插值(:

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";
    }
}

输出:

Adding
  Count changed
  Item[] changed
Adding
  Count changed
  Item[] changed
Removing
  Count changed
  Item[] changed
Changing
  Item[] changed
在属性

ItemItemsCount中,只有Item实际上有一个 setter,所以没有必要覆盖ItemsCount,因为你无法设置它们,所以没有必要从中引发事件。它们只会响应其他方法(如 AddRemove(而更改,并且这些方法将引发必要的属性更改事件(实际上,如果您查看源代码,ObservableCollection<T>也不会覆盖这些方法,而是覆盖由基类中的AddRemove调用protected方法(。

现在对于Item,该属性不会被覆盖,但如果您查看 SetItem 方法的源代码:

/// <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);
}

您将从注释中注意到,这是在设置Item时由基类调用的,并且您还将注意到它触发了OnPropertyChanged事件。

如果您查看Collection<T>的来源,您可以确认是这种情况:

    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);
        }
    }

因此,总而言之,Item Collection<T>调用中SetItem在触发PropertyChanged事件的ObservableCollection<T>中被覆盖。