How do I create a design breakpoint in Windows 10 XAML? - xaml

The Responsive Design Guide for Windows 10 apps talks about responsive design techniques and in particular about using design breakpoints for specific size classes:
Design breakpoints for specific size classes
The number of device targets and screen sizes across the Windows 10
ecosystem is too great to worry about optimizing your UI for each one.
Instead, we recommended designing for a few key widths (also called
"breakpoints"): 320, 720, and 1024 epx.
See: https://msdn.microsoft.com/en-us/library/windows/apps/dn958435.aspx#sizeclasses
The article describes the general concept of responsive design and design breakpoints. I'm already familiar with these concepts from HTML and CSS media queries. But I don't know how to do it in XAML?
Searching for Windows 10 and design breakpoints doesn't yield the information I want, can you point me in the right direction?

Design breakpoints for specific size classes is just a concept, a recommendation to give you key sizes to worry about. As Justin mentioned, one really simple way to accomplish that is to use visual state triggers to trigger changes in your UI based on minimum window width. There is a state trigger called AdaptiveTrigger that allows you to do that out of the box. There are other available open source state triggers, but the AdaptiveTrigger is the one you need to react to different widths, or breakpoints, in XAML. Here's a very simple example:
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="AdaptiveSizesVisualStateGroup">
<VisualState x:Name="Large">
<!-- VisualState to be triggered when window width is >=1024 effective pixels -->
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="1024" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="MySplitView.IsPaneOpen" Value="True" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Medium">
<!-- VisualState to be triggered when window width is >=720 and < 1024 effective pixels -->
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="720" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="MySplitView.IsPaneOpen" Value="False" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Small">
<!-- VisualState to be triggered when window width is >=320 and < 720 effective pixels -->
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="320" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="MySplitView.IsPaneOpen" Value="False" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Minimum">
<!-- VisualState to be triggered when window width is >=0 and < 320 effective pixels -->
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="0" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="MySplitView.IsPaneOpen" Value="False" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
You can see that I used a different visual state for different window width. AdaptiveTrigger is the object taking care of actually noticing that the window size has changed and triggering a particular visual state inside a visual state group. Once a visual state is active, the setters are used to set different values to different target objects in XAML. In my code example, I am keeping the SplitView pane closed for all the widths except when >= 1024 effective pixels.
Now, even though AdaptiveTriggers are easy to use, it's very easy to clutter your XAML code with a bunch of setters in each visual state, and it may be hard to maintain that code. Just look how much XAML I wrote for a dummy sample! Also, it's possible that you will want major differences in the UI between Phone and Desktop, so your best bet could end up being writing specific XAML Views tailored for specific device families, which could also have AdaptiveTriggers inside...

To add to the response above, here is a quick intro to the new Adaptive Triggers. If you're using these for the first time, this link might help since this example starts completely from scratch.
http://jamesqquick.com/windows-10-adaptive-triggers-intro/

Related

How to dynamically change position of Text and Image depending upon windows size in xaml

I want to change the position of image and Text when the user resize the app window and width is very small. Please refer the attached gif which shows it happening for a Windows Settings app. I want to do achieve something similar to this.
I want to change the position of image and Text when the user resize the app window
What you are looking for is Adaptive layouts with visual states and state triggers.
When your app window grows or shrinks beyond a certain amount, you could alter layout properties to reposition, resize, reflow, reveal or replace sections of your UI. What you need is to define different visual states for your UI first. Then apply them when the window width or window height crosses a specified threshold. The document above shows different ways to change the visual states for different windows size.
There are two common ways:
handling the Window.SizeChanged Event in the code behind. Then call the VisualStateManager.GoToState method to apply the appropriate visual state.
using the AdaptiveTrigger Class in XAML. It will be triggered to apply the visual state when the size of the window grows or shrinks beyond the value you defined.
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState>
<VisualState.StateTriggers>
<!-- VisualState to be triggered when the
window width is >=640 effective pixels. -->
<AdaptiveTrigger MinWindowWidth="640" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="mySplitView.DisplayMode" Value="Inline"/>
<Setter Target="mySplitView.IsPaneOpen" Value="True"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
Please check this document for more information and code sample: Adaptive layouts with visual states and state triggers.

