views:

801

answers:

2

I'm having a right barney getting my head around how everything fits together using the MVVM pattern. It all seems quite simple in practice but trying to implement it I seem to be breaking various other rules that I try to code by.

Just as a side note, I'm trying to implement the pattern using Flex, not Silverlight or WPF, so if anyone can come with good reasons why this shouldn't be done, then I'd like to hear them.

I have a problem where I have several views. Sometimes I have to display two views on the page at the same time; sometimes I switch back to a single view. In my normal Flex brain I would have a main view with a code-behind which contained all my other views (equally with code-behinds). That main view would then do the switching of the other individual views.

When I try to implement this in MVVM I'm trying to stick to the principles of MVVM by using binding which decouples my Views from the ViewModels. Let's say I create a ViewModel for application-wide state and my ApplicationView binds to that data and does all the switching of the sub views.

Now, where should I create my view models for my subviews? I've tried inside the ApplicationView -- that didn't seem right. And then I've tried outside of the application view and passing and instance of it into the ApplicationView and then my sub models a bind to it. Am I missing something? None of these methods seem to fit the whole point of trying to decouple this.

Any good books or links that explain this problem would be much appreciated.

Cheers, James

+3  A: 

I've seen variants of the MVVM approach used on a couple different Flex projects, but I haven't seen an approach that feels perfectly right to me. That said, I think using Presentation Models makes testing in Flex a lot easier, so I'm pretty sure that there will start to be more applications designed around this pattern.

The easiest approach I've seen to implementing MVVM in Flex is to place the individual ViewModels within the application Model / ModelLoactor. The ModelLoactor contains any global data and also serves as an accessor to all ViewModels. ApplicationViews can then bind to their particular ViewModel through the ModelLocator, while ViewModels can be updated both through Commands and through bindings to their parent ModelLocator. One benefit of this approach is that all of the data logic is localized; of course, this could also be seen as a drawback, with the central ModelLocator being a touch brittle due to its hard coded references to all ViewModels.

I've seen cleaner approaches work by using the Mate framework. Mate allows for a much more decentralized injection of ViewModels into the appropriate ApplicationViews. (I suppose this could also be accomplished with Swiz, I'm just not as familiar with that framework). With Mate, each ApplicationView has its ViewModel injected via a Map. What's cool with this approach is how ViewModels can be updated using an EventMap (the Mate version of a FrontController). Essentially, your ApplicationViews will dispatch events that are handled by one or more EventMaps, and these Maps can then make changes to one or more of the ViewModels. This approach allows for a user gesture or event from one ApplicationView to change the state of several ViewModels at once. In addition, because this logic is extracted into Mate's EventMaps, it's very easy to change how events are handled or which ViewModels are changed. Of course, the major drawback of this approach is that you're committing to using Mate as a framework, which may not be an option depending on the requirements of the project.

I hope that helps!

jmreidy
+6  A: 

The approach you are referring to is ViewModel composition. Its where you have multiple complex view parts that need to bind to their own ViewModel entity. The approach entails constructing a root ViewModel with properties for each child ViewModel. Then the root View is bound to the root View Model and each View (whether displayed or collapsed) is bound to the corresponding property on the root ViewModel.

The ViewModel would look like this:

public class RootViewModel 
{
   ChildViewModelA ChildA { get; set; }
   ChildViewModelB ChildB { get; set; }
}

The View would look like this:

<Grid>
   <ChildViewA DataContext="{Binding ChildA}" />
   <ChildViewB DataContext="{Binding ChildB}" />
</Grid>

You could also implement this in away to allow yourself to select an active workspace.

The ViewModel would look like this:

public class RootViewModel 
{
   public List<ViewModel> ChildWorkspaces { get; set; }
   public ViewModel ActiveWorkspace { get; set; }

   public RootViewModel() 
   {
      ChildWorkspaces.Add(ChildViewModelA);
      ChildWorkspaces.Add(ChildViewModelB);
   }
}

The View would look like this:

<Grid>
   <Grid.Resources>
      <DataTemplate DataType="ChildViewModelA">
          <ChildViewA />
      </DataTemplate>
      <DataTemplate DataType="ChildViewModelB">
          <ChildViewB />
      </DataTemplate>
   </Grid.Resources>
   <ContentControl Content="{Binding ActiveWorkspace}" />
</Grid>

This will result in the appropriate visual representation being selected implicity based on the type of the actual object stored in ActiveWorkspace.

Pardon my response was in WPF. I tried my hardest to not get caught up in the syntax of it all :-)

As you can see the plurality of "ViewModel" can be ambiguous. Often times we find the need to construct multiple sub-entities to structure the ViewModel appropriately. But all ViewModel entities would be somewhere within the root View Model object.

When implementing MVVM in WPF, I prefer to infer what visual element to apply data context implicitly (as illustrated in the later half of this response). In more complex scenarios I prefer to use a DataTemplateSelector to conduct that decisioning. But in super simple cases you can explicitly apply DataContext either imperatively in C#/ActionScript or declaratively through bindings.

Hope this helps!

markti
OK so i think this has cleared up my confusion as i wasn't sure if the Views should contain a reference to the view model which is how you describe in the first eg. Going to leave this as open for a few days to see if any one else comments but this is basically what i was after. thanks
James Hay
The only "references" the view should have to the ViewModel should be declarative bindings. The goal with MVVM is to have both the View and the ViewModel be agnostic of each other.
markti