How to get edited values in ObservableCollectionin WPF(MVVM) - c#

public class PricingGrpModel
{
public string Name { get; set; }
public string Description { get; set; }
}
private ObservableCollection<PricingGrpModel> _myCollection;
public ObservableCollection<PricingGrpModel> myCollection
{
get { return _myCollection; }
set { _myCollection= value; OnPropertyChanged("myCollection"); }
}
myCollection.CollectionChanged += new NotifyCollectionChangedEventHandler(myCollection_CollectionChanged);
void myCollection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
try
{
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
break;
case NotifyCollectionChangedAction.Remove:
break;
}
}
catch(Exception exception)
{
}
}
I have bound 'myCollection' ObservableCollection to DataGrid's ItemsSource. The Collection Change event fired while adding or removing the Row. But I couldn't track the changes of existing row value. how can I get a notification when an item's property in an ObservableCollection has been changed?

you can use NewItems and OldItems properties of the NotifyCollectionChangedEventArgs.
When you call ObservableCollection.Remove(), the removed items will be present in OldItems property:
void myCollection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.OldItems != null)
{
foreach (var removedItem in e.OldItems)
{
}
}
}
The only problem is, that when you call ObservableCollection.Clear() method, the OldItems property is null.
If you want to access also cleared items, you will have to create your custom class by inheriting from ObservableCollection and override RemoveItem protected method. RemoveItem method is invoked also when you call ObservableCollection.Clear() You can use my ExtendedObservableCollection from this answer: Trigger InotifyPropertyChanged/CollectionChanged on ObservableCollection

You can't directly track the item Changes via the CollectionChanged Event.
What you can do is:
Add and Remove an EventHandler to the PricingGrpModel.PropertyChanged in the CollectionChanged EventHandler for each item in the ObservableCollection.

Related

WPF binding to property of all items in a collection

