views:

118

answers:

2

I have a simple app that consists of:

Model

  • Items
  • Filter criteria applied to that list of items

Views

  • WelcomePage
  • MainItemsPage
  • FilterEditPage

I am using MVVM Light and Windows Phone 7

I currently have 3 ViewModels, one for each View. In the past I have had a single ViewModel which made the comunication which I am about to ask about very easy. However I wanted to go with the 3 seperate VMs as that seems to be the correct way.

The WelcomePage is able to set one of the Filter criteria before navigating to the MainItemsPage. The MainItemsPage is bound to an Items property that is exposed by its ViewModel. That ViewModel needs to have filtered that list depending on the current filter criteria. The FilterEditPage allows the user to edit the full criteria set of 4 variables. When the criteria is changed the Items collection used in the ViewModel for MainItemsPage needs to be refiltered.

The question is how I flow the Filter changes through the app. I know that MVVM has the concept of Messaging and the MVVM Light toolkit provides the Messenger class. However what I am struggling with is where does the responsibility lie for sending those messages?

  1. Do the 3 VMs go to the Model whenever they need to work with the current Filter set?
  2. Do all Filter updates go through the FilterEditViewModel and that in turn broadcasts a filter change message?
  3. Do I go back to a single VM for all the Views?

I cannot see 1. working because something will need to trigger the VMs to go back to the Model I know I can get 3. working right now with no problem. Is it that wrong?

TIA

Pat Long

A: 

Three VMs is the right way in your scenario. I suggest you to build a Parent/Child relation between you VMs. Since the the MainVM holds the ItemList, this is the place, where FilterChanges are applied. The FilterEditVM only receives the filter changes and than calls the MainVM, that it has to re-apply the filters.

The structure would be something like this:

public class WelcomePageVM
{
    public WelcomePageVM()
    {
        this.FilterEditPageVM = new FilterEditPageVM(this);
        this.MainItemsVM = new MainItemsVM(this);
    }

    public FilterEditPageVM FilterEditPageVM { get; private set; }

    public MainItemsVM MainItemsVM { get; private set; }

    public void SetInitialFilter1(object filter)
    {
        // the initial filter
        this.FilterEditPageVM.Filter1Value = filter;
        this.MainItemsVM.ApplyFilters();
    }
}

public class FilterEditPageVM : ChildViewModelBase<WelcomePageVM>
{
    public FilterEditPageVM(WelcomePageVM parent)
        : base(parent) { }

    public object Filter1Value { get; set; }
    public object Filter2Value { get; set; }
    public object Filter3Value { get; set; }
    public object Filter4Value { get; set; }

    public void FinishFilterChange()
    {
        this.Parent.MainItemsVM.ApplyFilters();
    }
}

public class MainItemsVM : ChildViewModelBase<WelcomePageVM>
{
    public MainItemsVM(WelcomePageVM parent)
        : base(parent) { }

    public List<object> ItemList { get; set; }

    public void ApplyFilters()
    {
        // filter apply logic
    }
}

public abstract class ChildViewModelBase<T>
{
    T _parent;

    public ChildViewModelBase(T parent)
    {
        this._parent = parent;
    }

    public T Parent { get { return _parent; } }
}

Here you can access all viewmodels, which is okay because you stay in the "controller" level.

JanW
P.S: Added FinishFilterChange() to FilterEditVM
JanW
Thanks. I can see all that working but it just seems wrong that the little old WelcomePage is the Parent but I think that is me getting caught up in some misunderstanding and misapplication of semantics. Have you put WelcomePage as the Parent because it is the first screen(view) loaded?
Pat Long - Munkii Yebee
Exactly. Of course, with the above pattern you can freely chose your root. But I recommend to use the first View as your root, because its sensefull, if your controller model represents the ways you can follow on the GUI. If you review your App after some time, it is easier to understand the workflow. If you dont like your welcome page as root, i suggest you to build another real RootView, in which you switch your three other views. This particular RootView will then possess all three above ViewModels.
JanW
A: 

I would put the shared current filter in the Model not the view model. You've got lots viewModels potentially on different pages or on the same page (consider a breadcrumb showing current selection and something else that needs to show a filter has been applied).

How about a singleton model for the Filter that view models can subscribe to?

LittleColin