为了详细说明上面 Clemens 的回答,这是使用这些事件(在集合上和包含的项目上)来实现 IsDirty 标志的简单方法,例如您描述的:
public class DirtyCollection<T> : ObservableCollection<T> where T : INotifyPropertyChanged
{
private bool isDirty = false;
public bool IsDirty
{
get { return this.isDirty; }
}
public void Clean()
{
this.isDirty = false;
}
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
// We aren't concerned with how the collection changed, just that it did.
this.isDirty = true;
// But we do need to add the handlers to detect property changes on each item.
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
this.AddPropertyChanged(e.NewItems);
break;
case NotifyCollectionChangedAction.Remove:
this.RemovePropertyChanged(e.OldItems);
break;
case NotifyCollectionChangedAction.Replace:
case NotifyCollectionChangedAction.Reset:
this.RemovePropertyChanged(e.OldItems);
this.AddPropertyChanged(e.NewItems);
break;
}
base.OnCollectionChanged(e);
}
private void AddPropertyChanged(IEnumerable items)
{
if (items != null)
{
foreach (var obj in items.OfType<INotifyPropertyChanged>())
{
obj.PropertyChanged += OnItemPropertyChanged;
}
}
}
private void RemovePropertyChanged(IEnumerable items)
{
if (items != null)
{
foreach (var obj in items.OfType<INotifyPropertyChanged>())
{
obj.PropertyChanged -= OnItemPropertyChanged;
}
}
}
private void OnItemPropertyChanged(object sender, PropertyChangedEventArgs e)
{
// A property of a contained item has changed.
this.isDirty = true;
}
}
代码应该是不言自明的。
当然,您可以删除“where T : INotifyPropertyChanged”以允许将未实现该接口的对象存储在集合中,但是您将不会收到有关它们的任何属性更改的通知,因为没有该接口,他们无法通知您。
如果您不仅要跟踪集合是脏的,而且还要跟踪如何,在 OnCollectionChanged 和 OnItemPropertyChanged 中添加一些用于记录事件 args 中传递的信息的添加会很好地做到这一点。