Microsoft recently released the Windows 8.1 Preview, providing developers everywhere with a first glimpse at what they need to do to prepare for the next release of the operating system. 8.1 may sound like an incremental release, but the next version of Windows is packed with features enabling developers to create better, faster, richer Windows Store apps. Microsoft has provided a great document summarizing the new features, but I wanted to offer my own take on it by making available a new version of Contoso Cookbook – one that’s faithful to the original, but that was rewritten from the ground up to demonstrate what’s great about Windows 8.1, and what developers should expect to encounter when they port Windows 8 apps to the new platform.
If you’re not familiar with it, Contoso Cookbook is a Windows Store sample app that I wrote last year for Microsoft. It was published on MSDN, complete with 300 pages of labs that developers could use to get up to speed quickly on Windows 8 by developing an end-to-end app in either XAML and C# or HTML5 and JavaScript. Once I got my hands on the Windows 8.1 Preview bits, I updated the XAML and C# version to help developers get up to speed just as quickly on Windows 8.1. (I haven’t updated the labs themselves; I may do that later, but for now all I have to offer is the completed sample code. I haven’t updated the JavaScript version, either, but hope to do that later this summer if time permits.) The new version is pictured below.
You can download a Visual Studio 2013 solution containing the Windows 8.1 Preview version of Contoso Cookbook from SkyDrive and take it for a test drive. It looks a lot like the Windows 8 version on the outside, but there are a few differences. For example, you can now click the Settings charm, select Preferences from the settings menu, and use the Preferences page shown below to specify whether the app should use local (in-package) data or remote data. The latter is hosted in the cloud in Windows Azure. Local data is the default, and is useful if you’re demoing the cookbook and don’t have an Internet connection available. Of course, the Preferences page itself uses Windows 8.1’s new SettingsFlyout control – something that was missing from the XAML run-time in Windows 8 – as does the About page accessed through the settings menu. SettingsFlyout is one of many features of Windows 8.1 that dramatically reduced the amount of code and XAML required to create the cookbook.
The following sections provide an overview of the changes I made to leverage the new infrastructure in Windows 8.1. I made other changes as well – for example, I completely reshaped the JSON data that feeds the app to improve its structure and make it more in keeping with the JSON sample data that Visual Studio provides – but that’s not what’s important. What IS important is what Contoso Cookbook tells us about Windows 8.1 – and along those lines, there’s plenty to talk about.
Tiles
Windows 8 supported two tile sizes: square (150 x 150 pixels) and wide (310 x 150 pixels). Windows 8.1 supports four tile sizes: small (70 x 70), medium (150 x 150), wide (310 x 150), and large (310 x 310). Only the medium tile is required, but apps have the option of supporting the other sizes as well.
To that end, I added a large tile to Contoso Cookbook. You can see the 310 x 310 image file (LargeLogo.png) in the project’s Assets folder, and if you look in the app manifest (on the Application UI tab), you’ll see where I designated it as the large tile image. Now, if you pin Contoso Cookbook to the start screen, you can right-click it and use the Resize button in the application bar at the bottom of the screen to select any of the four tile sizes. Note that you can switch to a small tile even though I didn’t provide a small tile image. The Windows 8.1 Preview generates the small tile image for you if you don’t provide one, but for pixel-perfect small tiles, you always have the option of providing your own 70 x 70 image.
I also made a minor change to the code in ItemDetailPage.xaml.cs that creates a secondary tile to pin a recipe to the Windows start screen. The SecondaryTile class has a new constructor in 8.1, as well a new VisualElements property that lets you control the tile’s foreground and background colors, specify whether text should be shown on the tile, and more. The documentation warns that some of the old constructors “may be altered or unavailable for releases after Windows 8.1 Preview,” so the time is now to fix your code.
Snapping, View State, and Window Size
In Windows 8, any Windows Store app could be snapped – reduced to occupy a 320-pixel-wide slice of the screen. That slice was exactly 320 pixels wide, and if you didn’t like it, well…you just had to get used to it.
Windows 8.1 lets apps be resized continuously down to 500 pixels. And by checking a box in the manifest editor, you can allow your app to be resized down to a width of 320 pixels. In other words, snapping as we knew it has gone away. Most apps don’t have to do anything special to accommodate narrower window widths because Microsoft believes that 500 pixels is wide enough to accommodate most UIs – even those that use GridView controls to scroll horizontally. However, you have the option of responding to changes in window size and adjusting the layout of your UI if necessary to provide a compelling user experience. If your app is one that displays real-time information – for example, a mail app or one that shows stock prices – you might elect to enable the 320-pixel option so a user can keep it on the screen without taking valuable real estate away from other apps. In that case, you’ll almost certainly end up writing logic to adjust the layout when you’re occupying a very narrow slice of the screen. But how that logic is implemented has changed in Windows 8.1.
Most Windows 8 apps written in XAML and C# used logic built into LayoutAwarePage (which was generated by Visual Studio) to drive changes to the layout through Visual State Manager based on changes in view state. The current view state was obtained from ApplicationView.Value and was always set to one of four values: Snapped, Filled, FullScreenPortrait, or FullScreenLandscape. Forget about predefined view states: they don’t exist any more. Neither, for that matter, does LayoutAwarePage. In Windows 8.1, you register your own Window.SizeChanged event handler in each page whose layout you want to change when the window size changes, and you either effect those changes in code, or you call VisualStateManager.GoToState to let Visual State Manager do it for you. Since SizeChanged events don’t fire when a user clicks the Back button to go back to a page, you’ll want to include similar logic in the page’s OnNavigatedTo override as well.
In the original version of Contoso Cookbook, I went to great pains to make sure all three pages looked good in snapped mode. Since the cookbook is probably not an app most users would want to keep on the screen, I did away with the snapped layouts in the new version and accepted the default minimum width of 500 pixels. I did, however, include logic to change the layout of the group-detail and item-detail pages in portrait mode. “Portrait mode” doesn’t necessarily mean the screen orientation is portrait; it means Contoso Cookbook is running in a window that’s taller than it is wide. In the screen shot below, the item-detail page is showing in portrait mode because it’s occupying about half the screen, and the width is currently less than the height. But drag the bar a little further to the right, and the page will snap back into landscape mode and lay out the content the same way it does when it’s running full-screen.
Look inside ItemDetailPage.xaml and you’ll see the Visual State Manager XAML I wrote to define visual states named “Portrait” and “Landscape:”
<VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="ApplicationViewStates"> <VisualState x:Name="Landscape"/> <VisualState x:Name="Portrait"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="landscapeContent" Storyboard.TargetProperty="Visibility"> <DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed"/> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="portraitContent" Storyboard.TargetProperty="Visibility"> <DiscreteObjectKeyFrame KeyTime="0" Value="Visible"/> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups>
Then open ItemDetailPage.xaml.cs and you’ll find the C# code that I wrote to switch between these states:
public ItemDetailPage() { this.InitializeComponent(); this.navigationHelper = new NavigationHelper(this); this.navigationHelper.LoadState += navigationHelper_LoadState; DataTransferManager.GetForCurrentView().DataRequested += OnDataRequested; Window.Current.SizeChanged += (s, e) => UpdateVisualState(); } protected override void OnNavigatedTo(NavigationEventArgs e) { navigationHelper.OnNavigatedTo(e); UpdateVisualState(); } private void UpdateVisualState() { VisualStateManager.GoToState(this, ApplicationView.GetForCurrentView().Orientation.ToString(), false); }
Notice how I used the ApplicationView.Orientation property, which is new in Windows 8.1, to generate the string – either “Portrait” or “Landscape” – that identifies the visual state. ApplicationView also now has properties named IsFullScreen, AdjacentToLeftDisplayEdge, and AdjacentToRightDisplayEdge, which you can use to make adjustments to the layout based on the app’s size and position. Of course, you can also use the width of the window to drive layout changes. In a Window.SizeChanged handler, you can get the width from WindowSizeChangedEventArgs.Size.Width, and outside of SizeChanged (for example, in OnNavigatedTo), you can get it from Window.Current.Bounds.Width.
Search
In Windows 8, developers were encouraged to implement search contracts to support in-app search. The idea was that at any time, a user could pull out the charms bar, tap the Search charm, and initiate a search. It sounded good at the time, but it didn’t work out so well in practice. For one thing, most users never realized that the Search charm existed.
To incorporate Microsoft’s new vision of how search should work, I began by removing the OnSearchActivated override from App.xaml.cs. (It will probably need to be added back in for RTM, but in the preview, it seems that apps can’t be externally search-activated since the search pane no longer shows a list of search-supportive apps). Then I added Windows 8.1’s new SearchBox control to Contoso Cookbook’s start page (you can see it in the upper-right corner of the first screen shot in this article) and wired up handlers for the SuggestionsRequested and QuerySubmitted events that the control fires. These handlers are essentially the same ones that used to be wired up to the search pane; when Microsoft designed the SearchBox control, they intentionally based its API on that of the SearchPane class to make porting easy. Consequently, if you wish to perform an in-app search of recipe data in the new Contoso Cookbook, you don’t go to the Search charm; instead, you type a search term into the search box on the start page and press Enter or tap the magnifying-glass icon.
Microsoft has additional plans to enhance search that haven’t been fully revealed. Look for more news around this important feature when Windows 8.1 RTMs.
AppBars and CommandBars
Another change forthcoming in Windows 8.1 is how you implement application bars, often referred to simply as “appbars.” In Windows 8, you declared an AppBar control, declared a two-column Grid containing StackPanels inside it to separate left commands from right commands, and filled the StackPanels with Button controls stylized to look like appbar buttons. StandardStyles.xaml contained more than 200 button styles to help with the styling.
AppBar controls are still supported for backwards compatibility, and there may be times when you still need them – for example, if you want to include TextBox controls or other non-button controls in an appbar. But Windows 8.1 introduces the CommandBar control, which makes it easier than ever to work appbar magic in your apps. CommandBars host AppBarButton, AppBarToggleButton, and AppBarSeparator controls, which don’t require external styling. And they automatically compact themselves to use space more efficiently in windows that occupy just a portion of the screen.
If you look in ItemDetailPage.xaml, you’ll see how I declared a CommandBar in that page:
<Page.BottomAppBar> <CommandBar> <AppBarButton Icon="Camera" Label="Share"> <AppBarButton.Flyout> <MenuFlyout> <MenuFlyoutItem Text="Photo" Click="OnShootPhoto" /> <MenuFlyoutItem Text="Video" Click="OnShootVideo" /> </MenuFlyout> </AppBarButton.Flyout> </AppBarButton> <AppBarButton Icon="Pin" Label="Pin" Click="OnPinRecipe" /> </CommandBar> </Page.BottomAppBar>
Compare that to the XAML gymnastics required to create the same appbar in the original cookbook and you’ll appreciate the simplicity this brings. Oh, and notice the MenuFlyout control attached to the first AppBarButton. That’s another one of 8.1’s new XAML goodies. To create a menu that pops up when an appbar button is clicked in Windows 8, you had to new up a PopupMenu object and call some obscure XAML methods to position it over the button. In 8.1, you simply declare a MenuFlyout, attach if to a button via the Flyout property, and let the run-time do the work.
Although not shown in my sample, you can put appbar buttons in a <Command.SecondaryCommands> element to position them in the other half of the CommandBar.
Settings Flyouts
One of the elements most glaringly absent from Windows 8’s XAML run-time was a SettingsFlyout control. To display a settings flyout – something almost every Windows Store app does – you either had to craft one from scratch, or get it from a third-party library such as Callisto. Good news: Windows 8.1 includes a SettingsFlyout control. Showing settings flyouts has never been easier, and the control includes a number of helpful properties such as HeaderBackground and HeaderForeground that allow you to style it to match the branding of your app.
To add a settings flyout to your project, you invoke Visual Studio’s Add New Item command and select “Settings Flyout.” Visual Studio then derives a class from SettingsFlyout and drops it into your project, a lot like a user control. Your open the XAML file and insert the content that you want to appear in the flyout, and then displaying the flyout is a simple matter of instantiating it and calling its Show (or ShowIndependent) method:
new AboutSettingsFlyout().Show();
Contoso Cookbook contains two settings flyouts: an About flyout and a Preferences flyout. You can see them by clicking the Settings charm and selecting About or Preferences from the ensuing settings menu. You’ll notice that I set HeaderBackground on both flyouts to the same orangish color used in Contoso Cookbook’s splash screen. Unfortunately, there is still no way to interrogate the system for the color it uses in its own flyouts’ headers, so you just have to pick a color that’s consistent with the styling of your app.
HTTP Networking
In Windows 8, WinRT had great support for sockets networking, WebSocket networking, Bluetooth networking, and even NFC networking. But inexplicably, it had no general-purpose HTTP networking support. Consequently, Windows 8 apps that wanted to communicate with REST services relied on .NET for Windows Store Apps’ HttpClient class.
The .NET version of HttpClient is still there, but in 8.1, WinRT introduces an HttpClient class of its own. Located in the new Windows.Web.Http namespace, WinRT’s HttpClient class offers a few features .NET’s does not, including support for chainable HTTP request filters that allow you to add layered support for authentication, retries, and other HTTP goodies. I rewrote the parts of Contoso Cookbook that rely on HTTP networking to use the WinRT version of HttpClient. Here’s the code in RecipeDataSource that retrieves JSON recipe data from Azure:
_baseUri = "http://contosorecipes8.blob.core.windows.net/"; var cts = new CancellationTokenSource(); cts.CancelAfter(5000); // Wait up to 5 seconds try { var client = new HttpClient(); var response = await client.GetAsync(new Uri(_baseUri + "BlueRecipes")).AsTask(cts.Token); if (!response.IsSuccessStatusCode) { await new MessageDialog("Unable to load remote data (request failed)").ShowAsync(); return; } jsonText = await response.Content.ReadAsStringAsync(); } catch (OperationCanceledException) { new MessageDialog("Unable to load remote data (operation timed out)").ShowAsync(); }
Notice how I included logic to time-out the call to HttpClient.GetAsync if the request doesn’t complete within 5 seconds: I called the AsTask extension method to convert the IAsyncOperationWithProgress returned by GetAsync into a Task, and I passed in a CancellationToken set to time out after 5000 milliseconds. This is something Windows Store developers frequently miss. You have no guarantees when an async network call will complete (or whether it will complete at all), so it’s always a good idea to include a time out so your app doesn’t hang and leave the user wondering what’s happening.
Summary
Contoso Cookbook doesn’t leverage all the new features in the Windows 8.1 Preview, but it certainly hits the highlights. I haven’t compared code counts in the old and new versions, but I can attest that the 8.1 version of Contoso Cookbook required substantially less code and markup to write, thanks in no small part to new controls such as SettingsFlyout.
I’ll update Contoso Cookbook again Windows 8.1 RTMs. Until then, feel free to share the source code with colleagues and try to get them excited about 8.1!
Update: I just created a video based on this blog post and published it for free on WintellectNOW. Check it out and let me know what you think!