UWP element sizing

I'm beginner at UWP ,
how can we give sizes to elements that work correctly in both phones and desktop ?
i.e. text block topic must be 200 pixel in desk top and 100 pixel on phones .
Read about the Adaptive Layout in UWP
In a nutshell, you would use the new Adaptive Triggers to change your UI based on the screen width.
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState x:Name="Narrow">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="0" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="MyText.Width" Value="100" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="WideScreen">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="500" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="MyText.Width" Value="200" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
There are few ways to achieve nice and smooth layout behaviour on the phone and desktop.
Adaptive triggers
DeviceFamily Folders
Xaml Behaviors
I published two blog posts about how to achieve good design results:
https://mobileprogrammerblog.wordpress.com/2015/10/23/universal-windows-10-application-with-tailored-design-part-1/
https://mobileprogrammerblog.wordpress.com/2015/11/23/universal-windows-10-application-with-tailored-design-part-2/
https://blogs.windows.com/buildingapps/2015/11/30/xaml-behaviors-open-source-and-on-uwp/
I also definitely recommend watchin Channel9 video by Dante Gagne about tailored UWP design:
https://channel9.msdn.com/Events/Visual-Studio/Visual-Studio-2015-Final-Release-Event/Universal-Windows-Platform-Tailored-Experiences?ocid=SessionsInEvent

Why does my AdaptiveTrigger fire when I change the theme settings?

I have a user interface that adapts to different device form factors using AdaptiveTrigger. In particular, I have a SplitView-based shell menu with two state triggers for when the minimum window width is 1000 epx and 600 epx respectively. The 600 epx state trigger can fire on certain mobile devices in landscape mode depending on their form factor and scale factor, and this is intended behavior.
However, I've noticed that on the desktop, the 600 epx state trigger fires in the background (changing ShellSplitView.DisplayMode from Overlay to CompactOverlay) as soon as I change a theme setting such as toggling between dark and light mode, changing the accent color, or toggling high contrast mode; and on both the mobile emulator and a device, it fires when I go to the Settings app, change a theme setting, and return to my app. Most peculiarly, this only happens in the default state and only after I've caused any of the state triggers to fire, by resizing the window on the desktop or by rotating the mobile emulator or device. Resizing/rotating again after returning to the app makes the problem go away. I have not previously seen this in any other apps, including Microsoft's apps or any third-party UWP apps.
I've confirmed that this is not caused by some other code interfering with the state triggers, by successfully reproducing the problem in a blank UWP project with a single page containing nothing but a SplitView with any number of visual states (and some text content):
<Page
x:Class="App1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App1"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState>
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="1000"/>
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="ShellSplitView.DisplayMode" Value="Inline"/>
<Setter Target="ShellSplitView.IsPaneOpen" Value="True"/>
</VisualState.Setters>
</VisualState>
<VisualState>
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="600"/>
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="ShellSplitView.DisplayMode" Value="CompactOverlay"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<SplitView
x:Name="ShellSplitView"
CompactPaneLength="48"
DisplayMode="Overlay"
IsPaneOpen="False"
OpenPaneLength="256">
<SplitView.Content>
<TextBlock Text="Content"/>
</SplitView.Content>
<SplitView.Pane>
<TextBlock Text="Pane"/>
</SplitView.Pane>
</SplitView>
</Grid>
</Page>
You can attempt to reproduce the problem yourself by creating a blank UWP project, replacing the contents of MainPage.xaml with the above XAML, and running the project.
Considering all I did was change the theme settings, I don't understand why any of the state triggers would fire. In fact, according to this guide on MSDN, the default values reflected in the SplitView element's attributes should be reapplied automatically:
When you use state triggers, you don't need to define an empty DefaultState. The default settings are reapplied automatically when the conditions of the state trigger are no longer met.
And according to the Windows.UI.Xaml.AdaptiveTrigger page itself:
By default, the StackPanel orientation is Vertical. When the window width is >= 720 effective pixels, the VisualState change is triggered, and the StackPanel orientation is changed to Horizontal.
... which, together, reinforce my point — the window width does not change when I change the theme settings, so I don't see why the state trigger would kick in when it shouldn't, and why only after I've triggered a state change by resizing the window or rotating the device.
So why is this happening, and how do I fix it?
This issue appears to have been fixed in the Windows 10 Anniversary Update for all device families. The state triggers will no longer activate when they're not supposed to, and the default values as specified outside of the state triggers are now correctly reapplied.
You do not need this workaround if your app will only be running on the 1607 branch (build 14393) or newer. Note that this refers to the minimum version as specified in your project properties, and not the target version.
You need this workaround if your app will be running on the 1511 branch (build 10586) or 1507 branch (build 10240), even though it will behave correctly on devices with the newer builds.
Unfortunately, I haven't been able to work around this problem without just adding a default state to the VisualStateGroup anyway, using a state trigger with a minimum dimension of 0 epx (you do not need any setters — you just need a state trigger):
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState>
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="1000"/>
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="ShellSplitView.DisplayMode" Value="Inline"/>
<Setter Target="ShellSplitView.IsPaneOpen" Value="True"/>
</VisualState.Setters>
</VisualState>
<VisualState>
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="600"/>
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="ShellSplitView.DisplayMode" Value="CompactOverlay"/>
</VisualState.Setters>
</VisualState>
<VisualState>
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="0"/>
</VisualState.StateTriggers>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
As to why this happens, my guess is that the VisualStateManager is trying to go to a state when the system theme is updated, but as there is none defined for the initial (or "Default" or "Normal") state, it has to choose the next best alternative. What I still don't understand, is why the VisualStateManager has to change visual states when the system theme is updated in the first place... don't ThemeResources refresh by themselves? Why would they depend on the VisualStateManager?
It's interesting to note that most third-party tutorials on adaptive triggers in UWP already do this. It's not clear if the authors were aware of this problem, or if they added the default state simply because they were used to doing so in the Silverlight/WPF days. Based on the documentation above and the otherwise correct UWP behavior, though, this is probably an edge case.

Doing localization in visualstatemanager by changing x:uid?

I am adding localization to my UWP app by adding x:uid tags to all of my elements and using the multilingual toolkit. However I've run into an issue where in one case I change the text itself in the narrow view using the visualstatemanager. How can I do this in a localized app? My first thought would be to change the uid of the element to the new match the new text, I'm not sure it's possible.
Here is an example of what I'd like to do, but doesn't work:
<textblock x:Name="DescriptionTextBox" x:uid="DescriptionTextBox"/> // Normal long description
....
<VisualState x:Name="NarrowState">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="0" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="DescriptionTextBox.Uid" Value="DescriptionTextBoxShort" /> // Uid of short description
x:Uid is no dependency property on your TextBlock and can't be set at runtime. You can double check this by going to the generated code behind (.g.i.cs file) of your XAML page. To do this, hit F12 on InitializeComponent() in the constructor. Now locate your control in the generated code and start drilling down the object tree: you won't encounter a Uid property. It's a XAML directive backed up by an attribute.
How I typically solve this is having 2 TextBlocks (one collapsed) with the the long and short text and toggle Visibility between both TextBlocks in your VisualStates. Depending on what the parent container of these TextBlocks is, you might need to add a StackPanel or Grid as some parent controls can only have 1 child element.

How to disable/enable a VisualState based on some condition? (Metro)

I defined a VisualState for a button in a controltemplate:
<ControlTemplate x:Key="ButtonTemplate" TargetType="Button">
...
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
...
<VisualState x:Name="PointerOver">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="c1" Storyboard.TargetProperty="Opacity" To="0.7"/>
</Storyboard>
</VisualState>
...
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
...
</ControlTemplate>
But this effect (change opacity when mouseover) should be enabled/disabled based on a viewmodel condition, so how do I do that with XAML?
I tried creating a binding for the To value of the DoubleAnimation, it doesn't work because Storyboard is freezed. I'm also thinking sth like a template selector, but there is no such thing for the VisualState Manager.
I was discussing it recently with someone and I might add a generic solution to the problem to the WinRT XAML Toolkit, which would work similar to DataTriggers from WPF, but for now I would just add a DependencyProperty to your control, bind the property to your view model and on value change - update the visual state.