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.