C# ObservableCollection PropertyChanged 事件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1003344/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 05:17:34  来源:igfitidea点击:

ObservableCollection PropertyChanged event

c#wpfmvvmobservablecollectionpropertychanged

提问by Jose

OK so I want to subclass ObservableCollectionto add a property to it. Unfortunately the PropertyChangedevent is protected. Basically I want to subclass it to have a SelectedItemthat I can bind to for lists in my MVVM WPF app.

好的,所以我想子类化ObservableCollection以向其添加属性。不幸的是,该PropertyChanged事件受到保护。基本上我想将它子类SelectedItem化为我可以绑定到我的 MVVM WPF 应用程序中的列表。

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 come the UI can get notified of PropertyChangedevents(e.g. Count property) and I can't do it in code-behind?

因为访问限制。这让我要问一个更深层次的问题。为什么 UI 可以收到PropertyChanged事件通知(例如 Count 属性)而我不能在代码隐藏中做到这一点?

My head is spinning, can someone please enlighten me?

我的头在旋转,有人能指教我吗?

采纳答案by Jose

SelectableList<int> intList = new SelectableList<int>();
((INotifyPropertyChanged)intList).PropertyChanged += 
    new PropertyChangedEventHandler(intList_Changed);

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显式地实现了 INotifyPropertyChanged,这意味着您必须先将实例转换为接口,然后才能访问接口的方法、属性和事件。至于为什么要这样做,我不知道。该绑定标记extension不“知道” ObservableCollections或任何其他类型。它检查类型以查看它们是否实现或扩展了特定的接口/基类(INPC、INCC、DependencyObject 等),因此不关心接口是否显式实现。

回答by micahtan

The UI can and does get notified. This is a restriction JUSTwith ObservableCollection, which defines the PropertyChanged event as protected.

UI 可以并且确实得到通知。这是一个限制JUST用的ObservableCollection,为保护其定义PropertyChanged事件。

FWIW, I think you're better off leaving ObservableCollection alone and just adding another property to your VM.

FWIW,我认为您最好不要理会 ObservableCollection,而只是向您的 VM 添加另一个属性。

回答by jpierson

ObservableCollection (int .NET 3.5) appears to implement the PropertyChanged event in an interesting way.

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

protected event PropertyChangedEventHandler PropertyChanged;

event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged;

This means that the protected PropertyChangedevent is likely only meant to be used for internal implementation. The other INotifyPropertyChanged.PropertyChangedevent is the one that actually fulfills the implementation of the INotifyPropertyChangedinterface as an explicit interface. Strangely I do not see any place within the ObservableCollection where the INotifyPropertyChanged.PropertyChangedis 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.

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

In the .NET 4.0 implementation it appears that the INotifyPropertyChanged.PropertyChangedevent instead hooks to the same private delegate used by the protected PropertyChangedevent 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.

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

Correction:I have verified that the INotifyPropertyChanged.PropertyChangedevent 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.

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

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.

因此,为了让您的示例工作,您需要编写使其工作看起来像下面的示例,正​​如 Will 在他的回答中所展示的那样。

SelectableList<int> intList = new SelectableList<int>();
((INotifyPropertyChanged)intList).PropertyChanged += 
    new PropertyChangedEventHandler(intList_Changed);

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 OnPropertyChangedmethod 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.

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

回答by Somnath

I tried to add a new property in

我试图在

public class ResultCollection<T> : ObservableCollection<T>
{

        Boolean _val;
        public Boolean Val
        {   
            get
            {   
                return _val;
            }
            set
            {   
                _val= value;
                OnPropertyChanged(new PropertyChangedEventArgs("Val"));
            }
        }
}

I really didn't notice that PropertyChangedis defined as protected. Finally moved Val property to ViewModel.

我真的没有注意到PropertyChanged被定义为protected。最后将 Val 属性移至 ViewModel。