I need to bind to a bool property, that is only true, when one of the properties in the collection is true.
This is the binding:
<tk:BusyIndicator IsBusy="{Binding Tabs, Converter={StaticResource BusyTabsToStateConverter}}">
And the viewmodel:
public class MainWindowViewModel : INotifyPropertyChanged
{
private ObservableCollection<Tab> _tabs;
public ObservableCollection<Tab> Tabs
{
get
{ return _tabs; }
set
{
if (value != _tabs)
{
_tabs = value;
NotifyPropertyChanged();
}
}
}
The Tab class also has property change notification:
public class Tab : INotifyPropertyChanged
{
public bool IsBusy { get{...} set{...NotifyPropertyChanged();} }
This is the converter:
public class BusyTabsToStateConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var tabs = value as ObservableCollection<Tab>;
return tabs.Any(tab => tab.IsBusy);
}
}
The problem is, when Tab.IsBusy changes the binding source is not notified, because it is bound to the observable collection and not to the IsBusy property.
Is there a way to make the notification trigger correctly when the IsBusy property on any of the items in the collection changes?
Instead of a Binding Converter, you could have a AnyTabBusy property in MainWindowViewModel, for which a change notification is fired by a PropertyChanged event handler, which is attached or detached to individual elements from the Tabs collection when they are added to or removed from the collection.
In the example below, the Tabs property is readonly. If it has to be writeable, you would have to attach and detach the TabsCollectionChanged handler in the Tabs setter.
public class MainWindowViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public ObservableCollection<Tab> Tabs { get; } = new ObservableCollection<Tab>();
public bool AnyTabBusy
{
get { return Tabs.Any(t => t.IsBusy); }
}
public MainWindowViewModel()
{
Tabs.CollectionChanged += TabsCollectionChanged;
}
private void TabsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
foreach (Tab tab in e.NewItems)
{
tab.PropertyChanged += TabPropertyChanged;
}
break;
case NotifyCollectionChangedAction.Remove:
foreach (Tab tab in e.OldItems)
{
tab.PropertyChanged -= TabPropertyChanged;
}
break;
default:
break;
}
}
private void TabPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(Tab.IsBusy))
{
PropertyChanged?.Invoke(this,
new PropertyChangedEventArgs(nameof(AnyTabBusy)));
}
}
}
If you want to make this code reusable, you could put it into a derived collection class like shown below, where you could attach a handler for an ItemPropertyChanged event.
public class ObservableItemCollection<T>
: ObservableCollection<T> where T : INotifyPropertyChanged
{
public event PropertyChangedEventHandler ItemPropertyChanged;
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
base.OnCollectionChanged(e);
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
foreach (INotifyPropertyChanged item in e.NewItems)
{
item.PropertyChanged += OnItemPropertyChanged;
}
break;
case NotifyCollectionChangedAction.Remove:
foreach (INotifyPropertyChanged item in e.OldItems)
{
item.PropertyChanged -= OnItemPropertyChanged;
}
break;
default:
break;
}
}
private void OnItemPropertyChanged(object sender, PropertyChangedEventArgs e)
{
ItemPropertyChanged?.Invoke(this, e);
}
}
The view model could now be reduced to this:
public class MainWindowViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public ObservableItemCollection<Tab> Tabs { get; }
= new ObservableItemCollection<Tab>();
public bool AnyTabBusy
{
get { return Tabs.Any(t => t.IsBusy); }
}
public MainWindowViewModel()
{
Tabs.ItemPropertyChanged += TabPropertyChanged;
}
private void TabPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(Tab.IsBusy))
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(AnyTabBusy)));
}
}
}
I've taken #Clemens' answer, and converted in to an extension method that could make it easier to use on multiple collections. It will take an PropertyChangedEventHandler and automatically add and remove it from the items in the collection as they are added and removed. If you up-vote this, please up-vote#Clemens' answer also, since it is based on his work.
Be careful not use use an anonymous method as your PropertyChanged handler (this goes for all event handlers in general, not just this solution) without taking special precautions, as they can be difficult to remove.
(Note: this requires C# 7, as it uses a local function to make dealing with the CollectionChanged handler's delegate easier.)
public static class ObservableCollectionExtensions
{
public static Hook<TList> RegisterPropertyChangeHook<TList>(this ObservableCollection<TList> collection, PropertyChangedEventHandler handler) where TList : INotifyPropertyChanged
{
void Collection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
foreach (TList item in e.NewItems)
{
item.PropertyChanged += handler;
}
break;
case NotifyCollectionChangedAction.Remove:
foreach (TList item in e.OldItems)
{
item.PropertyChanged -= handler;
}
break;
default:
break;
}
}
return new Hook<TList>(collection, Collection_CollectionChanged);
}
public class Hook<TList> where TList : INotifyPropertyChanged
{
internal Hook(ObservableCollection<TList> collection, NotifyCollectionChangedEventHandler handler)
{
_handler = handler;
_collection = collection;
collection.CollectionChanged += handler;
}
private NotifyCollectionChangedEventHandler _handler;
private ObservableCollection<TList> _collection;
public void Unregister()
{
_collection.CollectionChanged -= _handler;
}
}
}
You can use it like this:
void Main()
{
var list = new ObservableCollection<Animal>();
list.RegisterPropertyChangeHook(OnPropertyChange);
var animal = new Animal(); // Has a "Name" property that raises PropertyChanged
list.Add(animal);
animal.Name="Charlie"; // OnPropertyChange called
list.Remove(animal);
animal.Name="Sam"; // OnPropertyChange not called
}
private void OnPropertyChange(object sender, PropertyChangedEventArgs e)
{
Console.WriteLine($"property changed: {e.PropertyName}");
}
If you want to be able to unregister the hook, do this:
var hook = list.RegisterPropertyChangeHook(OnPropertyChange);
hook.Unregister();
Unregistering ended up being trickier than I expected, due to extension method classes not supporting generics. It uses the "memento" pattern to return an object that you can use to unregister later.
To propagate notification from Model to Collection of Model, You need to have a Notifiable property in Collection itself.
Maybe you can extend the ObservableCollection and have a Property in that which can notify the UI
There's no way to get this for free unfortunately. I would create an IsBusy property on MainWindowViewModel. When Tabs is set, add a listener for collection changes and have that update the IsBusy property.

