Skip to content
November 15, 2009 / Thomas Danemar

Using the VisualStateManager with the Model-View-Viewmodel (MVVM) pattern in WPF or Silverlight

The visual state manager is a powerful addition to WPF 4.0 that facilitates handling state visuals for WPF and Silverlight controls. For example, a button control could have the states “Pressed”, “Normal”, “Disabled”, etc., and have different looks for each of those states, with transitions between them. If you’re unfamiliar with the Visual State Manager, check out the Visual State Manager Overview, or ScottGu’s post.

The Visual State Manager is already a part of Silverlight 2, and will be in WPF 4.0. You can, however, use it already if you download the official WPF Toolkit.

Now, as nice as the VisualStateManager (VSM) is, anyone who has tried to use it with the Model-View-Viewmodel (MVVM) or Model-View-Presenter (MVP) will have run into some issues. The big showstopper is that to change states using the VSM, you have to pass the view as an argument:

VisualStateManager.GoToState(View, stateName, true);

If you’re using the MVP pattern, this is okay, since your presenter will likely be aware of the view. For example, if you’re using Caliburn (which, by the way, is an awesome framework for MVP or MVVM), you can do something like this:

private object View { get; set; }
public override void ViewLoaded(object view, object context)
{
	View = view;
	base.ViewLoaded(view, context);
}

private void ChangeStateTo(string stateName)
{
	Application.Current.Dispatcher.Invoke((System.Action) (delegate()
	{
		VisualStateManager.GoToState((Control)View, stateName, true);
	}), null);
}

This works just fine. But if you’re using MVVM this isn’t really a solution, since the viewmodel should not have to know about the view. Also, ideally you’d like to bind your visual state to a property on the presenter/viewmodel. Unit testing states will also be difficult like this.

The solution lies in WPF’s attached properties (ooh, don’t we just love those?). We’ll create a helper class with a VisualState depencency property, and in the PropertyChangedCallback method for that property we’ll pass the sender (which will be our view) and the new property value (which will be the name of the state) to the VisualStateManager:

public class StateManager : DependencyObject
{
	public static string GetVisualStateProperty(DependencyObject obj)
	{
		return (string)obj.GetValue(VisualStatePropertyProperty);
	}

	public static void SetVisualStateProperty(DependencyObject obj, string value)
	{
		obj.SetValue(VisualStatePropertyProperty, value);
	}

	public static readonly DependencyProperty VisualStatePropertyProperty =
		DependencyProperty.RegisterAttached(
		"VisualStateProperty",
		typeof(string),
		typeof(StateManager),
		new PropertyMetadata((s, e) =>
		{
		var propertyName = (string)e.NewValue;
		var ctrl = s as Control;
		if (ctrl == null)
			throw new InvalidOperationException("This attached property only supports types derived from Control.");
		System.Windows.VisualStateManager.GoToState(ctrl, (string)e.NewValue, true);
	}));
}

Now in XAML we can bind the VisualStateName string property on our viewmodel to our new helper class:

<UserControl x:Class="MyApp.SomeView"
//namespaces omitted for brevity
MyApp:StateManager.VisualStateProperty="{Binding VisualStateName}">

And that’s it! Our helper class will switch states on the view for us. The viewmodel no longer has to be aware of the view, and unit testing states becomes a lot easier.

About these ads

20 Comments

