【问题标题】:ObservableCollection PropertyChanged eventObservableCollection PropertyChanged 事件
【发布时间】:2010-11-03 10:51:02
【问题描述】:

我想继承 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 属性)?请注意,我不能在代码隐藏中执行此操作。

我头晕眼花,谁能赐教?

【问题讨论】:

    标签: c# wpf mvvm observablecollection propertychanged


    【解决方案1】:

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

    protected event PropertyChangedEventHandler PropertyChanged;
    
    event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged;
    

    这意味着受保护的 PropertyChanged 事件可能仅用于内部实现。另一个 INotifyPropertyChanged.PropertyChanged 事件是真正实现 INotifyPropertyChanged 接口作为explicit interface 的事件。奇怪的是,我在 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 中实现各种控件中的事件。

    【讨论】:

    • 非常感谢这个出色的、经过充分研究的答案!您的回答为我提供了使用 ObservableCollection 获取属性通知所需的“线索”。希望我有不止一票来奖励:)
    【解决方案2】:

    我尝试在

    中添加新属性
    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。

    【讨论】:

      【解决方案3】:
      SelectableList<int> intList = new SelectableList<int>();
      ((INotifyPropertyChanged)intList).PropertyChanged += 
          new PropertyChangedEventHandler(intList_Changed);
      

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

      【讨论】:

      • 抱歉,在我发布自己的答案之前,我一定忽略了你的答案。
      • @jpierson:大声笑,我回答了 1 年 9 个月 21 天前。雅认为你会注意到。 (顺便说一句,我不在乎,没关系,回答吧——你那里有一些很好的信息)。
      【解决方案4】:

      用户界面可以并且确实会收到通知。这是对 ObservableCollection 的限制JUST,它将 PropertyChanged 事件定义为受保护的。

      FWIW,我认为你最好不要管 ObservableCollection,只为你的虚拟机添加另一个属性。

      【讨论】:

      • ObservableCollection 实现了一个可公开访问的显式实现的 PropertyChanged 事件以及一个受保护的事件。请记住,受保护的成员不可能满足接口成员的实现,因此在这种情况下受保护的成员可以说是一条红鲱鱼。
      • 关于添加另一个属性而不是继承 ObservableCollection。我同意这可能是更简单的方法,如果您需要重用,请尝试使用 mini-ViewModel 模式而不是更改 ObservableCollection。我沿着创建一个 SelectableCollection 类的路线去做,就像 OP 正在尝试的那样,我可以说它简化了很多我不知道该怎么做的绑定情况,但我已经改变了我的其他一些地方最近的代码从这个 SelectableCollection 移开,因为让它成为 ViewModel 的扩展更容易。
      猜你喜欢
      • 2010-10-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多