11

我想子类化为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

4 回答 4

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

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

于 2009-06-16T19:14:47.530 回答
11

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

protected event PropertyChangedEventHandler PropertyChanged;

event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged;

这意味着受保护的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 实现的结果所做的假设一定是不准确的。我的猜测是反射器正在做一些奇怪的错误,我还没有证据。

因此,要使您的示例正常工作,您需要为此编写代码,就像下面的示例一样,正如 Will 在他的回答中所展示的那样。

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

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

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

于 2011-03-29T20:59:41.897 回答
1

我试图在

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

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

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

于 2012-12-28T06:23:01.880 回答
0

UI 可以并且确实会收到通知。这只是ObservableCollection 的限制,它将 PropertyChanged 事件定义为受保护的。

FWIW,我认为您最好不要单独留下 ObservableCollection 并为您的虚拟机添加另一个属性。

于 2009-06-16T19:16:05.763 回答