Сделал быструю реализацию сам:
public class ObservableCollectionEx<T> : ObservableCollection<T> where T : INotifyPropertyChanged
{
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
Unsubscribe(e.OldItems);
Subscribe(e.NewItems);
base.OnCollectionChanged(e);
}
protected override void ClearItems()
{
foreach(T element in this)
element.PropertyChanged -= ContainedElementChanged;
base.ClearItems();
}
private void Subscribe(IList iList)
{
if (iList != null)
{
foreach (T element in iList)
element.PropertyChanged += ContainedElementChanged;
}
}
private void Unsubscribe(IList iList)
{
if (iList != null)
{
foreach (T element in iList)
element.PropertyChanged -= ContainedElementChanged;
}
}
private void ContainedElementChanged(object sender, PropertyChangedEventArgs e)
{
OnPropertyChanged(e);
}
}
Признано, было бы немного запутанно и вводить в заблуждение запуск PropertyChanged в коллекции, когда свойство, которое фактически изменилось, находится в отдельном элементе, но это будет соответствовать моей конкретной цели. Это может быть расширено новым событием, которое запускается вместо внутри ContainerElementChanged
Мысли
РЕДАКТИРОВАТЬ: Следует отметить, что BCL ObservableCollection предоставляет интерфейс INotifyPropertyChanged только через явную реализацию, поэтому вам необходимо предоставить приведение для присоединения к событию следующим образом:
ObservableCollectionEx<Element> collection = new ObservableCollectionEx<Element>();
((INotifyPropertyChanged)collection).PropertyChanged += (x,y) => ReactToChange();
EDIT2: добавлена обработка ClearItems, спасибо, Джош
EDIT3: добавлена правильная отмена подписки на PropertyChanged, спасибо Mark
РЕДАКТИРОВАТЬ4: Wow это действительно учиться, как вы идете :). KP отметил, что событие было инициировано с коллекцией в качестве отправителя, а не с элементом, когда изменяется содержащийся элемент. Он предложил объявить событие PropertyChanged для класса, помеченного new . Это будет иметь несколько проблем, которые я попытаюсь проиллюстрировать на следующем примере:
// work on original instance
ObservableCollection<TestObject> col = new ObservableCollectionEx<TestObject>();
((INotifyPropertyChanged)col).PropertyChanged += (s, e) => { Trace.WriteLine("Changed " + e.PropertyName); };
var test = new TestObject();
col.Add(test); // no event raised
test.Info = "NewValue"; //Info property changed raised
// working on explicit instance
ObservableCollectionEx<TestObject> col = new ObservableCollectionEx<TestObject>();
col.PropertyChanged += (s, e) => { Trace.WriteLine("Changed " + e.PropertyName); };
var test = new TestObject();
col.Add(test); // Count and Item [] property changed raised
test.Info = "NewValue"; //no event raised
Вы можете видеть из примера, что «переопределение» события имеет побочный эффект, который вы должны быть чрезвычайно осторожны с тем, какой тип переменной вы используете при подписке на событие, так как это диктует, какие события вы получаете.