WynApse Home Page
Home    Blog    About    Contact       
Latest Article:


My Tags:
My Sponsors:







Lifetime Member:

Second Metro App




Windows 8 First Apps Contest

I'm thinking about an app (2?) for the First Apps Contest. Come on admit it, you are too... The time seems pretty short to me, but hey most of us are going to have time off for Christmas and New Years anyway, and what do we all do after the first couple days off... am I right? ... yeah, we're coding :)


So What do we Need?

The 'need' here for me is with respect to what I already have learned/accomplished with My First Metro App.

What other sorts of things can I think of at this point in time that I need to get an app ready for show and tell? A (very) short list might be:
  1. Some sort of logo to be used on the app tile
  2. A custom tile, whatever that takes (see number 1)
  3. One of those side windows ... a snap window in case you didn't know
  4. State saving ... to be honest, the first app I have in mind won't need it, but it's all good info
  5. Share source or target
  6. App Bar

Wow... when I started this post, there was only one thing I wanted to cover, and as I wrote, that list grew. Obviously I'm not going to cover all those in one post, but that's definitely a list of things to keep in mind, and it'll probably grow as I go.

Of course I could use one of the templates in VS2011, but I'm trying to write these articles from the standpoint of a Silverlight kinda-guy getting this new groove on, so for now I'm going to continue on with where I left my app at the end of the last post. Hopefully at some later date I'll officially dig into those templates. For now, I'm just going to extract what I need to get some things done.

So what I'm going to do today is add a snap panel/window/pane/whatever onto my app. You can take any app, drag it out, and get a 'snap' of sorts. If you build an app with a lot of data on it, you're not going to like the snap you get because it's going to only display the left end of it.... and that happens even if it's snapped to the right.

To get a real snap is not that difficult, you just need a bit of code from one of the templates, and a secondary view of your data that will display something useful in that narrow window.

Checking out the official word, the baseline resolution for Metro apps is 1366X768. The snap is 320 wide... this leaves, magically after leaving room for the spacer between, 1024X768 on the other app you have open. The snap can be on the right or the left, but if you want your users to like you, your'e going to have to have something in that snap area that works in 320X760. And, you have to get in and out of Snap gracefully.

One thing to note is that there is no Snap in Portrait mode. After using my Slate for a while, I get annoyed when an app doesn't allow portrait when it seems it should be able to, so keep that in mind, and also keep in mind you can lock an orientation.


On to the App

This isn't a brand-new app... I started with the code from My First Metro App, with the goal of adding a Snap window the right way.

Figuring out the 'right' way meant building samples from the templates and ratting around in the code. What you have to add to your app to get a Snap window isn't that big a deal, but of course, that doesn't say anything about what you may have to program up to display some of your app in 320X768.

First off, you're going to need a second grid for your Snap panel. The grid from Application 1 and this new Grid are both to be contained inside a "LayoutRoot" sort of Grid. I renamed the grid from Application 1 to be "NormalDisplayGrid", and made a new Grid that I named "SnapDisplayGrid". There's not much in that extra grid for now... just a Textblock to let me know it when I see it. The result, including the containing Grid looks like this:


<Grid x:Name="LayoutRoot" Background="AliceBlue">
<Grid x:Name="SnapDisplayGrid" Visibility="Collapsed">
<TextBlock Text="Snap" Foreground="Black" FontSize="36"/>
</Grid>
<Grid x:Name="NormalDisplayGrid">
<StackPanel Orientation="Vertical"
HorizontalAlignment="Center"
VerticalAlignment="Center"
>
<TextBlock Text="{Binding Path=ButtonString}"
FontSize="36"
Foreground="Black"/>
<Button Width="150"
Height="30"
Content="Press Me"
HorizontalAlignment="Center"
Background="DarkGray"
Command="{Binding PressCommand}"/>
</StackPanel>
</Grid>
</Grid>


That'll take care of defining the two parts of this simple app. Next we have to get the app launch the correct Grid based on how the app is running. That is taken care of by a bit more code... some xaml and some codebehind.


Visual State Groups

Starting with the xaml to keep that somewhat together in this post, just inside that "LayoutRoot" grid above, add this VisualStateGroups code:



<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="OrientationStates">
<VisualState x:Name="Full" />
<VisualState x:Name="Fill" />
<VisualState x:Name="Portrait" />
<VisualState x:Name="Snapped">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="SnapDisplayGrid">
<DiscreteObjectKeyFrame KeyTime="0" Value="Visible"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="NormalDisplayGrid">
<DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>


The only piece populated is the 'Snapped' Group, and the effect is to make 'SnapDisplayGrid' Visible and collapse 'NormalDisplayGrid'.

We're not quite done with the xaml though... one more line in the header and we're done:



Loaded="Page_Loaded" Unloaded="Page_Unloaded"



Obviously, that will launch a piece of C# when the page is loaded and unloaded, and that's the key to kicking all this magic off.



Code Behind

There's a small amount of C# involved in wiring this up in the code behind, but it is all boilerplate taken directly from one of the template apps:



// View state management for switching among Full, Fill, Snapped, and Portrait states

private DisplayPropertiesEventHandler _displayHandler;
private TypedEventHandler<ApplicationLayout, ApplicationLayoutChangedEventArgs> _layoutHandler;

private void Page_Loaded(object sender, RoutedEventArgs e)
{
if (_displayHandler == null)
{
_displayHandler = Page_OrientationChanged;
_layoutHandler = Page_LayoutChanged;
}
DisplayProperties.OrientationChanged += _displayHandler;
ApplicationLayout.GetForCurrentView().LayoutChanged += _layoutHandler;
SetCurrentViewState(this);
}

private void Page_Unloaded(object sender, RoutedEventArgs e)
{
DisplayProperties.OrientationChanged -= _displayHandler;
ApplicationLayout.GetForCurrentView().LayoutChanged -= _layoutHandler;
}

private void Page_LayoutChanged(object sender, ApplicationLayoutChangedEventArgs e)
{
SetCurrentViewState(this);
}

private void Page_OrientationChanged(object sender)
{
SetCurrentViewState(this);
}

private void SetCurrentViewState(Control viewStateAwareControl)
{
VisualStateManager.GoToState(viewStateAwareControl, this.GetViewState(), false);
}

private String GetViewState()
{
var orientation = DisplayProperties.CurrentOrientation;
if (orientation == DisplayOrientations.Portrait ||
orientation == DisplayOrientations.PortraitFlipped) return "Portrait";
var layout = ApplicationLayout.Value;
if (layout == ApplicationLayoutState.Filled) return "Fill";
if (layout == ApplicationLayoutState.Snapped) return "Snapped";
return "Full";
}



As you can see, the Page_Loaded code wires up the Page Orientation changes and Page Layout changes and then follow that code all the way down to GetViewState and SetCurrentViewState.

If we just look for tracking through to our Snap screen, when the Page Layout changes, SetCurrentViewState is called, which first does GetViewState, decides (maybe) that we're 'Snapped', passes that back and executes VisualStateManager.GoToState for the 'Snapped' state which will switch to our Snap Grid as shown here:



Not a lot of 'meat' in this post, but satisfies the requirement of how the heck you gracefully control that Snap window. Now to get a nice formatted view of your application into 320 pixels... that's the trick.

I'd like to think I'll do another Metro post soon, but if I'm going to try something for the contest myself, I might not post something until that's done.

I've got an idea for an app... think up one too and join me.... and


Stay in the 'Light


Microsoft MVP

Member of WPF and Silverlight Insiders

Creative Commons License

Copyright © 2006-2012, WynApse