Update a ViewModel when an item in an observable collection is updated

Source code is here:
https://github.com/djangojazz/BubbleUpExample
The problem is I am wanting an ObservableCollection of a ViewModel to invoke an update when I update a property of an item in that collection. I can update the data that it is bound to just fine, but the ViewModel that holds the collection is not updating nor is the UI seeing it.
public int Amount
{
get { return _amount; }
set
{
_amount = value;
if (FakeRepo.Instance != null)
{
//The repo updates just fine, I need to somehow bubble this up to the
//collection's source that an item changed on it and do the updates there.
FakeRepo.Instance.UpdateTotals();
OnPropertyChanged("Trans");
}
OnPropertyChanged(nameof(Amount));
}
}
I basically need the member to tell the collection where ever it is called: "Hey I updated you, take notice and tell the parent you are a part of. I am just ignorant of bubble up routines or call backs to achieve this and the limited threads I found were slightly different than what I am doing. I know it could possible be done in many ways but I am having no luck.
In essence I just want to see step three in the picture below without having to click on the column first.
Provided that your underlying items adhere to INotifyPropertyChanged, you can use an observable collection that will bubble up the property changed notification such as the following.
public class ItemObservableCollection<T> : ObservableCollection<T> where T : INotifyPropertyChanged
{
public event EventHandler<ItemPropertyChangedEventArgs<T>> ItemPropertyChanged;
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs args)
{
base.OnCollectionChanged(args);
if (args.NewItems != null)
foreach (INotifyPropertyChanged item in args.NewItems)
item.PropertyChanged += item_PropertyChanged;
if (args.OldItems != null)
foreach (INotifyPropertyChanged item in args.OldItems)
item.PropertyChanged -= item_PropertyChanged;
}
private void OnItemPropertyChanged(T sender, PropertyChangedEventArgs args)
{
if (ItemPropertyChanged != null)
ItemPropertyChanged(this, new ItemPropertyChangedEventArgs<T>(sender, args.PropertyName));
}
private void item_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
OnItemPropertyChanged((T)sender, e);
}
}
You should do two things to get it to work:
first: you should refactor the RunningTotal property so it can raise the property changed event. Like so:
private int _runningTotal;
public int RunningTotal
{
get => _runningTotal;
set
{
if (value == _runningTotal)
return;
_runningTotal = value;
OnPropertyChanged(nameof(RunningTotal));
}
}
Second thing you should do is calling the UpdateTotals after you add a DummyTransaction to the Trans. An option could be to refactor the AddToTrans method in the FakeRepo
public void AddToTrans(int id, string desc, int amount)
{
Trans.Add(new DummyTransaction(id, desc, amount));
UpdateTotals();
}

ObservableCollection Collection Changed event not firing

