Wednesday, May 4, 2011

Extending ObservableCollection to notify when an Item has changed.

By Miguel Juárez

There are several times that we would like that our collection would have the ability to notify not only when an element is added or removed from the collection itself (like the ObservableCollection does), but also to notify when any of the items’ property changes (when the items themselves are already implementing the INotifyPropertyChanged interface). Here I propose a solution for this problem.

What I’ll basically do is to extend ObservableCollection to provide for such capabilities. I will also define a new EventHandler (with a new EventArgs type) which the consumer can subscribe to get information from the PropertyChanged, such as the Property Name, or the Item’s Index in the collection.

public class NotifyCollectionChangeEventArgs : PropertyChangedEventArgs

{

public int Index { get; set; }

public NotifyCollectionChangeEventArgs(int index, string propertyName)

: base(propertyName)

{

Index = index;

}

}

public class NotifiableCollection: ObservableCollection where T: class, INotifyPropertyChanged

{

public event EventHandler<NotifyCollectionChangeEventArgs> ItemChanged;

protected override void ClearItems()

{

foreach (var item in this.Items)

{

item.PropertyChanged -= ItemPropertyChanged;

}

base.ClearItems();

}

protected override void SetItem(int index, T item)

{

this.Items[index].PropertyChanged -= ItemPropertyChanged;

base.SetItem(index, item);

this.Items[index].PropertyChanged += ItemPropertyChanged;

}

protected override void RemoveItem(int index)

{

this.Items[index].PropertyChanged -= ItemPropertyChanged;

base.RemoveItem(index);

}

protected override void InsertItem(int index, T item)

{

base.InsertItem(index, item);

item.PropertyChanged += ItemPropertyChanged;

}

private void ItemPropertyChanged(object sender, PropertyChangedEventArgs e)

{

T changedItem = sender as T;

OnItemChanged(this.IndexOf(changedItem), e.PropertyName);

}

private void OnItemChanged(int index, string propertyName)

{

if (ItemChanged != null)

{

this.ItemChanged(this, new NotifyCollectionChangeEventArgs(index, propertyName));

}

}

}

No comments:

Post a Comment