Home > C#, WinRT > Handling VisualState in Windows 8.1 Store apps

Handling VisualState in Windows 8.1 Store apps

16/10/2013

Last week we talked about creating a base page class for Windows 8.1 Store apps.

This class lacks visual states management as seen in the old LayoutAwarePage class. In fact, discrete view states are deprecated in Windows 8.1 and the snapped state is no longer required for certification. Instead, apps can be sized continuously to any size down to their minimum size. By default, the minimum size of an app is 500px, but we can set the minimun width to 320px using the application manifest file.

However, even if it is no longer required to handle the snapped view, tipically we need to adapt our apps to different window sizes. In this case, we have to explicitly write code to handle the SizeChanged event and update the UI accordingly.

A possible solution is to combine the classic VisualState management with the new window size model. Basically, we need to handle the Window.SizeChanged event and use the VisualStateManager to make transitions between visual states, that in this case depend on window size.

Let’s use the BasicPage we introduced in the last post (in the following code, only the portions related to visual states management are shown):

public class BasicPage : Page
{
    public BasicPage()
    {
        this.Loaded += page_Loaded;
        this.Unloaded += page_Unloaded;
    }

    private void page_Loaded(object sender, RoutedEventArgs e)
    {
        Window.Current.SizeChanged += Window_SizeChanged;
        DetermineVisualState();
    }

    private void page_Unloaded(object sender, RoutedEventArgs e)
    {
        Window.Current.SizeChanged -= Window_SizeChanged;
    }

    private void Window_SizeChanged(object sender, WindowSizeChangedEventArgs e)
    {
        DetermineVisualState();
    }

    private void DetermineVisualState()
    {
        var state = string.Empty;
        var applicationView = ApplicationView.GetForCurrentView();
        var size = Window.Current.Bounds;

        if (applicationView.IsFullScreen)
        {
            if (applicationView.Orientation == ApplicationViewOrientation.Landscape)
                state = "FullScreenLandscape";
            else
                state = "FullScreenPortrait";
        }
        else
        {
            if (size.Width == 320)
                state = "Snapped";
            else if (size.Width <= 500)
                state = "Narrow";
            else
                state = "Filled";
        }

        System.Diagnostics.Debug.WriteLine("Width: {0}, New VisulState: {1}", 
            size.Width, state);

        VisualStateManager.GoToState(this, state, true);
    }
}

In the Loaded event of the page, we register on the Window.SizeChanged event and then we call the DetermineVisualState method, in which we make the following checks:

  • We check if the app is running fullscreen. If so, we control also the screen orientation, and we set the state variable accordingly;
  • If the app isn’t fullscreen, we check the window width to determine the new state. Note that this is only an example, you are free to define these states in the way that is more comfortable for your app, but always remember the 500px default minumum width.

Finally, we use VisualStateManager to make the transitions to the new state. As we have registered to the SizeChanged event, everytime we change the width of the window, a new transition is generated.

Having this code in the base class, in the XAML page we can use the VisualStateManager like we did in old Windows 8 Store apps:

<Grid x:Name="typicalPanel">
    <TextBlock Text="Normal view" 
               Style="{StaticResource BaseTextBlockStyle}" />
</Grid>

<Grid x:Name="narrowPanel" Visibility="Collapsed">
    <TextBlock Text="App width is between 500 and 320px"
               Style="{StaticResource BaseTextBlockStyle}" />
</Grid>

<VisualStateManager.VisualStateGroups>
    <VisualStateGroup>
        <VisualState x:Name="Narrow">
            <Storyboard>

                <ObjectAnimationUsingKeyFrames 
                    Storyboard.TargetName="typicalPanel" 
                    Storyboard.TargetProperty="Visibility">
                    <DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed" />
                </ObjectAnimationUsingKeyFrames>

                <ObjectAnimationUsingKeyFrames 
                    Storyboard.TargetName="narrowPanel" 
                    Storyboard.TargetProperty="Visibility">
                    <DiscreteObjectKeyFrame KeyTime="0" Value="Visible" />
                </ObjectAnimationUsingKeyFrames>

            </Storyboard>
        </VisualState>
    </VisualStateGroup>
</VisualStateManager.VisualStateGroups>

For simplicity, in this code only two visual states are handled. We have two grids, typicalPanel and narrowPanel. Their visibility is managed using the animation in the VisualStateManager tag: when the state becomes Narrow (i.e., the width is between 500 and 320px), typicalPanel is hidden and narrowPanel is shown.

Categories: C#, WinRT
  1. khan
    21/12/2013 at 18:05

    Assume that I want to add a scrollviewer to all of my pages in my app when it is in snapped view or fill view. So that user could scroll and use my app.How to achieve it by applying your code?

  1. 16/10/2013 at 12:02
  2. 17/10/2013 at 05:45
Comments are closed.
%d bloggers like this: