【问题标题】:WPF MVVM - How to subscribe to PropertyChanged of model instance bound to Grid row?WPF MVVM - 如何订阅绑定到网格行的模型实例的 PropertyChanged?
【发布时间】:2017-03-16 04:12:52
【问题描述】:

我的问题与MVVM in WPF - How to alert ViewModel of changes in Model... or should I?ViewModel subscribing to Model's PropertyChanged event for a specific property 非常相似。但是,还是有区别的。

背景信息

我的模型是 Employee,我感兴趣的属性是 DisplayLtdOccupationId。

但在我的 ViewModel 中,我不只是有一个 Employee 实例。相反,我有一个 Employee 对象的集合。

 ObservableCollection<Employee> EmployeeCensus

在我看来,我有一个绑定到 EmployeeCensus 的 DataGrid。所以我在网格中有员工行。

问题

我希望能够响应 DisplayLtdOccupationId 的值已更改的特定 Employee 行的 PropertyChanged。我想在我的 ViewModel 中使用处理程序方法来做到这一点。

在我的处理程序中,我希望刚刚更改的 Employee 对象将位于“sender”变量中。然后我会获取它的 DisplayLtdOccupationId,从 ViewModel 内存中已有的集合中进行查找,并在同一个 Employee 对象的不同属性中设置查找值。

更多详情

ViewModel 和 Employee Model 都实现了 INotifyPropertyChanged(通过:Microsoft.Practices.Prism.ViewModel.NotificationObject)。

DataGrid 将 DisplayLtdOccupationId 属性显示为内联下拉列表,用户可以在其中选择不同的值。

为什么不在 Employee 模型中,在 DisplayLtdOccupationId 的 Setter 中执行此操作?因为我无权访问那里的查找集合。

我不想在视图中使用触发器来启动处理程序。这导致了一个问题,这也是我想探索仅使用 ViewModel 和 Model 的解决方案的原因。

我还可以添加更多内容,但我试图让问题保持简短和重点。如果需要更多信息,请告知。

【问题讨论】:

    标签: wpf mvvm


    【解决方案1】:

    类似的东西。我想你希望得到一些更聪明、更简洁的东西,但这就是你得到的。 Employee_PropertyChanged 处理对Employee 属性的更改。您还可以为您的 Employee 类提供一个特定事件,该事件在更改其 DisplayLtdOccupationId 属性时引发。然后您的父视图模型将处理该事件而不是PropertyChanged。无论哪种方式都有效。

    public class ViewModel : ViewModelBase
    {
        public ViewModel()
        {
            EmployeeCensus = new ObservableCollection<Employee>();
        }
    
        #region EmployeeCensus Property
        private ObservableCollection<Employee> _employeeCensus = null;
        public ObservableCollection<Employee> EmployeeCensus
        {
            get { return _employeeCensus; }
            //  Protect this so we don't have to handle the case of somebody giving us
            //  a whole new collection of new Employees. 
            protected set
            {
                if (value != _employeeCensus)
                {
                    if (_employeeCensus != null)
                    {
                        _employeeCensus.CollectionChanged -= _employeeCensus_CollectionChanged;
                    }
    
                    _employeeCensus = value;
                    OnPropertyChanged(nameof(EmployeeCensus));
    
                    if (_employeeCensus != null)
                    {
                        _employeeCensus.CollectionChanged += _employeeCensus_CollectionChanged;
                    }
                }
            }
        }
    
        private void _employeeCensus_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            if (e.OldItems != null)
            {
                foreach (var item in e.OldItems.Cast<Employee>())
                {
                    item.PropertyChanged -= Employee_PropertyChanged;
                }
            }
            if (e.NewItems != null)
            {
                foreach (var item in e.NewItems.Cast<Employee>())
                {
                    item.PropertyChanged += Employee_PropertyChanged;
                }
            }
        }
    
        private void Employee_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            switch (e.PropertyName)
            {
                case nameof(Employee.DisplayLtdOccupationId):
                    //  Do stuff
                    break;
            }
        }
        #endregion EmployeeCensus Property
    }
    

    【讨论】:

    • 哇,真快。让我试试看!我不确定是否必须将处理程序添加到每个实例,但我看到了!感谢您提供安全代码并删除处理程序。
    • 只要把OC属性设为只读就简单多了。
    • @Will 这是真的。
    • '您还可以给您的 Employee 类一个特定事件,该事件会在其 DisplayLtdOccupationId 属性发生更改时引发'我已经养成了在我创建的每个属性附近设置这些事件的习惯,以避免处理 PropertyChanged - 无论好坏。
    猜你喜欢
    • 1970-01-01
    • 2010-11-23
    • 2011-10-07
    • 2016-08-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-18
    相关资源
    最近更新 更多