I have an observable collection in my ViewModel, bound to a datagrid. I want to implement some logic for refreshing the data in other windows based on changes to the collection/ updates to the database (using LINQ to SQL).
Here is my view model code:
public FTViewModel(int JobID)
{
_windowCloseAction = new DelegateCommand(OnWindowClose);
_oFTrn = new ObservableFilesTransmitted(_dataDc, JobID);
_oFTrn.CollectionChanged += oFTrnCollectionChanged;
}
void oFTrnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.NewItems != null)
{
foreach (FilesTransmitted f in e.NewItems)
f.PropertyChanged += FilesTransmitted_PropertyChanged;
}
if (e.OldItems != null)
{
foreach (FilesTransmitted f in e.OldItems)
f.PropertyChanged -= FilesTransmitted_PropertyChanged;
}
}
void FilesTransmitted_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "DocumentNumber")
{
_filesTransmittedChange = true;
}
_refreshViews = true;
}
and the ObservableCollection constructor:
class ObservableFilesTransmitted : ViewableCollection<FilesTransmitted>
{
public ObservableFilesTransmitted(DocControlDC dataDc, int ID)
{
foreach (FilesTransmitted ftran in dataDc.FilesTransmitteds.Where(x=>x.JobID==ID).OrderByDescending(x => x.TransmittalName))
{
this.Add(ftran);
}
}
}
The debugger does not stop in the oFTrnCollectionChanged. I think because the call to create the observable collection happens before I add the CollectionChanged event. But obvously I can't switch those two lines. I've looked at various StackOverflow and CodeProject topics on this, and it seems like what I have should work. Do I need to add and remove a dummy item just to get the CollectionChanged hander called? What am I missing?
It seems like perhaps I should have a constructor (for the observable collection) that does not add any members, and a function that adds the members from the database. Then I can call new, add the collectionchanged handler, and then fill the collection. I am hoping to avoid that level of rewrite though, but perhaps it's the only reasonable way.
When I run in to this the easiest way to solve it is just subscribe manually at the start.
public FTViewModel(int JobID)
{
_windowCloseAction = new DelegateCommand(OnWindowClose);
_oFTrn = new ObservableFilesTransmitted(_dataDc, JobID);
foreach(var item in _oFTrn)
{
item.PropertyChanged += FilesTransmitted_PropertyChanged;
}
_oFTrn.CollectionChanged += oFTrnCollectionChanged;
}
However a even better solution is instead of using a class derived from ObserveableCollection<T> use a class derived from BindingList<T>. Any member raising their PropertyChanged event will cause the collection to raise ListChanged with the change type of ItemChanged
public FTViewModel(int JobID)
{
_windowCloseAction = new DelegateCommand(OnWindowClose);
_oFTrn = new ObservableFilesTransmitted(_dataDc, JobID);
_oFTrn.CollectionChanged += oFTrnListChanged;
}
void oFTrnListChanged(object sender, ListChangedEventArgs e)
{
if (e.ListChangedType == ListChangedType.ItemChanged)
{
if (e.PropertyDescriptor.Name == "DocumentNumber")
{
_filesTransmittedChange = true;
}
}
_refreshViews = true;
}
I have simply changed the ObservableCollection constructor and added a populate function:
New view model code:
public FTViewModel(int JobID)
{
_oFTrn = new ObservableFilesTransmitted(_dataDc, JobID);
_oFTrn.CollectionChanged += oFTrnCollectionChanged;
_oFTrn.FillCollection();
}
new ObservableCollection class:
class ObservableFilesTransmitted : ViewableCollection<FilesTransmitted>
{
DocControlDC _dc = null;
int _jobID = 0;
public ObservableFilesTransmitted(DocControlDC dataDc, int ID)
{
_dc = dataDc;
_jobID = ID;
}
public void FillCollection()
{
foreach (FilesTransmitted ftran in _dc.FilesTransmitteds.Where(x=>x.JobID==_jobID).OrderByDescending(x => x.TransmittalName))
{
this.Add(ftran);
}
}
}
And it all works as expected. But it gets called for each item added. I may play with the idea that I simply loop through the collection and add the propertychanged handler for each item in the viewmodel constructor. Seems like less of a performance hit that way.

Get changed item from CollectionChanged event using TrulyObservableCollection

