ObservableCollection PropertyChanged事件

时间:2009-06-16 18:58:11

标签: c# wpf mvvm 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属性),而我无法在代码隐藏中执行此操作?

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

4 个答案:

答案 0 :(得分:10)

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

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

答案 1 :(得分:8)

ObservableCollection(int .NET 3.5)似乎在interesting way中实现了PropertyChanged事件。

protected event PropertyChangedEventHandler PropertyChanged;

event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged;

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

在.NET 4.0实现中,似乎 INotifyPropertyChanged.PropertyChanged 事件挂钩到受保护的 PropertyChanged 事件使用的同一个私有委托,这可能是一个错误固定。这也可能是由于differences in how auto event implementations are handled in .NET 4.0

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

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

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

有趣吗?使用显式接口主要用于避免给定接口所需的成员中不可避免的冲突,但它们可用于隐藏成员的存在。

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

答案 2 :(得分:1)

我尝试在

中添加新属性
public class ResultCollection<T> : ObservableCollection<T>
{

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

我真的没有注意到 PropertyChanged 被定义为受保护的。最后将Val属性移动到ViewModel。

答案 3 :(得分:0)

用户界面可以并且确实得到通知。这是一个带有ObservableCollection的限制 JUST ,它将PropertyChanged事件定义为protected。

FWIW,我认为你最好不要单独留下ObservableCollection而只是向你的VM添加另一个属性。