Home > C#, MVVM, Windows Phone, WinRT > Handling VisualState in Universal apps with Behavior SDK and MVVM

Handling VisualState in Universal apps with Behavior SDK and MVVM

15/07/2014

With VisualState, we can easily create different UIs that can be shown alternately. In Windows 8, for example, it was used by the Basic Page template to define layouts that adapt to orientation and app width. But, in general, we can create different UIs and show them based on the current state of the app. Let’s see how to do that in a Universal Windows app with MVVM Light.

Let’s define the following ViewModel:

public class MainViewModel : ViewModelBase
{
    private enum ViewModelState
    {
        Default,
        Details
    }

    private string currentState;
    public string CurrentState
    {
        get { return currentState; }
        set
        {
            this.Set(ref currentState, value);
        }
    }

    public RelayCommand GotoDetailsStateCommand { get; set; }
    public RelayCommand GotoDefaultStateCommand { get; set; }

    public MainViewModel()
    {
        GotoDetailsStateCommand = new RelayCommand(() =>
        {
            CurrentState = ViewModelState.Details.ToString();
        });

        GotoDefaultStateCommand = new RelayCommand(() =>
        {
            CurrentState = ViewModelState.Default.ToString();
        });
    }
}

The CurrentState property at lines 10-17 represents the state of the ViewModel, that we can change using the two RelayCommands defined in the constructor.

Now we define two VisualStates in the MainPage.xaml page: we want that, when the CurrentState property changes, the VisualState is updated accordingly. To do that with an MVVM approach, we can make use of the Behavior SDK:

<Page
    x:Class="MvvmDemo.MainPage"
    DataContext="{Binding Source={StaticResource Locator}, Path=MainViewModel}"
    ...
    xmlns:i="using:Microsoft.Xaml.Interactivity"
    xmlns:core="using:Microsoft.Xaml.Interactions.Core"
    ...
    >

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <Grid x:Name="DefaultPanel" HorizontalAlignment="Center" 
              VerticalAlignment="Center">
            <StackPanel>
                <TextBlock Text="Default State" 
                           Style="{StaticResource SubheaderTextBlockStyle}" />
                <Button Margin="0,20,0,0" Content="Go to Details state" 
                        Command="{Binding GotoDetailsStateCommand}" />
            </StackPanel>
        </Grid>

        <Grid x:Name="DetailsPanel" HorizontalAlignment="Center" 
              VerticalAlignment="Center" Visibility="Collapsed">
            <StackPanel>
                <TextBlock Text="Details State" 
                           Style="{StaticResource SubheaderTextBlockStyle}"
                           Foreground="Yellow" />
                <TextBlock Text="Details message here..." 
                           Style="{StaticResource TitleTextBlockStyle}" />
                <Button Margin="0,20,0,0" Content="Go to Default state" 
                        Command="{Binding GotoDefaultStateCommand}" />
            </StackPanel>
        </Grid>

        <VisualStateManager.VisualStateGroups>
            <VisualStateGroup x:Name="ApplicationViewStates">
                <VisualState x:Name="Default"/>

                <VisualState x:Name="Details">
                    <Storyboard>
                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="DefaultPanel" 
                                                    Storyboard.TargetProperty="Visibility">
                            <DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed"/>
                        </ObjectAnimationUsingKeyFrames>
                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="DetailsPanel" 
                                                    Storyboard.TargetProperty="Visibility">
                            <DiscreteObjectKeyFrame KeyTime="0" Value="Visible"/>
                        </ObjectAnimationUsingKeyFrames>
                    </Storyboard>
                </VisualState>
            </VisualStateGroup>
        </VisualStateManager.VisualStateGroups>

        <i:Interaction.Behaviors>
            <core:DataTriggerBehavior Binding="{Binding CurrentState}" 
                                      ComparisonCondition="Equal" Value="Default">
                <core:GoToStateAction StateName="Default" />
            </core:DataTriggerBehavior>
            <core:DataTriggerBehavior Binding="{Binding CurrentState}" 
                                      ComparisonCondition="Equal" Value="Details">
                <core:GoToStateAction StateName="Details" />
            </core:DataTriggerBehavior>
        </i:Interaction.Behaviors>
    </Grid>
</Page>

We have defined two grids: the first at lines 11-19 (DefaultPanel) and the other at lines 21-32 (DetailsPanel). The latter is initially collapsed. Thanks to the VisualStateManager, it will be shown when the VisualState of the page changes to Details, using the animations at lines 38-49.

The transition betweeen VisualStates is done using behaviors. In particular, we use a DataTriggerBehavior that checks the value of the CurrentState property: accordingly to its value (lines 54-61), we invoke the GotoStateAction action to actually modify the page state.

That’s all. Everytime we change the value of CurrentState property in the ViewModel, the corresponding trigger will be executed, resulting in a change of the Visual State.

You can download the working example using the link below.

Handling VisualState in Universal apps with Behavior SDK and MVVM

Categories: C#, MVVM, Windows Phone, WinRT
  1. thierry verdier
    17/07/2014 at 15:09

    I try this for narrow and default view but with hub page and usercontrols in each hub sections and it doesn’t work😦 any idea ?

    • 17/07/2014 at 15:11

      What problem do you have?

      • thierry verdier
        17/07/2014 at 15:15

        datatrigger dosen’t seem to trigger inside usercontrol so visualstate isn’t changed

      • 17/07/2014 at 15:19

        Have you checked in the Output Windows of Visual Studio if there is any binding error?

      • thierry verdier
        17/07/2014 at 15:26

        I can’t check right now but I deedn’t see any error

  1. 29/07/2014 at 09:06
Comments are closed.
%d bloggers like this: