在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
Company.Employees.PresentTimespans.Start
Company.Employees.PresentTimespans.Finish
Company.Employees
CurrentTime
CurrentCompany
所以它基本上是由UpdatePresentEmployees
读取的任何属性或集合。
到目前为止,我的最佳解决方案包括向上述所有对象注册大量事件处理程序。这包括有几个Dictionary
实例来跟踪我必须订阅的添加对象,特别是我必须取消订阅的对象。
最困难和最令人讨厌的部分是订阅所有PresentTimespan
个对象以侦听属性更改以及PresentTimespans
Employee
个ObservableTracker
集合来监听集合更改。
我的猜测是必须有更好的方法来做到这一点。
毕竟,在JFace(Java)中有一个使用UpdatePresentEmployees
的非常有趣的解决方案。因此,您只需提供ObservableTracker
和539320442
跟踪哪些对象已被读取的代码,并自动让您监听其中任何一项的更改,并正确地取消订阅不相关的对象。因此,总的来说,这个问题有更好的方法。什么是C#提供?它能比我上面提到的最佳解决方案做得更好吗?我可以避免一些样板代码吗?可以用.net提供的类来完成,还是需要一些额外的类/库?
感谢您的帮助和建议!
答案 0 :(得分:0)
您可以使用BindingList而不是ObservableCollection并附加到ListChanged事件。但请记住,BindingList有一些缺点,如不是很快。有关详细信息,这可能很有趣:difference between ObservableCollection and BindingList
如果您不想使用BindingList,则必须使用事件连接项目。
答案 1 :(得分:0)
正如Nikhil Agrawal所指出的,Rx或ReactiveUI对我来说是一个很好的框架。所以我认为这是一个解决方案。