I'm using a TrulyObservableCollection as a datasource in a WPF DataGrid. My class implements the PropertyChange event properly (I get notification when a property changes). The CollectionChanged event gets triggered as well. However, my issue lies in the connection between the PropertyChanged event and CollectionChanged event. I can see in the PropertyChanged event which item is being changed (in this case the sender object), however I can't seem to find a way to see which one is changed from within the CollectionChanged event. The sender object is the whole collection. What's the best way to see which item has changed in the CollectionChanged event? The relevant code snippets are below. Thank you for your help, and let me know if there needs to be some clarification.
Code for setting up the collection:
private void populateBret()
{
bretList = new TrulyObservableCollection<BestServiceLibrary.bretItem>(BestClass.BestService.getBretList().ToList());
bretList.CollectionChanged += bretList_CollectionChanged;
dgBretList.ItemsSource = bretList;
dgBretList.Items.Refresh();
}
void bretList_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
//Do stuff here with the specific item that has changed
}
Class that is used in the collection:
public class bretItem : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private int _blID;
public string _blGroup;
[DataMember]
public int blID
{
get { return _blID; }
set
{
_blID = value;
OnPropertyChanged("blID");
}
}
[DataMember]
public string blGroup
{
get { return _blGroup; }
set
{
_blGroup = value;
OnPropertyChanged("blGroup");
}
}
protected void OnPropertyChanged (String name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
}
TrulyObservableCollection class
public class TrulyObservableCollection<T> : ObservableCollection<T> where T : INotifyPropertyChanged
{
public TrulyObservableCollection()
: base()
{
CollectionChanged += new NotifyCollectionChangedEventHandler(TrulyObservableCollection_CollectionChanged);
}
public TrulyObservableCollection(List<T> list)
: base(list)
{
foreach (var item in list)
{
item.PropertyChanged += new PropertyChangedEventHandler(item_PropertyChanged);
}
CollectionChanged += new NotifyCollectionChangedEventHandler(TrulyObservableCollection_CollectionChanged);
}
void TrulyObservableCollection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.NewItems != null)
{
foreach (Object item in e.NewItems)
{
(item as INotifyPropertyChanged).PropertyChanged += new PropertyChangedEventHandler(item_PropertyChanged);
}
}
if (e.OldItems != null)
{
foreach (Object item in e.OldItems)
{
(item as INotifyPropertyChanged).PropertyChanged -= new PropertyChangedEventHandler(item_PropertyChanged);
}
}
}
void item_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
NotifyCollectionChangedEventArgs a = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset);
OnCollectionChanged(a);
}
}
EDIT:
In the item_PropertyChanged event the NotifyCollectionChangedEventArgs are set with NotifyCollectionChangedAction.Reset. This causes the OldItems and NewItems to be null, therefore I can't get the changed item in that case. I can't use .Add as the Datagrid is updated with an additional item. I can't appear to get .Replace to work either to get the changed item.
How about this:
In your ViewModel that contains the ObservableCollection of bretItem, the ViewModel subscribes to the CollectionChanged event of the ObservableCollection.
This will prevent the need of a new class TrulyObservableCollection derived from ObservableCollection that is coupled to the items within its collection.
Within the handler in your ViewModel, you can add and remove the PropertyChanged event handler as you are now. Since it is now your ViewModel that is being informed of the changes to objects within the collection, you can take the appropriate action.
public class BretListViewModel
{
private void populateBret()
{
bretList = new ObservableCollection<BestServiceLibrary.bretItem>(BestClass.BestService.getBretList().ToList());
bretList.CollectionChanged += bretList_CollectionChanged;
}
void bretList_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
if (e.NewItems != null)
{
foreach (Object item in e.NewItems)
{
(item as INotifyPropertyChanged).PropertyChanged += new PropertyChangedEventHandler(item_PropertyChanged);
}
}
if (e.OldItems != null)
{
foreach (Object item in e.OldItems)
{
(item as INotifyPropertyChanged).PropertyChanged -= new PropertyChangedEventHandler(item_PropertyChanged);
}
}
}
void item_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
var bret = sender as bretItem;
//Update the database now!
//One note:
//The ObservableCollection raises its change event as each item changes.
//You should consider a method of batching the changes (probably using an ICommand)
}
}
A Thing of Note:
As an aside, it looks like you are breaking the MVVM pattern based upon this snippet:
dgBretList.ItemsSource = bretList;
dgBretList.Items.Refresh();
You probably should consider loading your ViewModel and binding your View to it instead of coding logic in the code-behind of your View.
It's not appropriate to use the collection changed event in this way because it's only meant to be fired when adding/removing items from the collection. Which is why you've hit a wall. You're also in danger of breaking the Liskov substitution principle with this approach.
It's probably better to implement the INotifyPropertyChanged interface on your collection class and fire that event when one of your items fires its property changed event.

