Skip to main content
Stack Overflow
  1. About
  2. For Teams

Return to Answer

Post Timeline

added 549 characters in body
Source Link
EldHasp
  • 8.8k
  • 2
  • 11
  • 34
 // 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();
 }
Source Link
EldHasp
  • 8.8k
  • 2
  • 11
  • 34

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

AltStyle によって変換されたページ (->オリジナル) /