问题
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?
回答1:
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<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);
}
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.
回答2:
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
来源:https://stackoverflow.com/questions/31342296/why-does-observablecollectiont-implement-inotifypropertychanged