Skip Navigation LinksHome > View Post

Model-View-ViewModel and Animation

Anyone who's seen one of my WPF presentations will likely know I'm a huge fan of Model-View-ViewModel (M-V-VM) and a total code-behind hater.

Whilst my approach to M-V-VM is something I hope to discuss in much more detail on this blog in the near future, I want to talk about a particular interesting scenario I discussed with a customer recently.

In this scenario there was a quiz like application that asked the user a question, accepted an answer that the user types in and then evaluates the answer as correct or incorrect. Sounds like a doddle so far.

The interesting part of this scenario came when the customer wanted to introduce two animations: one that played for a correct answer and one that played when the answer given was incorrect. When the animation has finished playing, we would then move on to the next question. In my experience animation can be a sticky area for M-V-VM and it is certainly harder to create a visual-agnostic ViewModel.

In some scenarios it's necessary to fallback to a more Model-View-Presenter (MVP) style interaction with lots of "left-hand, right-hand" code to poke back and forth between the View and the Presenter (or ViewModel). There are a couple of ways to spin this including having the View call a number of methods on the Presenter or have an interface that allows the Presenter to access certain methods or properties on the view. Both require a fair bit of code-behind and inherently make the Presenter (or ViewModel) much more visually aware.

By visually aware I mean that the ViewModel has become a specific implementation that is very customised for one particular implementation of that view. I always try to avoid this and create a 'canonical' ViewModel. Obviously, this is a balancing act but in most cases it's incredibly effective and allows me to reskin (via different Xaml) a screen incredibly effectively without touching the ViewModel (converters can come in very handy here). I clearly differ greatly in my interpretation of M-V-VM from Josh Smith. I hope to talk about this more in the future.

So, how can we have a more 'canonical' ViewModel and support animation? Firstly, I don't think there is a single correct answer to this and it varies depending on what you need to do. Which is good because that requires some design (in the patterns sense) which is fun, right?

Here's how I think you might tackle this scenario, and this is the shape of the ViewModel:

// some code snipped for brevity, class INotifyPropertyChanged properties
public class ViewModel : INotifyPropertyChanged
{
    public string Question { /* snip */ }
    public string Answer { /* snip */ }
    public QuestionState QuestionState { /* snip */ }
    public ICommand SubmitAnswer { /* snip */ }
    public ICommand NextQuestion { /* snip */ }
}

public enum QuestionState
{
    Unanswered, Correct, Incorrect
}

The ViewModel has very simple responsibilities. Load up the first question and set the Question property. When the SubmitAnswer command is executed the ViewModel needs to read the Answer property (set via Binding, of course) and evaluate whether it's correct. This evaluation would then be reflected by changing the QuestionState from Unanswered to Correct or Incorrect. The NextQuestion command is responsible for loading the next question.

So, how do we start the animation when the QuestionState changes? Easy, with a DataTrigger* bound to the QuestionState.

<DataTrigger Binding="{Binding QuestionState}" Value="Correct">     
    <DataTrigger.EnterActions>
        <BeginStoryboard>

And we'd need another trigger for the 'Incorrect' state. That's easy.

Now we could have the user press a button to request the next question (by binding the Button's Command property to our NextQuestion property) or, if we want to do it automatically, we could add an event handler to the Storyboard's Completed event.

    <Storyboard Completed="StoryboardCompleted">

Now, this requires a little code-behind (boo) but only a smidge:

    private void StoryboardCompleted
    {
        if (_viewModel.NextQuestion.CanExecute())
        {
            _viewModel.NextQuestion.Execute();
        }
    }

You could even get rid of the code-behind entirely by writing an attached behaviour that executes a bound ICommand when a storyboard completes.

If this makes no sense to you at all and you'd like to find out more about M-V-VM and then leave a comment and I'll try and move that content forward in my pipeline a bit.

* A common difficulty with DataTriggers is that they're only supported in a limited number of scenarios. Specifically in a Style (a Style's Triggers property accepts a DataTrigger) and inside a DataTemplate. To do what we want here we'll want to use a DataTrigger inside a DataTemplate and this is easy enough. Just define your DataTemplate (perhaps in your resources) and add a ContentPresenter where you want this template to be used. Set the ContentTemplate property of the ContentPresenter to your new DataTemplate. Finally, if you want your DataTemplate to use the current DataContext you'll need to wire this up.

