How to implement INotifyCollectionChanged in MVVM for Reset, Add,Remove,Move,Replace of NotifyCollectionChangedAction

mvvm, observablecollection, silverlight, wpf, xaml

Solution

Typically, a view model would not implement the `INotifyCollectionChanged` interface... that is for collection classes to implement. I have a massive WPF project and I haven't needed to implement that interface once.

I generally use custom collection classes that extend `ObservableCollection<T>` and these collections already implement the `INotifyCollectionChanged` interface. Therefore, when I need to display collections, I just add properties for these collections in my view model classes. If I then need to monitor changes in the collection, I would add a handler for the `CollectionChanged` event.

This is not something that can be built into the base view model unless you are certain that every view model will have a collection of a particular type. Even then, what would you do when you need more than one collection in a view model? You'd have to add a collection property and extra handlers, so why don't you just do that whenever you need to?

Problem

My ViewModelBase class is: ``` public abstract class ViewModelBase:INotifyPropertyChanged, IDisposable, INotifyCollectionChanged { #region Constructor protected ViewModelBase() { } #endregion // Constructor #region DisplayName /// <summary> /// Returns the user-friendly name of this object. /// Child classes can set this property to a new value, /// or override it to determine the value on-demand. /// </summary> public virtual string DisplayName { get; protected set; } #endregion // DisplayName #region Debugging Aides /// <summary> /// Warns the developer if this object does not have /// a public property with the specified name. This /// method does not exist in a Release build. /// </summary> [Conditional("DEBUG")] [DebuggerStepThrough] public void VerifyPropertyName(string propertyName) { // Verify that the property name matches a real, // public, instance property on this object. if (TypeDescriptor.GetProperties(this)[propertyName] == null) { string msg = "Invalid property name: " + propertyName; if (this.ThrowOnInvalidPropertyName) throw new Exception(msg); else Debug.Fail(msg); } } /// <summary> /// Returns whether an exception is thrown, or if a Debug.Fail() is used /// when an invalid property name is passed to the VerifyPropertyName method. /// The default value is false, but subclasses used by unit tests might /// override this property's getter to return true. /// </summary> protected virtual bool ThrowOnInvalidPropertyName { get; private set; } #endregion // Debugging Aides #region INotifyPropertyChanged Members /// <summary> /// raised when property of this object has some new value /// </summary> public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged(string propertyName) { PropertyChangedEventHandler handler = this.PropertyChanged; if (handler != null) { var e = new PropertyChangedEventArgs(propertyName); handler(this, e); } } #endregion #region IDisposable Members public void Dispose() { this.OnDispose(); } /// <summary> /// child classes can override this method to perform cleanup logic,like removing eventhandlers and disposing objects /// Anindya /// </summary> protected virtual void OnDispose() { //no implementation has been done here //intentionhally I have done so //so that this method will be only used for the overriding of this method //by default nothing I have kept in this method } #endregion #region INotifyCollectionChanged Members /// <summary> /// Occurs when an item is added, removed, changed, moved, or the entire list is refreshed. /// </summary> public event NotifyCollectionChangedEventHandler CollectionChanged; protected virtual void OnCollectionChanged(CollectionChangeEventArgs ccevent) { //NotifyCollectionChangedEventHandler handler = this.CollectionChanged; //if (handler != null) //{ // var e = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction //} } #endregion } ``` and my WorkSpaceViewModel is inheriting from ViewModelBase as followes: ``` public abstract class WorkspaceViewModel:ViewModelBase { #region Fields RelayCommand _closeCommand; #endregion // Fields #region Constructor protected WorkspaceViewModel() { } #endregion // Constructor #region CloseCommand /// <summary> /// Returns the command that, when invoked, attempts /// to remove this workspace from the user interface. /// </summary> public ICommand CloseCommand { get { if (_closeCommand == null) _closeCommand = new RelayCommand(param => this.OnRequestClose()); return _closeCommand; } } private void CanDoSomeImportantMethod() { } #endregion // CloseCommand #region RequestClose [event] /// <summary> /// Raised when this workspace should be removed from the UI. /// </summary> public event EventHandler RequestClose; void OnRequestClose() { EventHandler handler = this.RequestClose; if (handler != null) handler(this, EventArgs.Empty); } #endregion // RequestClose [event] } ``` My ViewModel is inheriting from WorkSpaceViewModel as followes: ``` public class MainWindowViewModel:WorkspaceViewModel,INotifyCollectionChanged { // RelayCommand _loadCommand; MatchBLL matchBLL = new MatchBLL(); EfesBetServiceReference.EfesBetClient proxy = new EfesBetClient(); public MainWindowViewModel() { _matchObsCollection = new ObservableCollection<EfesBet.DataContract.GetMatchDetailsDC>(); Load(); _matchObsCollection.CollectionChanged += new NotifyCollectionChangedEventHandler(_matchObsCollection_CollectionChanged); } /// <summary> /// This will get called when the collection is changed(for reference see http://stackoverflow.com/questions/1427471/observablecollection-not-noticing-when-item-in-it-changes-even-with-inotifyprop) /// </summary> /// <param name="sender"></param> /// <param name="e"></param> void _matchObsCollection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { } protected override void OnPropertyChanged(string propertyName) { base.OnPropertyChanged(propertyName); } public ICommand LoadCommand { get { if (_loadCommand == null) { _loadCommand = new RelayCommand( param => this.Load(), param => this.CanLoad ); } return _loadCommand; } } List<EfesBet.DataContract.GetMatchDetailsDC> matchList; ObservableCollection<EfesBet.DataContract.GetMatchDetailsDC> _matchObsCollection; public ObservableCollection<EfesBet.DataContract.GetMatchDetailsDC> MatchObsCollection { get { return _matchObsCollection; } set { _matchObsCollection = value; OnPropertyChanged("MatchObsCollection"); } } public void Load() { matchList = new List<GetMatchDetailsDC>(); matchList = proxy.GetMatch().ToList(); foreach (EfesBet.DataContract.GetMatchDetailsDC match in matchList) { _matchObsCollection.Add(match); } //ajebaje code PopulateSahibiKonuk(); } bool CanLoad { get { return true; } } #region INotifyCollectionChanged Members public event NotifyCollectionChangedEventHandler CollectionChanged; #endregion ``` Now I am having a `DataGrid` in UI and I want OnCollectionChanged of my `ObservableCollection`. How NotifyCollectionChangedAction like add, move, remove, replace, reset my viewmodel should fire. But I do not know how to implement or what I have to do in my base classes or in my viewmodel. Please provide me some useful code or urls or suggestion regarding this. Thanking you in advance.

Original source

Related problems