How can I raise a CollectionChanged event on an ObservableCollection, and pass it the changed items?

I have a class that inherits from ObservableCollection and adds a few additional methods such as AddRange and RemoveRange
My base method call is this:
public void AddRange(IEnumerable<T> collection)
{
foreach (var i in collection) Items.Add(i);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
My problem with this is that I want to access e.NewItems or e.OldItems in the CollectionChanged event to perform an action on whatever item is in the collection, and the NotifyCollectionChangedAction.Reset action does not pass in these values
void Instances_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.NewItems != null) // e.NewItems is always null
{
foreach (var item in e.NewItems)
{
if (item is EventInstanceModel)
((EventInstanceModel)item).ParentEvent = this;
}
}
}
So I thought I could just use the NotifyCollectionChangedAction.Add instead of Reset, however that throws a Range actions are not supported exception
public void AddRange(IEnumerable<T> collection)
{
var addedItems = collection.ToList();
foreach (var i in addedItems) Items.Add(i);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, addedItems));
}
So my question is, how can I raise a CollectionChanged event, and pass it the new or old item list?
I've been looking into it and apparently the CollectionChanged method cannot be raised with multiple items.
So I can call
OnCollectionChanged(new NotifyCollectionChangedEventArgs(
NotifyCollectionChangedAction.Add, singleItem));
but I can't call
OnCollectionChanged(new NotifyCollectionChangedEventArgs(
NotifyCollectionChangedAction.Add, listOfItems));
For now what I have done is simply raise the Add event for every item added, but I am still rather unhappy at this since it means I raise the CollectionChanged event for every item in the AddRange method instead of only once.
public void AddRange(IEnumerable<T> collection)
{
foreach (var i in collection)
{
Items.Add(i);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(
NotifyCollectionChangedAction.Add, i));
}
}
This works fine for me "stand-alone". Meaning I'm not using an ObservableCollection for data binding. So it's not an ObservableCollection issue but rather a ListCollectionView limitation.
Please read the following article, it's a very interesting read:
Nathan Nesbit's Blog
Your post says: My problem with this is that I want to access e.NewItems or e.OldItems in the CollectionChanged event to perform an action on whatever item is in the collection, and the NotifyCollectionChangedAction.Reset action does not pass in these values.
We're not "stuck" with that behavior, however, because (as many things OOP) if you don't like how something works, you can inherit it to make a custom event that behaves the way you want it to. Example: This custom class inherits from NotifyCollectionChangedEventArgs and I've changed its behavior so that NotifyCollectionChangedAction.Reset does pass in the changed values. (In this case I made a new list named RemovedItems to avoid confusion but one is free to modify existing collections like NewItems or OldItems as well.) I use it in production code and it works well for me.
public class NotifyCollectionResetEventArgs : NotifyCollectionChangedEventArgs
{
public NotifyCollectionResetEventArgs(List<object> removedItems)
: base(action: NotifyCollectionChangedAction.Reset)
{
RemovedItems = removedItems.ToList();
}
public List<object> RemovedItems { get; }
}
The class that inherits ObservableCollection overrides the Clear method:
public class ObservableAttributeValueCollection : ObservableCollection<object>
{
List<object> _removedItems = null;
public new void Clear()
{
_removedItems = Items.ToList<object>(); // 1. Capture the items.
base.Clear(); // 2. Clear the items
_removedItems = null; // 3. Clean up
}
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
if(e.Action == NotifyCollectionChangedAction.Reset)
{
base.OnCollectionChanged(new NotifyCollectionResetEventArgs(_removedItems));
}
else
{
base.OnCollectionChanged(e);
}
}
}
Finally, consuming this event in a handler uses the 'is' pattern to assign the ePlus variable.
void handleCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
switch (e.Action)
{
case NotifyCollectionChangedAction.Reset:
if (e is NotifyCollectionResetEventArgs ePlus)
{
foreach (var item in ePlus.RemovedItems)
{
// Do Something
}
}
break;
}
}

Categories