为什么 ObservableCollection 实现 INotifyPropertyChanged
本文关键字:实现 INotifyPropertyChanged ObservableCollection 为什么 | 更新日期: 2023-09-27 18:01:59
在 .NET 4.0 中,没有由 ObservableCollection<T>
定义的单个属性,也不会覆盖其父级或接口的任何属性。那么ObservableCollection<T>
为什么要实施INotifyPropertyChanged
呢?
我能想到的一个原因是,它使子类更容易定义自己的属性并使用ObservableCollection<T>
实现的OnPropertyChanged
方法。但这是主要原因吗?
Count
和Item[]
更改都会收到通知。下面是一个示例(仅将 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
Item
、Items
和Count
中,只有Item
实际上有一个 setter,所以没有必要覆盖Items
或Count
,因为你无法设置它们,所以没有必要从中引发事件。它们只会响应其他方法(如 Add
或 Remove
(而更改,并且这些方法将引发必要的属性更改事件(实际上,如果您查看源代码,ObservableCollection<T>
也不会覆盖这些方法,而是覆盖由基类中的Add
和Remove
调用protected
方法(。
现在对于Item
,该属性不会被覆盖,但如果您查看 SetItem
方法的源代码:
/// <summary>
/// Called by base class Collection<T> 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>
中被覆盖。