ObservableCollection PropertyChanged事件

Jos*_*ose 8 c# wpf observablecollection mvvm propertychanged

好的,所以我想子类ObservableCollection为它添加一个属性.不幸的是,PropertyChanged活动受到保护.基本上我想将它子类SelectedItem化为我可以绑定到我的MVVM WPF应用程序中的列表.

这是我班级的骨架:

public class SelectableList<T> : ObservableCollection<T>
{
    public T SelectedItem {get;set;}
}
Run Code Online (Sandbox Code Playgroud)

但我不能做到以下几点:

SelectableList<int> intList = new SelectableList<int>();
intList.PropertyChanged += new PropertyChangedEventHandler(intList_Changed);
Run Code Online (Sandbox Code Playgroud)

因为访问限制.这让我提出了一个更深层次的问题.为什么用户界面可以获得PropertyChanged事件通知(例如Count属性),我不能在代码隐藏中做到这一点?

我的头在旋转,有人可以赐教吗?

小智 11

SelectableList<int> intList = new SelectableList<int>();
((INotifyPropertyChanged)intList).PropertyChanged += 
    new PropertyChangedEventHandler(intList_Changed);
Run Code Online (Sandbox Code Playgroud)

ObservableCollection 显式实现了INotifyPropertyChanged,这意味着您必须先将实例强​​制转换为接口,然后才能访问接口的方法,属性和事件.至于为什么这样做,我不知道.该Binding标记extensio n不"知道" ObservableCollections或任何其他类型.它检查类型以查看它们是否实现或扩展特定的接口/基类(INPC,INCC,DependencyObject等),因此不关心接口是否显式实现.

  • @jpierson:lol,我回答了*1年,9个月,21天前*.你觉得你已经注意到了.(顺便说一句,我不在乎,没关系,回答 - 你在那里得到了一些好消息). (2认同)

jpi*_*son 8

ObservableCollection(int .NET 3.5)似乎以一种有趣的方式实现了PropertyChanged事件.

protected event PropertyChangedEventHandler PropertyChanged;

event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged;
Run Code Online (Sandbox Code Playgroud)

这意味着受保护的PropertyChanged事件可能仅用于内部实现.另一个INotifyPropertyChanged.PropertyChanged事件实际上是作为显式接口实现INotifyPropertyChanged接口的实现.奇怪的是,我没有在ObservableCollection中看到实际引发INotifyPropertyChanged.PropertyChanged的任何地方.这可能表明这是.NET 3.5中的一个错误,尽管我还没有测试确认是否例如当一个项目被添加到集合时是否为Count引发属性更改事件但是它似乎是如何工作的.

在.NET 4.0实现中,似乎INotifyPropertyChanged.PropertyChanged事件挂钩到受保护的PropertyChanged事件使用的同一个私有委托,这可能是一个错误修复.这也可能是由于.NET 4.0中自动事件实现的处理方式不同.

更正:我已经验证了ObservableCollection引发了INotifyPropertyChanged.PropertyChanged事件,因此我根据使用Reflector查看ObservableCollection实现的结果所做的假设必须是不准确的.我的猜测是反射器正在做一些奇怪的错误我还没有证据.

所以为了让你的例子工作,你需要写这个工作看起来像下面的例子,正如威尔在他的答案中所证明的那样.

SelectableList<int> intList = new SelectableList<int>();
((INotifyPropertyChanged)intList).PropertyChanged += 
    new PropertyChangedEventHandler(intList_Changed);
Run Code Online (Sandbox Code Playgroud)

有意思吗?使用显式接口主要用于避免给定接口所需的成员中不可避免的冲突,但它们可用于某种意义上隐藏成员的存在.

如果您想为您自己的子类中引入的自定义属性引发属性更改事件,请查看覆盖和/或调用ObservableCollection也实现的受保护OnPropertyChanged方法.这种技术是一种很好的采用标准,它允许子类在不访问底层事件委托的情况下引发事件或处理事件.通常也喜欢使用这种技术,而不是将子类钩子事件处理程序放到它自己的基类事件中.有关更多示例,请查看WinForms和WPF中各种控件中的事件是如何实现的.