ObservableCollection PropertyChanged 事件
我想对 ObservableCollection 进行子类化以向其添加属性。 不幸的是,PropertyChanged
事件受到保护。 基本上,我想将其子类化以获得一个 SelectedItem
,我可以将其绑定到我的 MVVM WPF 应用程序中的列表。
这是我的班级的框架:
public class SelectableList<T> : ObservableCollection<T>
{
public T SelectedItem {get;set;}
}
但我不能执行以下操作:
SelectableList<int> intList = new SelectableList<int>();
intList.PropertyChanged += new PropertyChangedEventHandler(intList_Changed);
因为访问限制。 这让我提出了一个更深层次的问题。 UI 如何通知 PropertyChanged
事件(例如 Count 属性)? 请注意,我无法在代码隐藏中执行此操作。
我的头很晕,有人可以帮我解惑吗?
I want to subclass ObservableCollection
to add a property to it. Unfortunately, the PropertyChanged
event is protected. Basically, I want to subclass it to have a SelectedItem
that I can bind to for lists in my MVVM WPF app.
Here's the skeleton of my class:
public class SelectableList<T> : ObservableCollection<T>
{
public T SelectedItem {get;set;}
}
But I cannot do the following:
SelectableList<int> intList = new SelectableList<int>();
intList.PropertyChanged += new PropertyChangedEventHandler(intList_Changed);
because of access restrictions. This causes me to ask a deeper question. How is the UI notified of PropertyChanged
events (e.g. Count property)? Note that I cannot do it in a code-behind.
My head is spinning, can someone please enlighten me?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
ObservableCollection 显式实现 INotifyPropertyChanged,这意味着您必须先将实例转换为接口,然后才能访问接口的方法、属性和事件。 至于为什么要这样做,我不知道。 绑定标记扩展n 不“知道“ObservableCollections 或任何其他类型。 它检查类型以查看它们是否实现或扩展特定的接口/基类(INPC、INCC、DependencyObject 等),因此不关心接口是否显式实现。
ObservableCollection implements INotifyPropertyChanged explicitly, which means you have to cast the instance to the interface before you can access the interface's methods, properties and events. As to why this is done, I don't know. The Binding markup extension doesn't "know" ObservableCollections or any other type. It checks types to see if they implement or extend specific interfaces/base classes (INPC, INCC, DependencyObject, etc) and so doesn't care if the interface is implemented explicitly.
ObservableCollection (int .NET 3.5) 似乎在 有趣的方式。
这意味着受保护的 PropertyChanged 事件可能仅用于内部实现。 另一个 INotifyPropertyChanged.PropertyChanged 事件实际上实现了 INotifyPropertyChanged 接口,作为 显式接口。 奇怪的是,我在 ObservableCollection 中没有看到任何实际引发 INotifyPropertyChanged.PropertyChanged 的地方。 这可能表明这是 .NET 3.5 中的一个错误,尽管我还没有测试来确认当将项目添加到集合中时是否会引发 Count 的属性更改事件,但这似乎是它应该如何工作的。
在 .NET 4.0 实现中,INotifyPropertyChanged.PropertyChanged 事件似乎改为挂钩到受保护的 PropertyChanged 事件使用的同一私有委托,这可能是一个错误修复。 这也可能只是由于 .NET 4.0 中处理自动事件实现方式的差异。
更正:我已经验证了 INotifyPropertyChanged.PropertyChanged 事件是由 ObservableCollection 引发的,因此我上面基于使用 Reflector 查看 ObservableCollection 实现的结果所做的假设一定是不准确的。 我的猜测是反射器正在做一些奇怪的错误,我还没有证据证明这一点。
因此,为了让您的示例正常工作,您需要编写如下示例,正如威尔在他的回答中所演示的那样。
有趣吧? 使用显式接口主要用于避免给定接口所需的成员之间不可避免的冲突,但它们在某种意义上可用于隐藏成员的存在。
如果您想为您在子类中引入的自定义属性引发属性更改事件,请考虑覆盖和/或调用 ObservableCollection 也实现的受保护的 OnPropertyChanged 方法。 该技术是一个被广泛采用的标准,允许子类在无需访问底层事件委托的情况下引发事件或处理事件。 通常最好也使用这种技术,而不是让子类挂钩事件处理程序来处理它自己的基类事件。 有关更多示例,请查看如何在 WinForms 和 WPF 中实现各种控件中的事件。
ObservableCollection (int .NET 3.5) appears to implement the PropertyChanged event in an interesting way.
This means that the protected PropertyChanged event is likely only meant to be used for internal implementation. The other INotifyPropertyChanged.PropertyChanged event is the one that actually fulfills the implementation of the INotifyPropertyChanged interface as an explicit interface. Strangely I do not see any place within the ObservableCollection where the INotifyPropertyChanged.PropertyChanged is actually raised. This may signal that this was a bug in .NET 3.5 although I haven't tested to confirm whether for example a property changed event is raised for Count when an item is added to a collection but that appears to be how it is supposed to work.
In the .NET 4.0 implementation it appears that the INotifyPropertyChanged.PropertyChanged event instead hooks to the same private delegate used by the protected PropertyChanged event which may have been a bug fix. It is also possible this is just due to differences in how auto event implementations are handled in .NET 4.0.
Correction: I have verified that the INotifyPropertyChanged.PropertyChanged event is raised by ObservableCollection so the assumptions I made above based on results from using Reflector to look at the ObservableCollection implementation must be inaccurate. My guess is that reflector is doing something strange bug I have no proof of that yet.
So to get your example to work you would need to write for this to work would look like the example below just as Will has demonstrated in his answer.
Interesting right? Using explicit interfaces is mainly used to avoid inevitable collisions in members required for a given interface but they can be used to in a sense hide the existence of a member.
If you would like to raise property change events for your own custom properties that you introduce in your subclass look into overriding and/or calling the protected OnPropertyChanged method that ObservableCollection also implements. This technique is a well adopted standard and allows subclasses to raise events or handle events without having access to the underlying event delegate. It is generally preferred to use this technique too by the way instead of having a subclass hook event handlers to it's own base classes events. For more examples look at how events in various controls are implemented in WinForms and WPF.
我尝试添加一个新属性,但
我确实没有注意到 PropertyChanged 被定义为受保护。 最后将 Val 属性移至 ViewModel。
I tried to add a new property in
I really didn't notice that PropertyChanged is defined as protected. Finally moved Val property to ViewModel.
UI 可以而且确实会收到通知。 这是 ObservableCollection 的一个限制,它将 PropertyChanged 事件定义为受保护。
FWIW,我认为你最好不要单独保留 ObservableCollection,而只是向虚拟机添加另一个属性。
The UI can and does get notified. This is a restriction JUST with ObservableCollection, which defines the PropertyChanged event as protected.
FWIW, I think you're better off leaving ObservableCollection alone and just adding another property to your VM.