UWP element sizing - size

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

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.

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.

How do I create a design breakpoint in Windows 10 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/

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.

Performance with XAML binding one value to many elements in GridView (Windows 8)

I have a Windows 8 XAML page with a grid in it that shows sample text in 100+ different fonts. The sample text is the same in each grid view item and can be changed using a textbox at the top of the page.
Every time you type a character all the grid view items are updated. The problem is that this is noticeably slow. Particularly if you type quickly.
I'm not sure what is making it so slow. Is it updating all the grid view items including the ones not on screen? Is something else causing the problem and this particular binding is just a red herring?
Here is my binding code (I've removed some xaml from my data template to make it clearer):
<ScrollViewer>
<GridView x:Name="FontGridView" ItemsSource="{Binding Fonts}" SelectionMode="Multiple" Margin="116,0,40,46">
<GridView.ItemTemplate>
<DataTemplate>
<Grid Width="600" MinHeight="100" MaxHeight="120">
<TextBox Text="{Binding ElementName=pageRoot, Path=DataContext.SampleText, Mode=OneWay}"
FontFamily="{Binding FamilyName}" FontSize="32" Background="Transparent" />
</Grid>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
</ScrollViewer>
Is there a better way to do this, or are there any other performance tuning things I can turn on?
UPDATE: You're less likely to make this mistake since Visual Studio 2012 RC came out. The templates for WinRT apps no longer use a ScrollViewer in this way. I'm keeping the question here for those that have ported apps they created using Visual Studio 2011.
Try removing the ScrollViewer.
Because the GridView is inside a scrollviewer, it is effectively given an infinite width. That might kill the virtualization of the WrapGrid in the GridView.
Furthermore, the GridView internally contains a ScrollViewer already. Obviously, you don't need two of them. But the inner ScrollViewer will also eat mouse wheel events, leaving no events for the outer ScrollViewer to react to. As a result scrolling with the mouse will not work.
Visual Studio 11 (bèta 1) templates contain code like this, to set a margin on the GridView. However, it's better to set a margin on the GridView's ItemsPanel, like this:
<GridView x:Name="FontGridView" ItemsSource="{Binding Fonts}" SelectionMode="Multiple">
<GridView.ItemTemplate>
<DataTemplate>
<Grid Width="600" MinHeight="100" MaxHeight="120">
<TextBox Text="{Binding ElementName=pageRoot, Path=DataContext.SampleText, Mode=OneWay}"
FontFamily="{Binding FamilyName}" FontSize="32" Background="Transparent" />
</Grid>
</DataTemplate>
</GridView.ItemTemplate>
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<WrapGrid x:Name="itemGridViewPanel" Margin="116,53,116,46"/>
</ItemsPanelTemplate>
</GridView.ItemsPanel>
</GridView>
Your original code did not include the Margin that you set on the GridView. But whatever it was, set the same Margin on the WrapGrid.
Notice also that I gave the WrapGrid a name. You can use that name to change the Margin when the screen orientation changes, typically as follows:
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState x:Name="FullScreenLandscape"/>
<VisualState x:Name="Filled"/>
<VisualState x:Name="FullScreenPortrait">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="itemGridViewPanel"
Storyboard.TargetProperty="Margin">
<DiscreteObjectKeyFrame KeyTime="0"
Value="96,53,96,46"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Snapped"/>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
UPDATE:
I had done this before, but with a VariableSizedWrapGrid. That produces the correct layout, but unfortunately, I'm afraid that VariableSizedWrapGrid is not a virtualizing panel.
WrapGrid is virtualizing, but the behavior at the left margin seems wrong when scrolling. It is correct at the right margin though.
Oh well, in two weeks time we should have the release candidate available. Hopefully things will have improved...
UPDATE:
It seems that Microsoft is aware of this. See http://social.msdn.microsoft.com/Forums/en-US/winappswithcsharp/thread/17385f7d-aadc-4edc-bbff-8738a2f0c917.
UPDATE:
It seems that the WrapGrid has not been fixed in the Release Candidate.
Simplify your data template.
<DataTemplate>
<TextBlock Text="{Binding ElementName=pageRoot, Path=DataContext.SampleText}"
Width="600" MinHeight="100" MaxHeight="120"
FontFamily="{Binding FamilyName}" FontSize="32" />
</DataTemplate>
You don't need the Grid. And it looks like you don't need a (complex) TextBox either, just a (simple) TextBlock.
Also, fixing the height of those text blocks (Height="120") might help (optimize) the layout process.
UPDATE:
I understand you're code is simplified from "the real thing". But that might hide the real problem for us. Remember, the data template is intantiated for every item that is on screen. The more complex it is, the more objects need to be instantiated (CPU and memory usage), possibly need to databind (CPU), need to be measured and laid out (CPU), and need to be rendered (CPU and GPU).
Just do a test with a very simple data template. If your program is faster now, or not, you know whether the data template is the performance problem or not.
Note that the complexity of the data template is not measured by the number of xaml elements you need to describe it, as those elements may have very different internal complexities. For example, do prefer a TextBlock over a TextBox if all you need to do is display text, not allow editing.
Also, if some of these elements have a lot of properties set, do use styles to set them. Using a style on many objects is more efficient than setting many properties on many objects, especially when it come to memory usage. And the less memory you use, the faster your program will be (due to modern CPU multilevel caching architectures).
For example:
<GridView x:Name="FontGridView" ItemsSource="{Binding Fonts}" SelectionMode="Multiple">
<GridView.Resources>
<Style TargetType="TextBlock">
<Setter Property="Width" Value="600" />
<Setter Property="MinHeight" Value="100" />
<Setter Property="MaxHeight" Value="120" />
<Setter Property="FontSize" Value="32" />
</Style>
</GridView.Resources>
<GridView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding ElementName=pageRoot, Path=DataContext.SampleText}"
FontFamily="{Binding FamilyName}" />
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
Try using a VirtualizingStackPanel
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</GridView.ItemsPanel>