如何检测嵌套属性中的更改?

时间:2017-03-03 09:02:08

标签: c# wpf data-binding

在C#中,我有一个足够复杂的模型。我已经有一个WPF客户端来操作该模型。我正在使用MVVM。该模型中的所有对象都支持INotifyPropertyChanged,集合的所有属性都支持INotifyCollectionChanged

将其作为一个简单的例子:

using System;
using System.Collections.ObjectModel;
using System.ComponentModel;


namespace CollectionTest1
{
    public class PropertyChangedSupport : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        protected void FirePropertyChange([System.Runtime.CompilerServices.CallerMemberName] string propertyName = "")
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public class Company : PropertyChangedSupport
    {
        private string name;
        public String Name { get { return name; } set { name = value; FirePropertyChange(); } }
        public ObservableCollection<Employee> Employees { get; } = new ObservableCollection<Employee>();

    }

    public class Employee : PropertyChangedSupport
    {
        private string name;
        public String Name { get { return name; } set { name = value; FirePropertyChange(); } }
        public ObservableCollection<PresentTimespan> PresentTimespans { get; } = new ObservableCollection<PresentTimespan>();

        public Boolean IsPresentAt(DateTime t)
        {
            foreach (PresentTimespan pt in PresentTimespans)
            {
                if (pt.Start.CompareTo(t) <= 0 && pt.Finish.CompareTo(t) >= 0) return true;
            }
            return false;
        }
    }

    public class PresentTimespan : PropertyChangedSupport
    {
        private string comment;
        public String Comment { get { return comment; } set { comment = value; FirePropertyChange(); } }
        private DateTime start;
        public DateTime Start { get { return start; } set { start = value; FirePropertyChange(); } }

        private DateTime finish;
        public DateTime Finish { get { return finish; } set { finish = value; FirePropertyChange(); } }
    }

    public class CompanyStatusView : PropertyChangedSupport
    {
        private DateTime currentTime;
        public DateTime CurrentTime { get { return currentTime; } set { currentTime = value; FirePropertyChange(); } }

        private Company currentCompany;
        public Company CurrentCompany { get { return currentCompany; } set { currentCompany = value; FirePropertyChange(); } }

        public ObservableCollection<Employee> PresentEmployees { get; } = new ObservableCollection<Employee>();

        public CompanyStatusView()
        {
            UpdatePresentEmployees();

        }

        private void UpdatePresentEmployees()
        {
            PresentEmployees.Clear();
            foreach (Employee e in CurrentCompany.Employees) {
                if (e.IsPresentAt(currentTime)) PresentEmployees.Add(e);
            }
        }
    }
}

我希望只要有变化就调用UpdatePresentEmployees:

  • 收藏Company.Employees.PresentTimespans
  • Property Company.Employees.PresentTimespans.Start
  • Property Company.Employees.PresentTimespans.Finish
  • 收藏Company.Employees
  • Property CurrentTime
  • Property CurrentCompany

所以它基本上是由UpdatePresentEmployees读取的任何属性或集合。

到目前为止,我的最佳解决方案包括向上述所有对象注册大量事件处理程序。这包括有几个Dictionary实例来跟踪我必须订阅的添加对象,特别是我必须取消订阅的对象。

最困难和最令人讨厌的部分是订阅所有PresentTimespan个对象以侦听属性更改以及PresentTimespans EmployeeObservableTracker集合来监听集合更改。

我的猜测是必须有更好的方法来做到这一点。

毕竟,在JFace(Java)中有一个使用UpdatePresentEmployees的非常有趣的解决方案。因此,您只需提供ObservableTracker539320442跟踪哪些对象已被读取的代码,并自动让您监听其中任何一项的更改,并正确地取消订阅不相关的对象。因此,总的来说,这个问题有更好的方法。什么是C#提供?它能比我上面提到的最佳解决方案做得更好吗?我可以避免一些样板代码吗?可以用.net提供的类来完成,还是需要一些额外的类/库?

感谢您的帮助和建议!

2 个答案:

答案 0 :(得分:0)

您可以使用BindingList而不是ObservableCollection并附加到ListChanged事件。但请记住,BindingList有一些缺点,如不是很快。有关详细信息,这可能很有趣:difference between ObservableCollection and BindingList

如果您不想使用BindingList,则必须使用事件连接项目。

答案 1 :(得分:0)

正如Nikhil Agrawal所指出的,Rx或ReactiveUI对我来说是一个很好的框架。所以我认为这是一个解决方案。