Leave a Comment
  1. Weidong Shen / Feb 19 2010 03:13

    Thanks! I was looking for a solution to this too. Cannot believe Microsoft designed VSM without MVVM in mind.

  2. Brett Styles / Mar 27 2010 23:15

    Hi Thomas, that works perfectly. Do you have any licence restrictions on us using that solution?

    • Thomas Danemar / Mar 28 2010 00:31

      Hi Brett! Of course not, go ahead and use it. Glad you’re finding it useful!

  3. Vinney / Nov 17 2010 20:26

    I must be missing something, I’m attempting to implement the StateManager class in a SL4 app but the states don’t seem to be changing. As far as I can tell, I’ve doen everything exactly as you’ve indicated here. Should I have to do anything different to make this work in a SL4 app? Was there anything left out?

    Thanks,
    Vinney

  4. Vinney / Nov 17 2010 21:25

    As it turns out, I built my visual states incorrectly. I threw a couple buttons on the page to test the visual state transitions and came to realize my core problem! After fixing the animations, the StateManager worked like a charm. Thanks a ton. I’m actually a bit surprised that the MVVM Light toolkit doesn’t contain a similar class…

  5. Steve Ives / Feb 17 2011 23:07

    Excellent example, thanks. I think I am 99% of the way there, but I when I try to do the binding in my View (in XAML) I get an error “A ‘Binding’ cannot be used within a ‘UserControl’ collection. A ‘Binding’ can only be set on a DependencyProperty of a DependencyObject”. Can you confirm exactly where and how you bind the VisualStateName property in the StateManager class to the Property in the ViewModel?

  6. Yeah / May 5 2011 19:44

    It is possible to use this to change a visual state of a control instead a view?

  7. kbo4sho / Jun 28 2011 04:13

    Thanks man, big help.

  8. Steven Picken / Jul 12 2011 02:55

    Whenever I do stuff with Silverlight, I try to avoid codebehind like the plague (personal preference). Believe it or not, the VSM can work quite well with MVVM using triggers.

    The unfortunate Gotcha is that xmlns:i and xmlns:ei come from
    xmlns:i=”http://schemas.microsoft.com/expression/2010/interactivity” and xmlns:ei=”http://schemas.microsoft.com/expression/2010/interactions” respectively which implies a reliance on Blend perhaps. I haven’t looked into it I just know that it works for me.

    So, a little explanation. The PropertyChangedTrigger fires when the Binding “Ready” changes. On it’s own, it doesn’t discriminate between what it was changed to, hence the ComparisonCondition to ensure that the state only changes when Ready changes to ‘true’
    After that, GoToStateAction will cause the ApplicationReady state to fire. If you need to change the state of a specific object, you can use the TargetObject of GoToStateAction to specify which receives the state change.

    Cheers,
    Steven Blom

  9. Steven Picken / Jul 12 2011 02:55

    Nuts, it buchered my xaml…

  10. Maxim V. Pavlov / Aug 19 2011 19:35

    It seems like I need help with this one.

    I have a button, for which I want to control the state. Buttons’ Style property is set to {StaticResource RoundPlay}

    Style RoundPlay defines the following custom state:

    Where do I add MyApp:StateManager.VisualStateProperty=”{Binding PlayingState}”>?
    How can I toggle my button to transition to this state from code?

    Thank you.

  11. Maxim V. Pavlov / Aug 19 2011 19:38

    It seems like I need help with this one.

    I have a button, for which I want to control the state. Buttons’ Style property is set to {StaticResource RoundPlay}

    Style RoundPlay defines the following custom state:

    VisualStateGroup x:Name=”PlayStates”
    VisualState x:Name=”PlayingState”

    (tags’ opening and closing brackets are omitted in both cases because of the comments filter)

    Where do I add MyApp:StateManager.VisualStateProperty=”{Binding PlayingState}”>?
    How can I toggle my button to transition to this state from code?

    Thank you.

  12. Maxim V. Pavlov / Aug 19 2011 19:48

    Got it. The binding expression should be to added to a buttons declaration and should be liked to a string property in a view model. That is important for understanding, but isn’t mentioned anywhere. You can go ahead and delete my questions altogether. Sorry for flooding =)

  13. Pravin / Oct 17 2012 16:13

    Thanks, you have saved my day

  14. Abhishek Shukla / Mar 24 2014 18:49

    Thanks a lot Thomas. Its is useful!

Trackbacks

  1. Working with MvvmLight and Ninject cool extensions « Mariano Ravinale's Blog
  2. VisualState Binding threading problem | Technical support, Computer, programming issue, issue tracking, quality assurance
  3. Visual State Publisher « Mariano Ravinale's Blog
  4. Trucs et astuces, développement Windows Phone 8 « Sébastien Ollivier

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

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: