Click here to Skip to main content
15,881,248 members
Articles / Desktop Programming / Universal Windows Platform
Tip/Trick

Building Adaptive UI in UWP

Rate me:
Please Sign up or sign in to vote.
3.40/5 (3 votes)
25 Oct 2015CPOL3 min read 18K   4   1
Building adaptive layout in a windows 10 app with relative panel and adaptive triggers

Introduction

A universal windows platform app as the name indicates is meant to run on a host of devices ranging from single-board raspberry pi's to full blown surface book and everything in between that runs windows 10 on it . Apart from the difference in computing power the range of form factors of these devices is also pretty diverse.

In such a scenario it becomes extremely important to create UI for your applications which target a host of devices from this set in an adaptive manner. Fortunately microsoft provides a good UI toolset to easily accomplish this.

Background

In windows phone or windows store apps the change in UI for different orientations is handled by Visual State Manager, the same VSM can be used for handling split mode in windows store apps. Windows 10 uses the same VSM but in an improved manner

Visual State Manager

The following piece of code explains the VSM behvior

XML
  1   <grid x:name="Root">
  2      <visualstatemanager.visualstategroups>
  3          <visualstategroup>
  4              <visualstate x:name="WideState">
  5                  <visualstate.setters>
  6                      <setter target="Root.Background" value="Green">
  7                  </setter></visualstate.setters>
  8                  <visualstate.statetriggers>
  9                      <adaptivetrigger minwindowwidth="600">
 10                  </adaptivetrigger></visualstate.statetriggers>
 11              </visualstate>
 12              <visualstate x:name="NarrowState">
 13                  <visualstate.setters>
 14                      <setter target="Root.Background" value="Red">
 15                  </setter></visualstate.setters>
 16                  <visualstate.statetriggers>
 17                      <adaptivetrigger minwindowwidth="0">
 18                  </adaptivetrigger></visualstate.statetriggers>
 19              </visualstate>
 20          </visualstategroup>
 21      </visualstatemanager.visualstategroups>
 22  </grid>

 

In order to support adaptive behavior there are two VisualStates sepcified within the VisualStateGroup in the VisualStateGroupsCollection of the VSM.

The above code specifies two UI transformations one for small devices when the min window width is between 0 & 599 and this is named the NarrowState and the second when width is equal or more than 600 this is named the WideState.

There are two parts to these visual transformations

1. The required change in UI

2. The criterion or trigger for the change

As you can see in the above code for the WideState transformation the first part is taken care by the VisualState.Setter at line number 5, it indicates the UI change, which is basically to set the Background Property of the Root Grid to Green, The trigger for this action is specified using the Adaptive Trigger at line number 9, which in this case says that invoke the setter(s) when MinWindowWidth is atleast 600. Similarly there is a setter & trigger specied for the NarrowState.

When you run the application and to shrink the width you would see the background color changing from green to red when the width goes below 600.

 

Relative Panel

As you can see VSM provides great way to write adaptive UI. However UWP provides another tool which complements the VSM in a nice way and it is the RelativePanel. Often there is a need to create Layout which has relatively positioned UI elements so that the same UI can fit to various form factors and this can be done using good old store app controls, however RelativePanel provides a cleaner way of achieving this. Lets take a look at an example.

XML
  1  <grid x:name="LayoutRoot">
  2          <visualstatemanager.visualstategroups>
  3              <visualstategroup>
  4                  <visualstate x:name="WideState">
  5                      <visualstate.statetriggers>
  6                          <adaptivetrigger minwindowwidth="600">
  7                      </adaptivetrigger></visualstate.statetriggers>
  8                      <visualstate.setters>                        
  9                          <setter target="FirstNameText.(RelativePanel.RightOf)" value="FirstNameLabel">
 10                      </setter></visualstate.setters>
 11                  </visualstate>
 12  
 13                  <visualstate x:name="NarrowState">
 14                      <visualstate.statetriggers>
 15                          <adaptivetrigger minwindowwidth="0">
 16                      </adaptivetrigger></visualstate.statetriggers>
 17                      <visualstate.setters>                        
 18                          <setter target="FirstNameText.(RelativePanel.Below)" value="FirstNameLabel">
 19                      </setter></visualstate.setters>
 20                  </visualstate>
 21              </visualstategroup>
 22          </visualstatemanager.visualstategroups>
 23          <relativepanel horizontalalignment="Stretch" margin="20">
 24              <textblock margin="0,5,10,5" text="First name" x:name="FirstNameLabel">
 25              <textbox width="300" x:name="FirstNameText">
 26          </textbox></textblock></relativepanel>
 27      </grid>

This example extends the first one by adding another set of setters for NarrowState and WideState.

The setter code at line number 8 specifies two properties for the setter.A Target which is set to "FirstNameText.(RelativePanel.RightOf)" and a Value which is set to "FirstNameLabel".

This declaration basically means that when the window width is >= 600 place the FirstName textbox to the right if FirstName label. Similarly the Narrow State provides a transformation which means place the FirstName text block below the FirstName label. 

The alignment of the controls relative to each other happens because they are placed in the RelativePanel.

Note the usage of parenthesis around the “RelativePanel.RightOf” and “RelativePanel.Below” properties. This is needed because RightOf and Below are attached properties defined by the RelativePanel class. This is similar to the well known Grid.Column/Grid.Row properties, or Canvas.Top/Canvas.Left, etc.

Running the code now will show the controls side by side when the window width is >= 600 and the same controls stack up one below the other when you shrink the window width below 600.

I hope the above example has explained how to create adaptive UI using VisualStateManager & RelativePanel.

 

History

 

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



Comments and Discussions

 
SuggestionBetter XAML Pin
sbarnes7-Jan-16 0:12
sbarnes7-Jan-16 0:12 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.