For Windows 8.0, I built an app called KwiQR which was meant to be a QR code scanning application.
It’s in the Windows 8 Store – you can find it here and, to date, it’s been downloaded only 6000 times so it’s need of a little love – I spent a long time working on these backgrounds – someone should at least be seeing them
It’s also in need of re-working for Windows 8.1.
At the time of building that app, I tried to make sure that I put in as many Windows 8.0 features that I could think of including things like the app acting both as a source of data and as a target of data for the Share charm, the ability to pin additional live tiles (so as to launch the app straight into “camera mode”), application bars, settings, roaming of data (including live updates to the app through dynamic changes in roamed data – try changing that background colour on one machine while watching another machine run the app) and so on.
I also tried to implement snapped view such that when the application was “pinned” to the edge of the screen it did the right thing and displayed a suitable snapped view in a window that was always going to be 320px wide.
In Windows 8.1, things changed. There’s no more snapping as I’m sure you’ve seen if you’ve been following things as they progressed. When I run up my 8.0 KwiQR application on the 8.1 preview and drag it to the left hand edge of the screen I see;
which looks “ok” but when I drag that application out a little, it looks wrong;
my app has 50% of the screen here and it doesn’t know what to do with it because it’s a Windows 8.0 app and it only understands the idea of “Snapped”/”Filled”/”FullscreenLandscape” and “FullscreenPortrait”. Those are values that come directly from the ApplicationViewState enumeration which could be obtained from ApplicationView.Value and which I is deprecated in Windows 8.1 along with ApplicationView.TryUnsnap which I used in another one of my apps in the Store.
In 8.1, your app gets to support any size of window that the user drags it to when they place it on the screen next to another app all the way down to the minimum that your app has specified.
By default, that minimum for your app is going to be 500px which on my screen means that this nice bright “orange” app here get’s stuck when it hits 500px;
and then once I hit 500px, the resizing bar stops playing nicely with me and won’t let me drag below that size;
as that red bar indicates in the picture above.
As an aside, my screen is actually as low-resolution as Windows 8.1 is telling my app it is. That’s all down to pixel densities and scaling.
If I want my app to go below that 500px size then I need to change my manifest to alter my minimum width for the app;
and then I can drag all the way down to 320px;
I think it’s fair to say that on Windows 8.0 most apps had a “full screen view” and a “snapped view”, a few less had a special “portrait” view and I’d say even fewer had a “filled” view.
In terms of what you’re supposed to do with these size changes on Windows 8.1, there is some guidance on the Dev Center and perhaps a little on the UX center but you’re certainly provided with a bunch of APIs that can tell you what’s going on in terms of the size of your window and where it is on the screen so you should have enough information in the app to do pretty much anything you like.
The “orange app” displayed above is just a XAML app with a Viewbox that is responding to Page.SizedChanged events and then picking up the new sizes and changing the width displayed on the screen. That’s an easy thing to do but the ApplicationView class can also provide a lot more information. For a starter, rather than my code having to work out whether width is wider than height, I can just pick up ApplicationView.Orientation and use it to either drive layout changes manually in some code or to drive visual state changes via the VisualStateManager.
For instance, I can display a rectangle in the middle of this view which might change depending on whether I’m portrait or landscape.
and that’s just a little bit of code;
public sealed partial class MainPage : Page { public MainPage() { this.InitializeComponent(); } void Page_SizeChanged(object sender, SizeChangedEventArgs e) { ApplicationView view = ApplicationView.GetForCurrentView(); ApplicationViewOrientation newOrienation = view.Orientation; if ((this.orientation == null) || (this.orientation.Value != newOrienation)) { VisualStateManager.GoToState(this, newOrienation.ToString(), true); this.orientation = newOrienation; } } ApplicationViewOrientation? orientation; }
with some visual states that I defined in Blend to show/hide the rectangles based on the state – i.e. the standard technique for altering a XAML based UI while it’s running (in HTML, you’d do this with media queries just like you do on the web);
<Page x:Class="App74.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:App74" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" SizeChanged="Page_SizeChanged"> <Grid Background="Orange"> <VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="OrientationStates"> <VisualState x:Name="Portrait"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="gridLandscape"> <DiscreteObjectKeyFrame KeyTime="0"> <DiscreteObjectKeyFrame.Value> <Visibility>Collapsed</Visibility> </DiscreteObjectKeyFrame.Value> </DiscreteObjectKeyFrame> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="gridPortrait"> <DiscreteObjectKeyFrame KeyTime="0"> <DiscreteObjectKeyFrame.Value> <Visibility>Visible</Visibility> </DiscreteObjectKeyFrame.Value> </DiscreteObjectKeyFrame> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> <VisualState x:Name="Landscape"/> </VisualStateGroup> </VisualStateManager.VisualStateGroups> <Viewbox MaxWidth="640" Margin="24" HorizontalAlignment="Center" VerticalAlignment="Center"> <Grid> <Grid x:Name="gridLandscape"> <Rectangle Stroke="White" StrokeThickness="6" Width="192" Height="96" /> <TextBlock Text="Landscape" VerticalAlignment="Center" HorizontalAlignment="Center" /> </Grid> <Grid x:Name="gridPortrait" Visibility="Collapsed"> <Rectangle Stroke="White" StrokeThickness="6" Width="96" Height="192" /> <TextBlock Text="Portrait" VerticalAlignment="Center" HorizontalAlignment="Center" /> </Grid> </Grid> </Viewbox> </Grid> </Page>
and then there’s other information hanging off that ApplicationView class that I might use like the AdjacentToLeftDisplayEdge, AdjacentToRightDisplayEdge, IsFullScreen properties. These aren’t mutually exclusive so from the point of view of the Visual State Manager they’d need to go into separate state groups. If I add a few red rectangles to my UI that “light up” when the app is next to the left/right hand edge and a whole bounding box that lights up when the app is full-screen as below;
then that works nicely with some new visual states;
and some code to drive changes;
public sealed partial class MainPage : Page { public MainPage() { this.InitializeComponent(); } void Page_SizeChanged(object sender, SizeChangedEventArgs e) { ApplicationView view = ApplicationView.GetForCurrentView(); ApplicationViewOrientation newOrienation = view.Orientation; if ((this.orientation == null) || (this.orientation.Value != newOrienation)) { VisualStateManager.GoToState(this, newOrienation.ToString(), true); this.orientation = newOrienation; } if ((this.isLeftEdge == null) || (this.isLeftEdge.Value != view.AdjacentToLeftDisplayEdge)) { VisualStateManager.GoToState(this, view.AdjacentToLeftDisplayEdge ? "leftEdge" : "leftBase", true); this.isLeftEdge = view.AdjacentToLeftDisplayEdge; } if ((this.isRightEdge == null) || (this.isRightEdge.Value != view.AdjacentToRightDisplayEdge)) { VisualStateManager.GoToState(this, view.AdjacentToRightDisplayEdge ? "rightEdge" : "rightBase", true); this.isRightEdge = view.AdjacentToRightDisplayEdge; } if ((this.isFullScreen == null) || (this.isFullScreen.Value != view.IsFullScreen)) { VisualStateManager.GoToState(this, view.IsFullScreen ? "fullScreen" : "fullScreenBase", true); this.isFullScreen = view.IsFullScreen; } } bool? isLeftEdge; bool? isRightEdge; bool? isFullScreen; ApplicationViewOrientation? orientation; }
that all works quite well with the exception that if I have the app occupying the left hand 50% of the screen and I pick it up and drag it to the occupy the right hand 50% of the screen then there is no size changed event fired and so my little red rectangles do not update correctly – I’m not sure if there is an event to sync that would pick up this action where the window moves but it does not resize to drive the appropriate state changes.
All in all, there’s lot of API support there for figuring out size, orientation and relative position of your app window and I think this ultimately makes for a more flexible system than with Windows 8.0 and the “Snapped/Filled” style scenarios. On a monitor with a reasonable number of (large) pixels I can stack up a whole bunch of windows for those advanced scenarios where I need to be monitoring Twitter, playing a bit of radio and searching on Bing;