Search code examples
xamlwin-universal-appwindows-8.1-universal

change layout based on orientation detect in xaml Windows app


I am trying to alter my views based on landscape and portrait orientation.

I tried code from couple of places, eg:

  1. How to detect orientation changes and change layout?

  2. https://social.msdn.microsoft.com/Forums/en-US/a2064993-e4a9-4a58-8498-ef03ed9403f4/how-to-set-grid-row-property-in-visualstatemanager-in-windows8-app?forum=winappswithcsharp

but it does not work for me. Not sure what I am doing wrong.? I am testing it from a Simulator.

 <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="1*" />
            <RowDefinition Height="1*" />
            <RowDefinition Height="18*" />
        </Grid.RowDefinitions>
<Grid/>
<Grid Grid.Row=1/>
<Grid Grid.Row="2">
    <Grid.RowDefinitions>
        <RowDefinition Height="4*" />
        <RowDefinition Height="14*" />
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*"/>
        <ColumnDefinition Width="Auto"/>
    </Grid.ColumnDefinitions>
    <Grid Grid.Row="0" x:Name="PageTotals" />

    <Grid Grid.Row="1" x:Name="PageDetails" />

    <VisualStateManager.VisualStateGroups>
        <VisualStateGroup x:Name="ApplicationViewStates">
            <VisualState x:Name="Filled"/>
            <VisualState x:Name="FullScreenPortrait"/>
            <VisualState x:Name="Snapped"/>
            <VisualState x:Name="FullScreenLandscape">
                <Storyboard>
                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="PageTotals"
                                           Storyboard.TargetProperty="(Grid.Column)">
                        <DiscreteObjectKeyFrame KeyTime="0" Value="0"/>
                    </ObjectAnimationUsingKeyFrames>
                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="PageTotals"
                                           Storyboard.TargetProperty="(Grid.RowSpan)">
                        <DiscreteObjectKeyFrame KeyTime="0" Value="2"/>
                    </ObjectAnimationUsingKeyFrames>
                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="PageDetails"
                                           Storyboard.TargetProperty="(Grid.Column)">
                        <DiscreteObjectKeyFrame KeyTime="0" Value="1"/>
                    </ObjectAnimationUsingKeyFrames>
                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="PageDetails"
                                           Storyboard.TargetProperty="(Grid.RowSpan)">
                        <DiscreteObjectKeyFrame KeyTime="0" Value="2"/>
                    </ObjectAnimationUsingKeyFrames>
                </Storyboard>
            </VisualState>
        </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>
</Grid>

Solution

  • The automatic triggers for VisualStates was something introduced with the LayoutAwarePage in Windows 8. However with Windows 8.1, the notion of Snapped screen got removed and the guidance was to design your app for 320px (setting in manifest) or 500px (default) as the minimum size. The automatic triggers on orientation changes were also removed.

    There are however samples of developers who tried to reproduce the Windows 8 behavior, like this post from Jeremy Likness. You can still write/use code similar to his implementation on the existing 8.1 API's to test the orientation and if your app is full screen and then go to the desired state yourself with VisualStateManager.GoToState.

    private static void SetLayout(Control control)
    {
        var orientation = ApplicationView.GetForCurrentView().Orientation;
        string newMode;
    
        if (orientation == ApplicationViewOrientation.Landscape)
        {
            newMode = ApplicationView.GetForCurrentView().IsFullScreen ? "FullScreenLandscape" : "Filled";
        }
        else
        {
            newMode = Window.Current.Bounds.Width <= 500 ? "Snapped" : "FullScreenPortrait";
        }
    
        if (newMode == GetLastOrientation(control))
        {
            return;
        }
    
        VisualStateManager.GoToState(control, newMode, true);
        SetLastOrientation(control, newMode);
    }
    

    Source: Jeremy's post.