<ContentPresenter ContentTemplate="{StaticResource myTemplate}" Content="{Binding}" />

This is a useful technique for breaking up your Xaml and a great way to introduce DataTriggers into the WPF bargain.

Tags: MVVM WPF

 
Josh Post By Josh Twist
2:15 AM
31 Dec 2008

» Next Post: WebTests expose silly security vulnerability
« Previous Post: The file '/default.aspx' has not been pre-compiled, and cannot be requested.

Comments are closed for this post.

Posted by Josh Smith @ 05 Jan 2009 6:45 AM
Nice post, Josh. I love seeing more MVVM goodness out there.

In reference to "how I interpret MVVM" (according to this post), I must say that my interpretation is fluid and frequently changing. One of the downsides to having online conversations, that are publicly visible, is that it's easy for others to then assume that whatever you happen to have thought on that day is "the way you see things." Ironically, the primary benefit of having those conversations is to promote new ways of thinking about some topic! :)

Thanks,
Josh

Posted by Brent Schooley @ 11 Jan 2009 5:26 PM
This is a very neat approach. The VisualStateManager that is coming in .NET 4.0 will clean this up even more. You can get the VisualStateManager now through the WPF Toolkit but as I point out on my blog(http://www.codesnack.com/2009/01/08/wpf-toolkit-is-not-ready-for-production-applications/), I don't recommend it at this point. The VSM would allow you to create these Unanswered, Correct, and Incorrect states for the view and then visually create the animations in Blend. Then, you could have the ViewModel set the state of the view.

Posted by Tyson Stolarski @ 13 Feb 2009 1:34 AM
Hi Josh.
Nice article, Im attempting the exact same thing, and came up with the same solution, but damn DataTriggers are not flexible enough!

I use ContentPresenters and bind their Content to a property on the current ViewModel instance that returns another IViewModel implementation. I then define DataTemplates for the various expected IViewModel implementations. However, I rarely define the template in-line, and instead just map it to another UserControl (Which gives good Blend support). This then leads me to the same problem of not being able to define DataTriggers within my UserControls (even though the only place those UserControls are instantiated is within a DataTemplate).

Any ideas? Do you know if DataTriggers will have better support in future versions?

And Brent, I like your thought path there - my only concern is that you would want to Bind the View's state to a ViewModel property, not have the ViewModel set the Views state (That is MVP). I have only briefly touched on the VSM in some silveright stuff, is that possible with VSM?

Cheers.
Tyson.

Posted by Paul Riddington @ 04 Mar 2009 5:55 AM
I have read a lot about the MVVM pattern and I like it. The one thing I don't like about it is the name! I believe it came from the brains behind Expression Blend but surely that much combined brain power could've come up with a better name? When I am trying to explain the "Model View Controller" or "Model View Presenter" pattern they are relatively easy to explain but "Model-View-ViewModel"...give me a break!

Posted by Christo Zietsman @ 11 May 2009 2:58 AM
Hi Josh.

Your article sounds very promising. I've been wonder how to do exactly the same thing for a while now.

I'm trying to create a working example, but I'm running into a few problems. It seems that the Completed event never gets fired. I know the storyboard runs, because I'm seeing the opacity change on a label I've added to my example.

Is there a chance you could post a simple example which works? It would be greatly appreciated.

Thanks,
Christo

Posted by Christo Zietsman @ 11 May 2009 4:48 AM
Oh joy ;-)

I've found a workaround. It seems that if the storyboard is defined inside the datatemplate's resources then it doesn't work, but if we've got a storyboard defined in the resource section of the containing element then it does work.

The intricacies of WPF can sometimes be daunting.

Sorry for the scare...

Posted by jbe @ 04 Jul 2009 9:46 AM
Hi Josh,

Great post. I encountered other scenarios where it’s impossible to go along without code in the code-behind file. Often it’s because a WPF Control doesn’t support data binding on a specific property (e.g. PasswordBox.Password).

I still use the M-V-VM pattern and include an interface for the view which can be accessed by the ViewModel. You are right, my ViewModels are specific for one view and cannot be reused but they don’t use any WPF specific constructs.

Interested in more concrete details? Then you might have a look at the project:

WPF Application Framework (WAF)
http://waf.codeplex.com

© 2005 - 2014 Josh Twist - All Rights Reserved.