我们有一个WPF应用程序,假设我有一个Department对象,其中我有一个ObservableCollection的课程,在每个课程中我有一个ObservableCollection的教师,在每个教师里面我有一个ObservableCollection的学生:
Department.cs ---- ObservableCollection课程
Course.cs ---- ObservableCollection教师
Teacher.cs ---- ObservableCollection学生
Student.cs ----姓名,年龄等
这4个类都实现了INotifyPropertyChanged,它们自己工作正常,我想要实现的是当Department对象图中的任何内容被更改时,是否是学生的年龄变化,或者添加了新课程还是教师删除,任何事情,我想知道它,理想情况下通过像DepartmentChanged这样的事件(理想情况下这只会加一次),所以我可以调用其他一些长时间运行的动作。
我很难想出一个干净的方法来做到这一点。据我所知,INotifyPropertyChanged仅跟踪类的属性更改,而ObservationCollection不知道其中一个项是否已更改。
到目前为止,我尝试了嵌套循环(伪代码):
foreach (var course in d.Courses){
foreach (var teacher in course.Teachers){
foreach (var student in teacher.Students){
((INotifyPropertyChanged)student).PropertyChanged += ...
}
teacher.Students.CollectionChanged += ...
}
}
但是可以想象,这会创建许多PropertyChanged事件,因为每个属性都订阅了它,而我想在Department中执行的操作最终被执行了很多次,这很糟糕。
然后我尝试使用一个计时器(我们的每个类都有一个IsDirty()来确定对象是否已经改变),间隔设置为500:
if(department != null && department.IsDirty()){
//call some long running Action here
}
虽然这似乎有效,但我觉得这种方法是错误的,如果可能的话,我真的想避免使用计时器,我很乐意听到其他建议和想法!
谢谢,
答案 0 :(得分:1)
这只是一个简单的想法,没有计时器,你可以在课程上实现IsDirty事件,&老师班?
例如,教师,内部PropertyChanged上的经理(当学生集合更改时正确订阅/取消订阅)。 当任何一个学生有一个有效的变化时,它所要做的只是提出IsDirty事件,所有事件都将学生obj作为一个参数。
课程将倾听并捕捉老师。这是一个很重要的事件,并将提升自己的课程.IsDirty WhereEventEventArgs = new CourseEventArgs将有一个课程,教师与学生有脏字。
在Department类中,您可以收听Course IsDirty事件并解析args ......
这个想法,似乎与你有同样的事情,但不是真的,因为它只处理最低级别的任何PropertyChanged然后利用你自己的事件将必要的信息鼓泡到顶部。其中顶级类别与学生的PropertyChanged行为实施以及广泛的喋喋不休。 此外,如果在学生级别,您进行更改(通过UI,发布它们,单击保存或其他),那么您可以控制何时引发IsDirty,可能只有一次。
答案 1 :(得分:1)
我认为您仍然需要在单个对象级别使用IsDrity位和INotifyPropertyChanged,但为什么不扩展ObservableCollection<T>
并覆盖一些基本方法来处理对象属性更改的注册?例如,创建类似的东西:
public class ChangeTrackerCollection<T> : ObservableCollection<T>
{
protected override void ClearItems()
{
foreach (var item in this)
UnregisterItemEvents(item);
base.ClearItems();
}
protected override void InsertItem(int index, T item)
{
base.InsertItem(index, item);
RegisterItemEvents(item);
}
protected override void RemoveItem(int index)
{
UnregisterItemEvents(this[index]);
base.RemoveItem(index);
}
private void RegisterItemEvents(T item)
{
item.PropertyChanged += this.OnItemPropertyChanged;
}
private void UnregisterItemEvents(T item)
{
item.PropertyChanged -= this.OnItemPropertyChanged;
}
private void OnItemPropertyChanged(object sender, PropertyChangedEventArgs e)
{
//TODO: raise event to parent object to notify that there was a change...
}
}