// Derived from BindableBase Class which implements InotifyPropertyChanged
public class SecondLevelViewModel : BindableBase
{
// constructor
public SecondLevelViewModel()
{
// relevant instantiations
ThirdLevels.ListChanged += ThirdLevels_ListChanged;
//foreach (ThirdLevelViewModel thirdLevel in ThirdLevels)
//{
// thirdLevel.PropertyChanged += thirdLevel_PropertyChanged;
//}
}
// ListChanged Event Handler
private static void ThirdLevels_ListChanged(object? sender, ListChangedEventArgs e)
{
ArgumentNullException.ThrowIfNull(sender);
BindingList<ThirdLevelViewModel> thirds = (BindingList<ThirdLevelViewModel>)sender!;
// The example shows only the processing of the "ItemChanged" change type.
// The rest of the values are given only to show what types of changes there are.
// If they do not need to be processed, they can be deleted.
switch (e.ListChangedType)
{
case ListChangedType.ItemChanged:
// Handling change of the ThirdLevelViewModel property
{
// We process only the next element.
// Its change will cause ListChanged for it and
// the next item will be processed in it.
// And so on down the chain to the end of the collection.
if (e.NewIndex < thirds.Count - 1)
{
ThirdLevelViewModel current = thirds[e.NewIndex];
ThirdLevelViewModel next = thirds[e.NewIndex + 1];
switch (e.PropertyDescriptor?.Name)
{
case nameof(ThirdLevelViewModel.Duration):
next.Duration = current.Duration + TimeSpan.FromSeconds(1);
break;
case nameof(ThirdLevelViewModel.StartTime):
next.StartTime = current.StartTime.AddMinutes(1);
break;
default:
break;
}
}
}
break;
case ListChangedType.Reset:
break;
case ListChangedType.ItemAdded:
break;
case ListChangedType.ItemDeleted:
break;
case ListChangedType.ItemMoved:
break;
case ListChangedType.PropertyDescriptorAdded:
break;
case ListChangedType.PropertyDescriptorDeleted:
break;
case ListChangedType.PropertyDescriptorChanged:
break;
default:
break;
}
}
// properties
public BindingList<ThirdLevelViewModel> ThirdLevels { get; } = new();
}
// Derived from BindableBase Class which implements InotifyPropertyChanged
public class SecondLevelViewModel : BindableBase
{
// constructor
public SecondLevelViewModel()
{
// relevant instantiations
ThirdLevels.ListChanged += ThirdLevels_ListChanged;
//foreach (ThirdLevelViewModel thirdLevel in ThirdLevels)
//{
// thirdLevel.PropertyChanged += thirdLevel_PropertyChanged;
//}
}
// ListChanged Event Handler
private static void ThirdLevels_ListChanged(object? sender, ListChangedEventArgs e)
{
ArgumentNullException.ThrowIfNull(sender);
BindingList<ThirdLevelViewModel> thirds = (BindingList<ThirdLevelViewModel>)sender!;
// The example shows only the processing of the "ItemChanged" change type.
// The rest of the values are given only to show what types of changes there are.
// If they do not need to be processed, they can be deleted.
switch (e.ListChangedType)
{
case ListChangedType.ItemChanged:
// Handling change of the ThirdLevelViewModel property
{
// We process only the next element.
// Its change will cause ListChanged for it and
// the next item will be processed in it.
// And so on down the chain to the end of the collection.
if (e.NewIndex < thirds.Count - 1)
{
ThirdLevelViewModel current = thirds[e.NewIndex];
ThirdLevelViewModel next = thirds[e.NewIndex + 1];
next.Duration = current.Duration + TimeSpan.FromSeconds(1);
}
}
break;
case ListChangedType.Reset:
break;
case ListChangedType.ItemAdded:
break;
case ListChangedType.ItemDeleted:
break;
case ListChangedType.ItemMoved:
break;
case ListChangedType.PropertyDescriptorAdded:
break;
case ListChangedType.PropertyDescriptorDeleted:
break;
case ListChangedType.PropertyDescriptorChanged:
break;
default:
break;
}
}
// properties
public BindingList<ThirdLevelViewModel> ThirdLevels { get; } = new();
}
// Derived from BindableBase Class which implements InotifyPropertyChanged
public class SecondLevelViewModel : BindableBase
{
// constructor
public SecondLevelViewModel()
{
// relevant instantiations
ThirdLevels.ListChanged += ThirdLevels_ListChanged;
//foreach (ThirdLevelViewModel thirdLevel in ThirdLevels)
//{
// thirdLevel.PropertyChanged += thirdLevel_PropertyChanged;
//}
}
// ListChanged Event Handler
private static void ThirdLevels_ListChanged(object? sender, ListChangedEventArgs e)
{
ArgumentNullException.ThrowIfNull(sender);
BindingList<ThirdLevelViewModel> thirds = (BindingList<ThirdLevelViewModel>)sender!;
// The example shows only the processing of the "ItemChanged" change type.
// The rest of the values are given only to show what types of changes there are.
// If they do not need to be processed, they can be deleted.
switch (e.ListChangedType)
{
case ListChangedType.ItemChanged:
// Handling change of the ThirdLevelViewModel property
{
// We process only the next element.
// Its change will cause ListChanged for it and
// the next item will be processed in it.
// And so on down the chain to the end of the collection.
if (e.NewIndex < thirds.Count - 1)
{
ThirdLevelViewModel current = thirds[e.NewIndex];
ThirdLevelViewModel next = thirds[e.NewIndex + 1];
switch (e.PropertyDescriptor?.Name)
{
case nameof(ThirdLevelViewModel.Duration):
next.Duration = current.Duration + TimeSpan.FromSeconds(1);
break;
case nameof(ThirdLevelViewModel.StartTime):
next.StartTime = current.StartTime.AddMinutes(1);
break;
default:
break;
}
}
}
break;
case ListChangedType.Reset:
break;
case ListChangedType.ItemAdded:
break;
case ListChangedType.ItemDeleted:
break;
case ListChangedType.ItemMoved:
break;
case ListChangedType.PropertyDescriptorAdded:
break;
case ListChangedType.PropertyDescriptorDeleted:
break;
case ListChangedType.PropertyDescriptorChanged:
break;
default:
break;
}
}
// properties
public BindingList<ThirdLevelViewModel> ThirdLevels { get; } = new();
}
For WPF I recommend using BindingList instead of ObservableCollection in such cases. In the IBindingList.ListChanged event you get the index of the changed element, the PropertyDescriptor of the changed property and other arguments needed to identify the changes.
Here is an example of using such a collection:
// Derived from BindableBase Class which implements InotifyPropertyChanged
public class SecondLevelViewModel : BindableBase
{
// constructor
public SecondLevelViewModel()
{
// relevant instantiations
ThirdLevels.ListChanged += ThirdLevels_ListChanged;
//foreach (ThirdLevelViewModel thirdLevel in ThirdLevels)
//{
// thirdLevel.PropertyChanged += thirdLevel_PropertyChanged;
//}
}
// ListChanged Event Handler
private static void ThirdLevels_ListChanged(object? sender, ListChangedEventArgs e)
{
ArgumentNullException.ThrowIfNull(sender);
BindingList<ThirdLevelViewModel> thirds = (BindingList<ThirdLevelViewModel>)sender!;
// The example shows only the processing of the "ItemChanged" change type.
// The rest of the values are given only to show what types of changes there are.
// If they do not need to be processed, they can be deleted.
switch (e.ListChangedType)
{
case ListChangedType.ItemChanged:
// Handling change of the ThirdLevelViewModel property
{
// We process only the next element.
// Its change will cause ListChanged for it and
// the next item will be processed in it.
// And so on down the chain to the end of the collection.
if (e.NewIndex < thirds.Count - 1)
{
ThirdLevelViewModel current = thirds[e.NewIndex];
ThirdLevelViewModel next = thirds[e.NewIndex + 1];
next.Duration = current.Duration + TimeSpan.FromSeconds(1);
}
}
break;
case ListChangedType.Reset:
break;
case ListChangedType.ItemAdded:
break;
case ListChangedType.ItemDeleted:
break;
case ListChangedType.ItemMoved:
break;
case ListChangedType.PropertyDescriptorAdded:
break;
case ListChangedType.PropertyDescriptorDeleted:
break;
case ListChangedType.PropertyDescriptorChanged:
break;
default:
break;
}
}
// properties
public BindingList<ThirdLevelViewModel> ThirdLevels { get; } = new();
}
default