【问题标题】:How can I notify that a property of an item in an observable collection has changed?如何通知可观察集合中项目的属性已更改?
【发布时间】:2011-09-30 00:43:56
【问题描述】:

好的,我在绑定到 ObservableCollection 的 XAML 文件中有一个 ItemsControl。 ObservableCollection 位于视图模型类(我们称之为 ViewModelA 类)中,并且 ObservableCollection 中的每个项目都是 另一个 视图模型类的实例(我们称之为 ViewModelB 类)。

ViewModelA 上有一个属性,当更改时,将间接更改 ViewModelB 类的许多实例中的属性值。换句话说,它不会直接进入 ViewModelB 并设置其属性,从而导致 INotifyPropertyChange 调用,而是进入模型,在我的模型中设置一些属性,并且我的模型中的更改会影响 ViewModelB 应该显示的内容视图。

如何通知视图 ViewModelB 中的某些内容发生了变化?

【问题讨论】:

    标签: c# wpf xaml observablecollection inotifypropertychanged


    【解决方案1】:

    理想情况下,您可以像 Reed Copsey 指出的那样做...在模型上实现 INotifyPropertyChanged 并让 ViewModelB 监听这些事件。然后,无论更新发生在哪里,ViewModelB 都会获取更改。

    但是,在某些情况下,模型不会(或不能)实现 INotifyPropertyChanged。在这种情况下,您可能需要考虑使用 Event Aggregator 模式在 ViewModelA 和 ViewModelB 实例之间传递消息。

    在这种情况下,您可以从 ViewModelA 发布“模型已更改”消息。 ViewModelB 实例将订阅此消息,并且当 A 发布消息时,每个实例都会收到通知。然后 ViewModelB 可以引发适当的 PropertyChanged 事件来告诉 UI 发生了什么变化。

    您可以在许多框架中找到有关事件聚合器的更多信息,包括

    【讨论】:

      【解决方案2】:

      如果模型中的更改将在 ViewModelB 的某些属性中发生更改,并且这些属性已向 UI 发出更改通知(即 ViewModleB 正在实现 INotifyPropertyChanged),则更改将立即反映在 UI 中。

      因此,如果您有另一个 viewmodelB 的 ObservableCollection,则无需为该 viewmodelB 的 propertychanged 连接事件。据我了解,无论谁更改 viewmodelB 的属性(模型类或其他任何人),如果属性有更改通知,视图将自动更新。

      【讨论】:

        【解决方案3】:

        为了解决这个问题,我创建了一个名为 VeryObservableCollection 的类。对于您添加的每个对象,它将对象的 NotifyPropertyChanged 事件与触发 CollectionChanged 事件的处理程序挂钩。对于删除的每个对象,它都会删除处理程序。非常简单,会给你你想要的。部分代码:

        public class VeryObservableCollection<T> : ObservableCollection<T>
        
        /// <summary>
        /// Override for setting item
        /// </summary>
        /// <param name="index">Index</param>
        /// <param name="item">Item</param>
        protected override void SetItem(int index, T item)
        {
            try
            {
                INotifyPropertyChanged propOld = Items[index] as INotifyPropertyChanged;
                if (propOld != null)
                    propOld.PropertyChanged -= new PropertyChangedEventHandler(Affecting_PropertyChanged);
            }
            catch (Exception ex)
            {
                Exception ex2 = ex.InnerException;
            }
            INotifyPropertyChanged propNew = item as INotifyPropertyChanged;
            if (propNew != null)
                propNew.PropertyChanged += new PropertyChangedEventHandler(Affecting_PropertyChanged);
        
            base.SetItem(index, item);
        }
        

        【讨论】:

          【解决方案4】:

          您应该能够告诉视图集合已更改,然后触发它重新绑定到整个集合(这将更新视图)。

          如果您的模型实现了INotifyPropertyChanged,另一种选择是让您的ViewModelB 类监听其包装模型的更改,并根据需要引发属性更改事件。

          【讨论】:

          • +1;您的回答比问题更清楚,所以我将重申一般情况:通知视图更改的两种方法是INotifyCollectionChangedINotifyPropertyChanged。但是,如果您的视图模型是相互依赖的,那么在您的视图模型中使用这些接口并根据需要弹出通知是非常自然的。
          • 这里的关键是集合本身并没有改变,所以 INotifyCollectionChanged 对我没有好处。但是,我可以在我的模型类上实现 INotifyPropertyChanged,所以它看起来会起作用。感谢您的帮助!
          猜你喜欢
          • 2010-11-04
          • 2013-02-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-09-02
          • 2023-04-02
          • 2017-03-13
          相关资源
          最近更新 更多