Everything needs a ViewModel – CollectionViewModel

CollectionViewModelThe title is a little misleading; but everyone loves generalisations and WPF. 😉
It may have been better named view-first decomposition or something similarly benign.

One of the big issues people face when implementing MVVM is collections (example, example), primarily how do I keep my model in sync. 

The reason; IMO, is that people tend to compose their ViewModels based on the models they are trying to display on-screen. Whilst this is not a bad idea (mainly because screens tend to be modelled on the models as well 🙂 ) solutions often come from a design-first approach whereby your ViewModels represent parts of the screen (not necessarily parts of the model or only a single model).

As an example take a Customer who has a collection of Addresses. When we create ViewModels based on the Model we tend to only see our objects i.e. Customer and Address. When we see a collection the first reaction is whack in a ObservableCollection.

 When creating the view that contains a collection it will often be displayed as some type of ItemsControl. The ItemsControl will often contain buttons for Adding, Deleting, Moving etc. When we look at it from the perspective of screen decomposition it becomes much clearer that there is some list component there which needs a ViewModel.

Once we come to this realisation the CollectionViewModel becomes self-evident. It’s responsibility is to maintain the underlying model; when a ViewModel is deleted from the collection it deletes the corresponding model from the underlying collection, same for add and move. I do this by listening to CollectionChanged event and providing the collection with mapping methods between ViewModel and Model.

protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
        {
           base.OnCollectionChanged(e);

  if (SyncIsDisabled)
                return;

            switch (e.Action)
            {
                case NotifyCollectionChangedAction.Add:
  foreach (var item in e.NewItems)
  AddToModel((TViewModel)item);
                    break;

                case NotifyCollectionChangedAction.Remove:
  foreach (var item in e.OldItems)
  RemoveFromModel((TViewModel)item);
                    break;

                case NotifyCollectionChangedAction.Reset:
                    underlyer.Clear();
                    break;

            }
        }

So when decomposing screens or models into ViewModels; or when you encounter an issue with a design, double-check everything is a ViewModel.

Advertisements
Tagged , , , ,

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: