Morse Coder Part 9 : Visual State Triggers

Intro

As we saw when we migrated our Universal Windows App to Windows 10 targetting Phones and PCs with the same set of markup presents us with a challenge…

Windows10-Phone.png

This UI is less than usable!  There are a new set of User Controls made available as part of Windows 10, for example the Relative Panel.  In this post we’ll look at ways we can make our UI adaptive based on the screen size we are targeting.

Outcome

By the end of this post we will have a single app that is usable on PCs, tablets, and Phones.  We’ll be looking into Visual State Triggers in order to alter the size of the text presented in our Input and Output TextBox and TextBlock controls.  Visual State Triggers apply transformations to the base XAML defined, we’ll be using this method to make our app responsive.

Prerequisites

Implementation

We’ll be setting up a couple of VisualStateGroups, one for Phone displays and one for larger displays.  It may prove to be a good idea to go more granular but for the purpose of example we’ll keep it simple.

The VisualStateGroup Objects will be defined at our Grid root control.

Let’s add them in :

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

</VisualState>
<VisualState x:Name="phoneView">

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

Now we must consider the circumstances in which these transformations will be applied.  Let’s add in our Visual State State Triggers using an Adaptive Trigger :

<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState x:Name="desktopView">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="900" />
</VisualState.StateTriggers>

</VisualState>
<VisualState x:Name="phoneView">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="0" />
</VisualState.StateTriggers>

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

The AdaptiveTriggers added there will be triggered for screens with a Width > 900 and a Width > 0, covering the spectrum we should expect to see.  We can now start making our Transformations within the Visual State using the Setters Property on the VisualState objects.  In order to do this we will need to give our target controls Name properties so that we can refer to them in our Setters.  All in, we’re left with :

<Grid Background="{Binding BackgroundBrush}">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>

<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState x:Name="desktopView">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="1200" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="output.FontSize" Value="72"/>
<Setter Target="input.FontSize" Value="72"/>
</VisualState.Setters>
</VisualState>
<VisualState x:Name="phoneView">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="0" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="output.FontSize" Value="24"/>
<Setter Target="input.FontSize" Value="24"/>
<Setter Target="input.Margin" Value="10"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>

<ScrollViewer Margin="30" VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
<TextBlock x:Name="output" HorizontalAlignment="Center" TextWrapping="Wrap" Text="{Binding Translation}" VerticalAlignment="Center" FontSize="72" />
</ScrollViewer>

<Grid Grid.Row="1">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="120" />
</Grid.RowDefinitions>
<TextBox x:Name="input" Text="{Binding Input, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" FontSize="72" Margin="50,10" TextWrapping="Wrap"/>
<!--<UserControls:MorseInput DotCommand="{Binding DotCommand}" DashCommand="{Binding DashCommand}" SpaceCommand="{Binding SpaceCommand}" HorizontalAlignment="Stretch" Margin="50,10" Grid.Row="1" VerticalAlignment="Stretch" />-->
</Grid>

</Grid>

Note the :

  • VisualState.Setters sections;
  • Setter Definitions defining a target and what we now want the values to be;
  • x:Name properties on the Input and Output controls allowing them to be referred to in the Setters.

Our Phone app now looks like…

Adaptive Phone
Adaptive Phone

 

…and our Desktop still looks like…

Adaptive-Desktop.png
Adaptive Desktop

Summary

Where are we?

  • Our app is now usable on a variety of screen sizes.  We could go further down this path, we may look to introduce a RelativePanel in a further post.

Where are we heading?

We’ll look at :

  • adding some more functionality to the app to swap the translation direction;
  • the MVVMLight INavigationService Implementation;
  • methods of serialising POCOs to Application Settings.

1 thought on “Morse Coder Part 9 : Visual State Triggers”

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