2

我们有一个 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
}

虽然这似乎可行,但不知何故我觉得这种方法是错误的,如果可能的话,我真的很想避免使用计时器,我很想听听其他建议和想法!

谢谢,

4

2 回答 2

1

这只是一个快速的想法,没有计时器,你能在 Course 和 Teacher 类上实现 IsDirty 事件吗?

例如,Teacher,PropertyChanged 内部的管理者(当学生集合发生变化时正确订阅/取消订阅)。当它的任何学生发生有效更改时,它所要做的就是引发 IsDirty 事件,这些事件都以学生 obj 作为参数。

Course 将监听并捕获 teacher.IsDirty 事件,并将引发它自己的 course.IsDirty,其中 CourseEventArgs = new CourseEventArgs 将有一个 Course,Teacher 和 Student 有脏字段。

在 Department 类中,您收听 Course IsDirty 事件并解析 args...

这个想法似乎与您所做的相同,但实际上并非如此,因为它仅在最低级别处理任何 PropertyChanged,然后使用您自己的事件将必要的信息冒泡到顶部。它将顶级课程与学生的 PropertyChanged 行为实现以及广泛的聊天区分开来。此外,如果在学生级别,您进行更改(通过 UI,并发布它们,单击保存或其他)然后您可以控制何时引发 IsDirty,也许只有一次。

于 2012-04-05T16:42:11.323 回答
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...
    }
}
于 2012-04-06T15:49:05.743 回答