[This documentation is preliminary and is subject to change.]
We introduce the essential code and concepts you need to create a Metro style app using C# or Visual Basic. You'll use Extensible Application Markup Language (XAML) to define the UI, and your selected language to write the app logic.
If you'd rather use another programming language, see:
Roadmap: How does this topic relate to others? See: Roadmap for Metro style apps using C# or Visual Basic.
Objectives
In this tutorial, we take a quick tour of the features that you'll use to build Metro style apps. Through the process of creating a simple blog reader app, we introduce concepts that are core to development with XAML, including layout, controls, templates, and data binding. We learn how to use the page templates and navigation that are built into Microsoft Visual Studio Express 2012 RC for Windows 8 to quickly start our app development. We then learn how to use custom styles to modify the look of our app, and how to adapt the UI to various layouts and views. Finally, we briefly discuss integrating our app with Windows 8 Release Preview and publishing it to the Windows Store. By the time you complete this tutorial, you'll be prepared to start building your own Metro style apps.
The tutorial takes you about 30 minutes to read, longer if you do the exercises.
Hello World
When you create your Metro style app using C# or Visual Basic, you typically define the UI using XAML, and write your app logic in an associated code behind file in your selected language. The XAML UI framework for Metro style apps using C# or Visual Basic is in the Windows.UI.Xaml.* namespaces of the Windows Runtime. If you've written apps using Windows Presentation Foundation (WPF), Microsoft Silverlight, or Silverlight for Windows Phone, you're already familiar with this programming model and you can use this experience to create your Metro style app using C++, C#, or Visual Basic.
The example here shows the XAML that defines the UI for a simple Hello World app and its associated code behind page. Even this simple example shows several concepts that are important to the XAML-based programming model, including partial classes, layout, controls, properties, and events.
<Page x:Class="WindowsBlogReader.MainPage" IsTabStop="false" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:WindowsBlogReader" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"> <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}"> <StackPanel> <Button Content="Click Me" Click="HelloButton_Click" /> <TextBlock x:Name="DisplayText" FontSize="48" /> </StackPanel> </Grid> </Page>
using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Navigation; namespace WindowsBlogReader { public sealed partial class MainPage : Page { public MainPage() { InitializeComponent(); } private void HelloButton_Click(object sender, RoutedEventArgs e) { DisplayText.Text = "Hello World"; } } }
A Hello World app is good place to start. But it doesn't take you very far down the road to profitability, so we'll take a different path as we explore building Metro style apps for Windows 8. The sample app that we use to get started is a simple blog reader that downloads and displays data from a Really Simple Syndication (RSS) 2.0 or Atom 1.0 feed. It seems appropriate to use the feeds from the Windows team blogs site. Here's one of these, the Developing for Windows blog.

Creating Windows Metro style apps in Visual Studio
In this section, you will learn how to:
- create a new Windows Metro style project in Visual Studio Express 2012 RC for Windows 8.
Microsoft Visual Studio is a powerful Integrated Development Environment (IDE) for developing Windows apps. It provides source file management; integrated build, deployment and launching support; XAML, Visual Basic, C#, C++, graphics, and manifest editing; debugging, and more. Visual Studio comes in several editions, but we'll use Visual Studio Express 2012 RC for Windows 8. You can download it for free along with the Windows Software Development Kit (SDK) for Metro style Apps so that you have everything you need to build, package and deploy your Metro style apps.
To get started creating an app, you create a new Windows Metro style project using C# or Visual Basic. Visual Studio Express 2012 RC for Windows 8 includes several templates for Windows Metro style projects that give you a head start on apps using a variety of layouts. The Blank App (XAML) project template provides the minimum files you need for any Windows Metro style app.
For more info about Visual Studio Express 2012 RC for Windows 8, see Visual Studio 11 Beta.
To create a new Windows Metro style project
- Open Visual Studio Express 2012 RC for Windows 8.
- Select File > New Project. The New Project dialog box opens.
- In the Installed pane, expand Visual C# or Visual Basic.
- Select the Windows Metro style template type.
- In the center pane, select Blank App (XAML).
- Enter a name for the project. Name this project "WindowsBlogReader".
Here's a new project being created in Visual Studio Express 2012 RC for Windows 8.

- Click OK. Your project files are created.
When you create your project, Visual Studio creates the project files and displays them in Solution Explorer. Let's look at the files that the Blank App (XAML) template created.
| File Name | Description |
|---|---|
| Properties/AssemblyInfo (.vb or .cs) | Contains the name and version metadata that is embedded into the generated assembly. |
| Package.appxmanifest | Contains metadata that describes your app, including display name, description, logos, and capabilities. |
| Assets/* | The default logo and splash screen images that you can replace with your own. |
| Common/StandardStyles.xaml | Contains default styles and templates for the app. |
| App.xaml, App.xaml.* (.vb, .cs) | These files specify app-level logic. The App class is required to display the user interface. |
| MainPage.xaml | The default start page that you use to create the user interface. |
| MainPage.xaml.* (.vb, .cs) | The code-behind file that contains the logic for the default start page. |
To learn more about these files and templates, see Jumpstart your Metro style app using templates (C#, C++, Visual Basic).
Specifying app capabilities
In this section, you will learn how to:
- use capabilities
- specify app capabilities in the Application Manifest Designer.
A Metro style app runs in a security container with limited access to the file system, network resources, and hardware. Whenever a user installs an app from the Windows Store, Windows looks at the metadata in the Package.appxmanifest file to figure out what capabilities the app needs to function. For example, an app might need to access data from the Internet, documents from the user's documents library, or the user's webcam and microphone. When the app is installed, it displays to the user the capabilities it needs, and the user must grant permission for it to access those resources. If the app doesn't request and receive access to a resource it needs, it will not be allowed access to that resource when the user runs it.
Here are some common capabilities:
| Capability | Description |
|---|---|
| Documents Library Access | Allows your app to access the user's Document Library, and to add, change, or delete files. Your app can access only file types that it has declared in the manifest. Your app cannot access Document Libraries on HomeGroup computers. |
| Enterprise Authentication | Allows an app to connect to intranet resources that require domain credentials. |
| Home or Work Networking | Allows inbound and outbound access from your app to the user's trusted networks such as home and enterprise networks. Inbound access to critical ports is always blocked. |
| Internet (Client & Server) | Allows your app to access the Internet and public networks, and allows incoming connections from the Internet to your app. Inbound access to critical ports is always blocked. This is a superset of the Internet (Client) capability. You do not need to declare both. |
| Internet (Client) | Allows your app to access the Internet and public networks. Most apps that require Internet access should use this capability. |
| Location | Allows your app to access the user's current location. |
| Microphone | Allows your app to access the user's microphone. |
| Music Library | Allows your app to access the user's Music Library, and to add, change, or delete files. It also allows access to Music Libraries on HomeGroup computers, and music file types on locally connected media servers. |
| Pictures Library Access | Allows your app to access the user's Picture Library, and to add, change, or delete files. It also allows access to Picture Libraries on HomeGroup computers, and picture file types on locally connected media servers. |
| Proximity | Allows your app to access the user's near-field communication (NFC) device. |
| Removable Storage | Allows your app to access removable storage devices, such as an external hard drive or USB flash drive, and to add, change, or delete files. Your app can access only file types that it has declared in the manifest. Your app can't access removable storage devices on HomeGroup computers. |
| Shared User Certificates | Allows your app to access software and hardware certificates, such as smart card certificates. |
| Text Messaging | Allows your app to access text messaging functionality. |
| Videos Library Access | Allows your app to access the user's Video Library, and to add, change, or delete files. It also allows access to Video Libraries on HomeGroup computers, and video file types on locally connected media servers. |
| Webcam | Allows your app to access the user's camera. |
To add capabilities to an app
- In Solution Explorer, double-click Package.appxmanifest. The file opens in the Application Manifest Designer.
- In the Application Manifest Designer, select the Capabilities tab.
- Select the check box next to each capability that your app needs. (Internet (Client) is selected by default. This is all we need for our blog reader app.)
- Save and close the file.
Getting data into an app
In this section, you will learn how to:
- create a custom data class
- retrieve an RSS or Atom data feed asynchronously.
Now that we declared the internet capability, we can write the code to get the blog feed into the app. The Windows team blogs expose the full text of the posts in both RSS and Atom form. The blog data that we want to display in our reader app is the title, author, date, and content from each of the latest blog posts.
To start, we need to download the data for each of the posts. Fortunately, the Windows Runtime contains a set of classes that does a lot of the work of processing the feed data for us. We find these classes in the Windows.Web.Syndication namespace. It’s possible to use these classes directly to show the data in the UI. But in our blog reader, we create our own data classes. This gives us some additional flexibility and allows us to treat RSS and Atom feeds in the same way.
To add a new class file to a project
- Select Project > Add Class. The New Item dialog box opens.
- Enter a name for the class file. In this example we use
FeedData. - Click Add. Your new class file is created.
We use 3 classes to hold and retrieve the feed data in our blog reader app. We put all 3 classes in one file named FeedData (.cs or .vb). The FeedData class holds info about the RSS or Atom feed. The FeedItem class holds info about individual blog posts that the feed contains. The FeedDataSource class contains a collection of feeds and a method to retrieve the feeds from the network. Here's the code for these classes.
using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Threading.Tasks; using Windows.Web.Syndication; namespace WindowsBlogReader { // FeedData // Holds info for a single blog feed, including a list of blog posts (FeedItem) public class FeedData { public string Title { get; set; } public string Description { get; set; } public DateTime PubDate { get; set; } private List<FeedItem> _Items = new List<FeedItem>(); public List<FeedItem> Items { get { return this._Items; } } } // FeedItem // Holds info for a single blog post public class FeedItem { public string Title { get; set; } public string Author { get; set; } public string Content { get; set; } public DateTime PubDate { get; set; } public Uri Link { get; set; } } // FeedDataSource // Holds a collection of blog feeds (FeedData), and contains methods needed to // retreive the feeds. public class FeedDataSource { private ObservableCollection<FeedData> _Feeds = new ObservableCollection<FeedData>(); public ObservableCollection<FeedData> Feeds { get { return this._Feeds; } } public async Task GetFeedsAsync() { Task<FeedData> feed1 = GetFeedAsync("http://windowsteamblog.com/windows/b/developers/atom.aspx"); Task<FeedData> feed2 = GetFeedAsync("http://windowsteamblog.com/windows/b/windowsexperience/atom.aspx"); Task<FeedData> feed3 = GetFeedAsync("http://windowsteamblog.com/windows/b/extremewindows/atom.aspx"); Task<FeedData> feed4 = GetFeedAsync("http://windowsteamblog.com/windows/b/business/atom.aspx"); Task<FeedData> feed5 = GetFeedAsync("http://windowsteamblog.com/windows/b/bloggingwindows/atom.aspx"); Task<FeedData> feed6 = GetFeedAsync("http://windowsteamblog.com/windows/b/windowssecurity/atom.aspx"); Task<FeedData> feed7 = GetFeedAsync("http://windowsteamblog.com/windows/b/springboard/atom.aspx"); Task<FeedData> feed8 = GetFeedAsync("http://windowsteamblog.com/windows/b/windowshomeserver/atom.aspx"); // There is no Atom feed for this blog, so we use the RSS feed. Task<FeedData> feed9 = GetFeedAsync("http://windowsteamblog.com/windows_live/b/windowslive/rss.aspx"); Task<FeedData> feed10 = GetFeedAsync("http://windowsteamblog.com/windows_live/b/developer/atom.aspx"); Task<FeedData> feed11 = GetFeedAsync("http://windowsteamblog.com/ie/b/ie/atom.aspx"); Task<FeedData> feed12 = GetFeedAsync("http://windowsteamblog.com/windows_phone/b/wpdev/atom.aspx"); Task<FeedData> feed13 = GetFeedAsync("http://windowsteamblog.com/windows_phone/b/wmdev/atom.aspx"); this.Feeds.Add(await feed1); this.Feeds.Add(await feed2); this.Feeds.Add(await feed3); this.Feeds.Add(await feed4); this.Feeds.Add(await feed5); this.Feeds.Add(await feed6); this.Feeds.Add(await feed7); this.Feeds.Add(await feed8); this.Feeds.Add(await feed9); this.Feeds.Add(await feed10); this.Feeds.Add(await feed11); this.Feeds.Add(await feed12); this.Feeds.Add(await feed13); } private async Task<FeedData> GetFeedAsync(string feedUriString) { // using Windows.Web.Syndication; SyndicationClient client = new SyndicationClient(); Uri feedUri = new Uri(feedUriString); try { SyndicationFeed feed = await client.RetrieveFeedAsync(feedUri); // This code is executed after RetrieveFeedAsync returns the SyndicationFeed. // Process it and copy the data we want into our FeedData and FeedItem classes. FeedData feedData = new FeedData(); feedData.Title = feed.Title.Text; if (feed.Subtitle != null && feed.Subtitle.Text != null) { feedData.Description = feed.Subtitle.Text; } // Use the date of the latest post as the last updated date. feedData.PubDate = feed.Items[0].PublishedDate.DateTime; foreach (SyndicationItem item in feed.Items) { FeedItem feedItem = new FeedItem(); feedItem.Title = item.Title.Text; feedItem.PubDate = item.PublishedDate.DateTime; feedItem.Author = item.Authors[0].Name.ToString(); // Handle the differences between RSS and Atom feeds. if (feed.SourceFormat == SyndicationFormat.Atom10) { feedItem.Content = item.Content.Text; feedItem.Link = new Uri("http://windowsteamblog.com" + item.Id); } else if (feed.SourceFormat == SyndicationFormat.Rss20) { feedItem.Content = item.Summary.Text; feedItem.Link = item.Links[0].Uri; } feedData.Items.Add(feedItem); } return feedData; } catch (Exception) { return null; } } } }
Now that we've added these data classes, click Build > Build solution, or press F7 to make sure the solution builds without error.
Retrieving the feed data
Let's take a closer look at how we download the blog feeds. The Windows.Web.Syndication.SyndicationClient class retrieves a fully parsed RSS or Atom feed, so we can use the data without worrying about parsing XML. To download a feed using the SyndicationClient class, we have to use the asynchronous RetrieveFeedAsync method. The asynchronous programming model is common in the Windows Runtime to help apps remain responsive. Fortunately, much of the complexity you might expect when using asynchronous methods has been taken care of for us.
Using await in C# and Visual Basic
Using the await keyword in C# and Visual Basic, the code for retrieving the feed asynchronously is similar to the code we would use to retrieve the feed synchronously. Let's take a look.
In the GetFeedsAsync method, we call GetFeedAsync for each of the blog feeds we want to retrieve. Where possible, we pass in the URL for the Atom feed because it includes author data that we want to show. When each blog feed is returned, we add it to the FeedDataSource.Feeds collection.
public async Task GetFeedsAsync() { Task<FeedData> feed1 = GetFeedAsync("http://windowsteamblog.com/windows/b/developers/atom.aspx"); ... this.Feeds.Add(await feed1); ... }
Now let's look at the GetFeedAsync method in more detail to see how the await keyword helps us. The first thing to notice is that we add the async keyword to the method signature.
You can use the await keyword only in a method that's defined as async. We specify the return type as Task<FeedData>. This tells the compiler to generate a Task that represents the FeedData object that the method retrieves.
Inside the method, we instantiate a SyndicationClient and call its RetrieveFeedAsync method to get the SyndicationFeed that contains the RSS or Atom info that we want.
The await keyword here tells the compiler to do a lot of work for us behind the scenes. The compiler schedules the rest of the method after this call as a callback to be executed when the call returns. It then immediately returns control to the calling thread, typically the UI thread, so that the app remains responsive. The Task that represents the eventual outcome of this method, a FeedData object, is returned to the caller at this point.
When RetrieveFeedAsync returns the SyndicationFeed with the data we want, the rest of the code in our method is executed. And, importantly, it's executed in the same thread context that we made the original call from (the UI thread), so we don't have to worry about using a dispatcher if we want to update the UI in this code. With the SyndicationFeed retrieved, we copy the parts we need into our FeedData and FeedItem data classes.
// This code is executed after RetrieveFeedAsync returns the SyndicationFeed. // Process it and copy the data we want into our FeedData and FeedItem classes. FeedData feedData = new FeedData(); feedData.Title = feed.Title.Text; if (feed.Subtitle != null && feed.Subtitle.Text != null) { feedData.Description = feed.Subtitle.Text; } // Use the date of the latest post as the last updated date. feedData.PubDate = feed.Items[0].PublishedDate.DateTime; foreach (SyndicationItem item in feed.Items) { FeedItem feedItem = new FeedItem(); feedItem.Title = item.Title.Text; feedItem.PubDate = item.PublishedDate.DateTime; feedItem.Author = item.Authors[0].Name.ToString(); // Handle the differences between RSS and Atom feeds. if (feed.SourceFormat == SyndicationFormat.Atom10) { feedItem.Content = item.Content.Text; feedItem.Link = new Uri("http://windowsteamblog.com" + item.Id); } else if (feed.SourceFormat == SyndicationFormat.Rss20) { feedItem.Content = item.Summary.Text; feedItem.Link = item.Links[0].Uri; } feedData.Items.Add(feedItem); } return feedData;
When we get to the return statement, we're not actually returning a FeedData object. Remember that when the method returned to the caller immediately after the await statement, it returned a Task to represent the eventual result of the method. Here, we finally get the result. The line return feedData;, gives the FeedData object that is the result of the method to the Task that is waiting for it.
The Task was awaited at this line in the GetFeedsAsync method.
When the Task gets the FeedData result that it's waiting for, the code execution proceeds and the FeedData is added to the FeedDataSource.Feeds collection.
Using the data in the app
To use the data in our app, we create an instance of the data source as a resource in App.xaml. We name the instance feedDataSource.
To add a resource to an app
- Double-click App.xaml in Solution Explorer. The file opens in the XAML editor.
- Add
<ResourceDictionary> </ResourceDictionary>tags inside the MergedDictionaries collection. - Add the resource declaration,
<local:FeedDataSource x:Key="feedDataSource"/>, to the new ResourceDictionary.
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<!--
Styles that define common aspects of the platform look and feel
Required by Visual Studio project and item templates
-->
<ResourceDictionary Source="Common/StandardStyles.xaml"/>
<!-- Add app resurces to this resource dictionary -->
<ResourceDictionary>
<local:FeedDataSource x:Key="feedDataSource"/>
</ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
The page template already has an override of the OnNavigatedTo method in its code-behind file. We put our code in this method to get the App's instance of FeedDataSource and get the feeds. First, we add the async keyword to the method declaration because we use the await keyword inside the method. When we navigate to the page, we check to see if the FeedDataSource already contains feeds. If it doesn't, we call the FeedDataSource.GetFeedsAsync method. Then we set the DataContext of the page to the first feed. Here's the relevant code for MainPage.xaml.cs/vb.
protected override async void OnNavigatedTo(NavigationEventArgs e)
{
FeedDataSource feedDataSource = (FeedDataSource)App.Current.Resources["feedDataSource"];
if (feedDataSource != null)
{
if (feedDataSource.Feeds.Count == 0)
{
await feedDataSource.GetFeedsAsync();
}
this.DataContext = (feedDataSource.Feeds).First();
}
}
You can build and run the app in debugging mode to make sure it builds and retrieves the feeds without error. To run the app in debugging mode, click Debug > Start debugging, or press F5. If there are no errors, the app will run, but only show a black screen. To return to Visual Studio, press Alt+Tab. In Visual Studio, click Debug > Stop debugging to close the app. If there are errors, Visual Studio shows info about the error. To learn more about running apps in Visual Studio, see Running Metro style apps from Visual Studio.
Defining the app layout in XAML
Note In the next 3 sections, Defining the app layout in XAML, Adding controls and content, and Displaying data, we go over the basics of creating a user interface in XAML. To learn these basics, we create a simple one page blog reader that displays the posts of a single blog feed. If you already have experience with XAML and are familiar with XAML layout, controls, and data binding, you can skim these sections without completing the exercises. But don't skip adding the code for the date converter; we use that later in our app. We get back to creating our full Metro style app in the section, Adding pages and navigation.
In this section, you will learn:
- what panels you can use to define a layout in XAML
- how to define rows and columns in a Grid
- how to use a StackPanel.
The app layout specifies the size and position of each object in your app. To position visual objects, you must put them in a Panel control or other container object. The XAML layout system provides various Panel controls, such as Grid, Canvas, and StackPanel, that serve as containers in which you arrange the controls.
The XAML layout system supports both absolute layout and dynamic layout. In an absolute layout, you position controls using explicit x and y coordinates (for example, by using a Canvas). In a dynamic layout, the layout container and the controls can be automatically sized and repositioned as the app resizes (for example, by using a StackPanel or a Grid). In practice, you typically define the layout of your app by combining absolute and dynamic layouts, and by embedding panels within other panels.
A typical layout for a blog reader app looks like this, with the title at the top, a list of posts on the left, and the content of the selected post on the right.

By default, the blank app template includes only an empty Grid that is the root element for our UI. To specify our layout, we divide the Grid into two rows. The top row holds the blog title. In the second row, we embed another Grid, divide it into two columns, and add some more layout containers to display the blog content.
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="140" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<!-- Title -->
<!-- Content -->
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*" MinWidth="320" />
<ColumnDefinition Width="3*" />
</Grid.ColumnDefinitions>
<!-- Left column -->
<ListView x:Name="ItemListView" />
<!-- Right column -->
<Grid Grid.Column="1" >
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
</Grid>
</Grid>
</Grid>
Let's look at what this XAML does in more detail. To define rows in a Grid, you add RowDefinition objects to the Grid.RowDefinitions collection. You can set properties on the RowDefinition to specify what the row will look like. You add columns in the same way, using ColumnDefinition objects and the Grid.ColumnDefinitions collection.
In XAML, the row definitions looks like this:
<Grid.RowDefinitions> <RowDefinition Height="140"/> <RowDefinition Height="*"/> </Grid.RowDefinitions>
The Height="140" property setting on the first row definition (row 0) sets the top row to an absolute height of 140 device-independent pixels (DIPs). This height doesn't change regardless of the size of the row contents or the app. The Height="*" setting on the second row definition (row 1) tells the bottom row to take up whatever space is left after row 0 has sized itself. This is often called star sizing. We also use star sizing in the column definitions of the second Grid. The width settings of Width="2*" and Width="3*" tell the Grid to divide itself into 5 equal parts. Two parts are used for the first column, and three parts are used for the second column.
To position an element within the Grid, you set the Grid.Row and Grid.Column attached properties on the element. The row and column numbering is zero-based. The default value of these properties is 0, so if you don't set anything, the element will go into the first row and the first column.
The <Grid Grid.Row="1"> element embeds a Grid within the bottom row of the root Grid. This Grid is divided into two columns.
The element <ListView x:Name="ItemListView"> adds a ListView to the left hand column of the bottom Grid. The element <Grid Grid.Column="1"> adds another Grid to the right hand column of the bottom Grid. We divide this Grid into two rows. The setting Height="Auto" tells the top row to make itself as tall as it needs to be to fit its content. The bottom row uses whatever space is left.
The last part of our UI that needs a layout panel is the list of blog posts. In this list, we need to arrange the title, author, and date as shown here.

You typically use a StackPanel when you want to automatically arrange consecutive elements in a small subsection of the UI on your page. The StackPanel is a simple layout panel that arranges its child elements into a single line that can be oriented horizontally or vertically. You can use the StackPanel.Orientation property to specify the direction of the child elements. The default value for the Orientation property is Orientation.Vertical. We use a StackPanel to arrange the items in our list of blog posts. We see it in use in the section, Formatting data with a data template. The XAML for the StackPanel looks like this.
<StackPanel> <TextBlock Text="{Binding Path=Title}" FontSize="24" Margin="5,0,0,0" TextWrapping="Wrap" /> <TextBlock Text="{Binding Path=Author}" FontSize="16" Margin="15,0,0,0"/> <TextBlock Text="{Binding Path=PubDate}" FontSize="16" Margin="15,0,0,0"/> </StackPanel>
Adding controls and content
In this section, you will learn how to:
- add controls to an app
Layout panels are important, but they're not very interesting without content to put in them. You create the UI for your app by adding controls such as buttons, lists, text, graphics, and images. The elements you use depend on what your app does. For a complete list of the controls we can use in our Metro style app, see the Controls list.
Looking at the sketch of our blog reader UI, it's clear that we need to display one-line text (the blog and post titles), multiline-text (the post content), and a list of blog posts. We add TextBlock controls to display the titles, and a ListView control to display the list of blog posts. At first glance, it seems that we might use a multi-line TextBlock or RichTextBlock to display the post content. But, when we dig deeper, we see that the string that contains the post content is not plain text, but a string of HTML. We don't want to display a bunch of HTML tags, which is what will happen if we put the string in a TextBlock, so we use a WebView control to display the HTML.
With controls added, the XAML for our UI now looks like this.
<Page x:Class="WindowsBlogReader.MainPage" IsTabStop="false" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:WindowsBlogReader" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"> <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}"> <Grid.RowDefinitions> <RowDefinition Height="140" /> <RowDefinition Height="*" /> </Grid.RowDefinitions> <!-- Title --> <TextBlock x:Name="TitleText" Text="{Binding Title}" VerticalAlignment="Center" FontSize="48" Margin="56,0,0,0"/> <!-- Content --> <Grid Grid.Row="1"> <Grid.ColumnDefinitions> <ColumnDefinition Width="2*" MinWidth="320" /> <ColumnDefinition Width="3*" /> </Grid.ColumnDefinitions> <!-- Left column --> <!-- The default value of Grid.Column is 0, so we do not need to set it to make the ListView show up in the first column. --> <ListView x:Name="ItemListView" ItemsSource="{Binding Items}" Margin="60,0,0,10"> </ListView> <!-- Right column --> <!-- We use a Grid here instead of a StackPanel so that the WebView sizes correctly. --> <Grid DataContext="{Binding ElementName=ItemListView, Path=SelectedItem}" Grid.Column="1" Margin="25,0,0,0"> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition Height="*" /> </Grid.RowDefinitions> <TextBlock x:Name="PostTitleText" Text="{Binding Title}" FontSize="24"/> <WebView x:Name="ContentView" Grid.Row="1" Margin="0,5,20,20"/> </Grid> </Grid> </Grid> </Page>
Now press F5 to build and run the app in debugging mode, and get your first look at the app UI. There's not much there yet, but if there are no errors, you'll see a screen like this. To return to Visual Studio, press Alt+Tab. In Visual Studio, click Debug > Stop debugging to close the app.

Displaying data
In this section, you will learn how to:
- bind data to UI
- format data with templates.
Binding data to UI
In the Hello World app that we started with, we updated the text in the UI by setting the Text property of the TextBlock in this button click event handler.
private void HelloButton_Click(object sender, RoutedEventArgs e) { DisplayText.Text = "Hello World"; }
Sometimes setting a Text property in code like this works well. But to display data, you typically use data binding to connect a data source to the UI. When you establish a binding and the data source changes, the UI elements that are bound to the data source can reflect changes automatically. Similarly, changes made by the user in a UI element can be reflected in the data source. For example, if the user edits the value in a TextBox, the binding engine automatically updates the underlying data source to reflect that change.
In the blog reader app, we show the blog title by binding the Text property of the title TextBlock to the Title property of a source object.
<TextBlock x:Name="TitleText" Text="{Binding Title}" VerticalAlignment="Center" FontSize="48" Margin="56,0,0,0" />
We show the title of the selected blog post in the same way.
<TextBlock x:Name="PostTitleText" Text="{Binding Title}" FontSize="24"/>
But wait! If both TextBlocks have exactly the same binding, how do they show different titles? The answer is in the DataContext that each TextBlock is bound to. The DataContext property lets you set the default binding for an entire UI element, including all of its child elements. Sometimes, you set the DataContext property for an entire page, and at other times, you set it for individual elements on the page. The DataContext setting at each XAML level overrides any settings at a higher level. Also, you can override any DataContext setting in effect for an individual binding by setting its Source property.
In the blog reader app, we set the DataContext for the whole page in the code behind. Remember that after retrieving the data feed, we set the DataContext with this line of code.
protected override async void OnNavigatedTo(NavigationEventArgs e)
{
...
this.DataContext = (feedDataSource.Feeds).First();
}
The context of the first TextBlock is the FeedData object, so it shows the FeedData.Title property.
How does the second TextBlock show the title of the selected blog post? The second TextBlock is within a Grid, as we see here.
<Grid DataContext="{Binding ElementName=ItemListView, Path=SelectedItem}" Grid.Column="1" Margin="25,0,0,0"> ... <TextBlock x:Name="PostTitleText" Text="{Binding Title}" FontSize="24"/> ... </Grid>
The DataContext of the Grid is bound to the SelectedItem property of the ListView. So again the binding engine works for us behind the scenes. Whenever the selection changes in the ListView, the DataContext of the StackPanel is updated automatically to be the selected post. The DataContext of the Grid overrides the DataContext of the page, so the second TextBlock displays the FeedItem.Title property of the selected blog post.
Each binding has a Mode property that specifies how and when the data is updated.
| Binding mode | Description |
|---|---|
| OneTime | The value is set on the target only when the binding is first created, but never updated after that. |
| OneWay | The target is updated if the source changes. |
| TwoWay | Both the target and the source are updated if either one changes. |
If you use OneWay or TwoWay bindings, for the binding to be notified of changes to the source object, you must implement the INotifyPropertyChanged interface. For more info about data binding, see QuickStart: Data binding to controls.
Formatting data with a data template
Showing the data we want in the list view is slightly more complex than just setting the binding. We have the ListView bound to the Items property of the FeedData object, so the correct data is there. But when we run the app like this, the ListView doesn't know what to show, so it just calls ToString on the object it's bound to. That gives us a list of "WindowsBlogReader.FeedItem" strings like we saw previously. Clearly, this is not what we want to show.
We can make it a little better by setting the DisplayMemberPath property on the ListView. This tells the list view to call ToString on the specified property of the bound object, instead of on the object itself. If we set DisplayMemberPath=Title, the ListView shows a list of blog post titles.
<ListView x:Name="ItemListView" ItemsSource="{Binding Items}" DisplayMemberPath="Title" Margin="60,0,0,10"> </ListView>
Press F5 to build and run the app, and now the list items look like this. This is closer to what we want to show.

But what we really want is to show the title, author, and published date for each post in the list. For that, we define a template that tells the ListView exactly how we want the data displayed. The controls for viewing collections of data items are derived from the ItemsControl class. These controls have an ItemTemplate property that we can assign a DataTemplate to. The DataTemplate defines how our data looks.
Important You can't use the DisplayMemberPath and an ItemTemplate at the same time. When you add the ItemTemplate to the ListView, be sure to remove the DisplayMemberPath setting.
Here's the XAML for the ListView using a DataTemplate defined inline instead of DisplayMemberPath.
<ListView x:Name="ItemListView" ItemsSource="{Binding Items}" Margin="60,0,0,10"> <ListView.ItemTemplate> <DataTemplate> <StackPanel> <TextBlock Text="{Binding Title}" FontSize="24" Margin="5,0,0,0" TextWrapping="Wrap" /> <TextBlock Text="{Binding Author}" FontSize="16" Margin="15,0,0,0"/> <TextBlock Text="{Binding PubDate}" FontSize="16" Margin="15,0,0,0"/> </StackPanel> </DataTemplate> </ListView.ItemTemplate> </ListView>
Defining the bit of UI inside the DataTemplate is just like defining any other UI. We use a StackPanel to stack 3 TextBlocks on top of each other. We then bind the Text property of the TextBlocks to the Title, Author, and PubDate properties. The default DataContext for these bindings is the object displayed in the ListView, which is a FeedItem.
Press F5 to build and run the app. Here's what the list looks like when we use a template to define it's appearance.

Formatting data with a value converter
In ItemListView's DataTemplate, we bind the PubDate property, which is a DateTime, to a TextBlock.Text property. The binding engine automatically converts PubDate from a DateTime to a string. But the automatic conversion shows both the date and the time, and we want to show only the date. To fix this, we can create our own value converter that converts a DateTime to a string, and in it we can format the string however we want to.
To create a value converter, we create a class that implements the IValueConverter interface and then implement the Convert and ConvertBack methods. Converters can change data from one type to another, translate data based on cultural info, or modify other aspects of the presentation. Here, we create a date converter that converts the date value passed in and formats it so that it shows only the day, the month, and the year.
Note To add a new class to the project, select Project > Add Class. Name the class DateConverter (.cs or .vb).
The Convert and ConvertBack methods also let you pass in a parameter so that you can use the same instance of the converter with different options. In this example, we have a formatting converter that produces different formats of the date based on the input parameter. You can use the ConverterParameter of the Binding class to pass a parameter as an argument into the Convert and ConvertBack methods. Later, we modify our list view to demonstrate this.
using System; using Windows.Globalization.DateTimeFormatting; namespace WindowsBlogReader { public class DateConverter : Windows.UI.Xaml.Data.IValueConverter { public object Convert(object value, Type targetType, object parameter, string culture) { if (value == null) throw new ArgumentNullException("value", "Value cannot be null."); if (!typeof(DateTime).Equals(value.GetType())) throw new ArgumentException("Value must be of type DateTime.", "value"); DateTime dt = (DateTime)value; if (parameter == null) { // Date "7/27/2011 9:30:59 AM" returns "7/27/2011" return DateTimeFormatter.ShortDate.Format(dt); } else if ((string)parameter == "day") { // Date "7/27/2011 9:30:59 AM" returns "27" DateTimeFormatter dateFormatter = new DateTimeFormatter("{day.integer(2)}"); return dateFormatter.Format(dt); } else if ((string)parameter == "month") { // Date "7/27/2011 9:30:59 AM" returns "JUL" DateTimeFormatter dateFormatter = new DateTimeFormatter("{month.abbreviated(3)}"); return dateFormatter.Format(dt).ToUpper(); } else if ((string)parameter == "year") { // Date "7/27/2011 9:30:59 AM" returns "2011" DateTimeFormatter dateFormatter = new DateTimeFormatter("{year.full}"); return dateFormatter.Format(dt); } else { // Requested format is unknown. Return in the original format. return dt.ToString(); } } public object ConvertBack(object value, Type targetType, object parameter, string culture) { string strValue = value as string; DateTime resultDateTime; if (DateTime.TryParse(strValue, out resultDateTime)) { return resultDateTime; } return Windows.UI.Xaml.DependencyProperty.UnsetValue; } } }
With the DateConverter class added, press F7 to make sure the solution builds without error.
Before we can use the DateConverter class, we must declare an instance of it in our XAML. We declare it with the key dateConverter as a resource of the app in App.xaml. Declaring it here makes it available for every page in our app to use.
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
...
<ResourceDictionary>
<local:FeedDataSource x:Key="feedDataSource"/>
<!-- Add the DateConverter here. -->
<local:DateConverter x:Key="dateConverter" />
</ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
Now we can use the DateConverter in our binding. Here's the updated binding for PubDate from ItemListView's DataTemplate.
<TextBlock Text="{Binding Path=PubDate, Converter={StaticResource dateConverter}}" FontSize="16" Margin="15,0,0,0"/>
With this XAML, the binding engine uses our custom DateConverter to change a DateTime to a string. The string that it returns is formatted the way we want, with only the day, month, and year.
Press F5 to build and run the app. The time is no longer displayed in the list view.
Displaying HTML in a WebView
To show a blog post in our page the final step is to get the post data to show in the WebView control. We already added this control, ContentView, to our UI.
<WebView x:Name="ContentView" Grid.Row="1" Margin="0,5,20,20"/>
The WebView control gives us a way to host HTML data within our app. But if we look at its Source property, we see that it takes the Uri of the web page to display. Our HTML data is just a string of HTML. It doesn't have a Uri that we can bind to the Source property. Luckily, there is a NavigateToString method that we can pass our string of HTML to.
To make this work, we handle the ListView's SelectionChanged event.
To add an event handler
- In XAML or design view, select the control that you need to handle an event for. In this example, click
ItemListViewin MainPage.xaml. - In the Properties Window, click the Events button (
).Tip If you don't see the Properties Window, press Alt+Enter to open it.
- Find the SelectionChanged event in the event list. In the text box for the event, type "ItemListView_SelectionChanged".

- Press Enter. The event handler is created and opened in the code editor. Add code that's executed when the event occurs.
Here's the XAML for the ListView with the SelectionChanged event added.
<ListView x:Name="ItemListView" ItemsSource="{Binding Items}" Margin="60,0,0,10" SelectionChanged="ItemListView_SelectionChanged"> ...
We add our code to the event handler that was created in the code behind page. In the event handler, we cast the selected item to a FeedItem and get the string of HTML from the Content property. We then pass the string to the NavigateToString method. If no item is selected, we clear the WebView by passing an empty string.
private void ItemListView_SelectionChanged(object sender, SelectionChangedEventArgs e) { // If there's a selected item (in AddedItems) // show it in the WebView. if (e.AddedItems.Count > 0) { FeedItem feedItem = e.AddedItems[0] as FeedItem; if (feedItem != null) { // Navigate the WebView to the blog post content HTML string. ContentView.NavigateToString(feedItem.Content); } } else { // If the item was de-selected, clear the WebView. ContentView.NavigateToString(""); } }
Here's what the app looks like when we run it.

This is a good basic page that works well for most situations. But a Metro style app needs to work well in all situations. It must adapt to the different resolutions, orientations, and views on different devices. For example, this is what the page looks like when viewed in portrait orientation.

You can see that our basic page doesn't work quite as well when viewed like this. We want our app to look good and also to better reflect the personality of the Windows team blogs. To meet these goals, we start with the page templates that are available in Visual Studio. Then we use what we learned in making this page to modify the templates and create our full app.
Adding pages and navigation
To make our blog reader work for all of the Windows team blogs, we must add more pages to our app and handle navigation between these pages. First, we want a page that lists all of the Windows team blogs. When a reader picks a blog from this page, we load the list of posts for that blog. The split page reader we’ve already created still works for this, but we want to make it a little nicer. Finally, we add a detail page so that we can read individual blog posts without the list view taking up space.
Page templates
Fortunately, we don't have to create each page from a blank template. Visual Studio Express 2012 RC for Windows 8 ships with a collection of page templates that are useful for a variety of situations. Here are the available page templates.
| Page Type | Description |
|---|---|
| Group Detail Page | Displays details for a single group and previews for each item in the group. |
| Grouped Items Page | Displays grouped collections. |
| Item Detail Page | Displays one item in detail, and enables navigation to adjacent items. |
| Items Page | Displays a collection of items. |
| Split Page | Displays a list of items and details for the selected item. |
| Basic Page | An empty page that can adapt to different orientations and views, and has a title and back button. |
| Blank Page | A blank page for a Metro style app. |
To add a page to an app
- Select Project > Add New Item. The Add New Item dialog box opens.
- In the Installed pane, expand Visual C# or Visual Basic.
- Pick the Windows Metro style template type.
- In the center pane, select the type of page to add to your project.
- Enter a name for the page.
- Click Add. The XAML and code behind files for your page are added to the project.
Here's the Add New Item dialog.

- The first time you add a new page to the Blank App template (other than a Blank Page), Visual Studio shows a dialog with a message that you need to add files that are missing from your project. Click Yes to add these files. Files for several utility classes are added to your project in the Common folder.
- Press F7 to build the app. The new page will show an error in the designer until you build the helper classes it depends on.
For our blog reader, we add an Items Page to show the list of Windows team blogs. We name this page ItemsPage. We add a Split Page to show the posts for each blog. We name this page SplitPage. The Split Page template is like the page we created for our simple blog reader app, but more polished. We use the Basic Page template for our detail page, which we name DetailPage. It just has a back button, page title, and a WebView control to show the post content. But, instead of loading the post content into the WebView from a string of HTML as we do in the split page, we navigate to the URL of the post and show the actual web page. The pages of the finished app look something like this:

When we add the page templates to our project and look at the XAML and code behind, it's apparent that these page templates do a lot of work for us. In fact, it's easy to get lost, so let's take a closer look at the page templates and see what's in them. All the page templates for Metro style apps have the same format.
The XAML for the page templates has 3 main sections:
| Resources | Styles and data templates for the page are defined in the Resources section. We talk more about this in the Creating a consistent look with styles section. |
| App Content | The controls and content that make up the app UI are defined within the root layout panel. |
| Visual State Manager | Animations and transitions that adapt the app to different layouts and orientations are defined in the Visual State Manager (VSM). We talk more about this in the Adapting to different layouts section. |
The template pages are all derived from the LayoutAwarePage class and can do much more by default than the BlankPage that we started with. LayoutAwarePage is an implementation of Page that enables important functionality for Metro style app development:
- The mapping of application view state to visual state lets the page adapt to different resolutions, orientations, and views.
GoBackandGoHomeevent handlers support basic navigation.- A default view model gives you a simple bindable data source.
The page templates also use styles and templates found in StandardStyles.xaml that apply the design guidelines for Metro style apps. We'll use some of these styles as a starting point and modify copies of them to customize the look of our app.
Navigating between pages
The XAML UI framework provides a built-in navigation model that uses Frames and Pages and works much like the navigation in a web browser. The Frame control hosts Pages, and has a navigation history that you can use to go forward and back through pages you've visited. You can pass data between pages as you navigate.
In the Visual Studio project templates, a Frame named rootFrame is set as the content of the app window. Let's look at the relevant code in App.xaml.cs/vb.
protected override void OnLaunched(LaunchActivatedEventArgs args) { // App state management code // ... // Create a Frame to act as navigation context and navigate to the first page var rootFrame = new Frame(); if (!rootFrame.Navigate(typeof(MainPage))) { throw new Exception("Failed to create initial page"); } // Place the frame in the current Window and ensure that it is active Window.Current.Content = rootFrame; Window.Current.Activate(); }
This code creates the Frame, sets it as the Window's content, and navigates to MainPage. Because we want the first page in our full app to be ItemsPage, we change the call to the Navigate method and pass in ItemsPage as shown here.
if (!rootFrame.Navigate(typeof(ItemsPage)))
{
throw new Exception("Failed to create initial page");
}
When ItemsPage is loaded, we need to get the instance of the data source and retrieve the feed data to display, just as we did with MainPage in the Using the data in the app section. For MainPage, we put our code in the OnNavigatedTo method override that's included in the page template. For the new pages that are derived from LayoutAwarePage, data is loaded in the LoadState method override instead. The code we add here is much like what we added to MainPage, but instead of setting the DataContext of the page, we use the DefaultViewModel provided by LayoutAwarePage. We add the async keyword to the method signature, and if the feeds haven't been retrieved already, we call the FeedDataSource.GetFeedsAsync method. Here's the relevant code for ItemsPage.xaml.cs/vb.
FeedDataSource feedDataSource = (FeedDataSource)App.Current.Resources["feedDataSource"];
if (feedDataSource != null)
{
if (feedDataSource.Feeds.Count == 0)
{
await feedDataSource.GetFeedsAsync();
}
this.DefaultViewModel["Items"] = feedDataSource.Feeds;
}
Press F5 to build and run the app. Now the ItemsPage is loaded instead of the MainPage we created previously. This page shows a grid of all the blogs, and the first item is selected by default. It looks something like this, but the items might be arranged differently depending on your screen resolution.

When the user picks a blog from the collection, we navigate from the items page to the split page . To do this navigation, we want the GridView items to respond to a click like a button, instead of being selected. To make the GridView items clickable, we set the SelectionMode and IsItemClickEnabled properties as shown here. We then add a handler for GridView's ItemClick event. Here's the XAML in ItemsPage.xaml for the GridView with the properties set and the ItemClick event added.
<GridView x:Name="itemGridView" AutomationProperties.AutomationId="ItemsGridView" AutomationProperties.Name="Items" Margin="116,0,116,46" ItemsSource="{Binding Source={StaticResource itemsViewSource}}" ItemTemplate="{StaticResource Standard250x250ItemTemplate}" SelectionMode="None" IsItemClickEnabled="True" ItemClick="ItemView_ItemClick" />
The items page also has a list view named itemListView that is shown in place of the grid when the app is Snapped. We talk more about this in the section Adapting to different layouts. For now, we just need to make the same changes to the ListView that we made to the GridView so they have the same behavior.
<ListView x:Name="itemListView" AutomationProperties.AutomationId="ItemsListView" AutomationProperties.Name="Items" Margin="10,0,0,60" ItemsSource="{Binding Source={StaticResource itemsViewSource}}" ItemTemplate="{StaticResource Standard80ItemTemplate}" SelectionMode="None" IsItemClickEnabled="True" ItemClick="ItemView_ItemClick"/>
We add the event handler to the ItemsPage.xaml.cs/vb code behind page. In the handler, we navigate to the split page and pass the data for the selected feed.
private void ItemView_ItemClick(object sender, ItemClickEventArgs e)
{
// Navigate to the split page, configuring the new page
// by passing the clicked item (FeedItem) as a navigation parameter
this.Frame.Navigate(typeof(SplitPage), e.ClickedItem);
}
To navigate between pages, you use the Frame control's Navigate, GoForward, and GoBack methods. To navigate back, the Visual Studio page templates include a Back button. The handler for the BackButton's Click event calls the Frame.GoBack method.
The Navigate(TypeName, Object) method lets us navigate and pass a data object to the new page. We use this method to pass data between our pages. The first parameter, typeof(SplitPage), is the Type of the page that we are navigating to. The second parameter is the data object that we pass to the page we're navigating to. In this case, we pass the clicked item.
Press F5 to build and run the app. Now when you click an item, instead of the item being selected, the split page is loaded. But the split page is still blank because we haven't connected it to the data yet.
In the SplitPage.xaml.cs/vb code behind page, we need to do something with the FeedData object that was just passed from the items page. For this, we again override the LoadState method. This method is already added in the page template code, so we just need to modify it to hook up our data. (You might need to expand the "Page state management" region to see the LoadState method.) The template pages include a built-in view model, named DefaultViewModel, which we can hook our data up to. The navigationParameter has the data object that was passed from the items page. We cast this back to a FeedData object, and add the feed data to DefaultViewModel with the key Feed, and add the FeedData.Items property to DefaultViewModel with the key Items. Here's the updated LoadState method.
protected override void LoadState(Object navigationParameter, Dictionary<String, Object> pageState)
{
// TODO: Assign a bindable group to this.DefaultViewModel["Group"]
// TODO: Assign a collection of bindable items to this.DefaultViewModel["Items"]
FeedData feedData = navigationParameter as FeedData;
if (feedData != null)
{
this.DefaultViewModel["Feed"] = feedData;
this.DefaultViewModel["Items"] = feedData.Items;
}
if (pageState == null)
{
// When this is a new page, select the first item automatically unless logical page
// navigation is being used (see the logical page navigation #region below.)
if (!this.UsingLogicalPageNavigation() && this.itemsViewSource.View != null)
{
this.itemsViewSource.View.MoveCurrentToFirst();
}
}
else
{
// Restore the previously saved state associated with this page
if (pageState.ContainsKey("SelectedItem") && this.itemsViewSource.View != null)
{
// TODO: Invoke this.itemsViewSource.View.MoveCurrentTo() with the selected
// item as specified by the value of pageState["SelectedItem"]
}
}
}
Press F5 to build and run the app. Now when you navigate to the split page, the data is displayed and you can select from the list of blog posts. But the page title is still blank. We'll fix that now.
In the Visual Studio page template, the TODO comments indicate where we add our data object to DefaultViewModel with the key Group. We can think of a blog feed as a group of blog posts, but it makes the code easier to read if we use the key Feed in place of Group. Because we used the key Feed instead, we need to change the binding in the page title to bind to the Feed property instead of Group. In SplitPage.xaml, change the Text binding of the TextBlock named pageTitle to bind to Feed.Title, like this:Text="{Binding Feed.Title}".
<TextBlock x:Name="pageTitle" Grid.Column="1" Text="{Binding Feed.Title}" Style="{StaticResource PageHeaderTextStyle}"/>
Press F5 to build and run the app. Now when you navigate to the split page, the page title is displayed.
We need to make a few more changes to finish adding functionality to the new pages we added to our app. After we add this code to our app, we can move on to styling and animating our app to make it look the way we want.
In ItemsPage.xaml, the page title is bound to a static resource with the key AppName. Update the text in this resource to Windows Team Blogs, like this.
<x:String x:Key="AppName">Windows Team Blogs</x:String>
In SplitPage.xaml, change the Grid named titlePanel to span 2 columns.
<!-- Back button and page title --> <Grid x:Name="titlePanel" Grid.ColumnSpan="2">
Also in SplitPage.xaml, we need to change the layout used to show the title and content of the selected blog post. To do that, replace the ScrollViewer named itemDetail with this ScrollViewer layout.
<!-- Details for selected item -->
<ScrollViewer
x:Name="itemDetail"
AutomationProperties.AutomationId="ItemDetailScrollViewer"
Grid.Column="1"
Grid.Row="1"
Padding="70,0,120,0"
DataContext="{Binding SelectedItem, ElementName=itemListView}"
Style="{StaticResource VerticalScrollViewerStyle}">
<Grid x:Name="itemDetailGrid">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBlock x:Name="itemTitle" Text="{Binding Title}"
Style="{StaticResource SubheaderTextStyle}"/>
<Border x:Name="contentViewBorder" BorderBrush="Gray" BorderThickness="2"
Grid.Row="1" Margin="0,15,0,20">
<Grid>
<WebView x:Name="contentView" />
<Rectangle x:Name="contentViewRect" />
</Grid>
</Border>
</Grid>
</ScrollViewer>
In SplitPage.xaml.cs/vb, add code to the ItemListView_SelectionChanged event handler to populate the WebView with the content of the selected blog post, as shown here. This event handler is in the Logical page navigation region of the code.
void ItemListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
// Invalidate the view state when logical page navigation is in effect, as a change
// in selection may cause a corresponding change in the current logical page. When
// an item is selected this has the effect of changing from displaying the item list
// to showing the selected item's details. When the selection is cleared this has the
// opposite effect.
if (this.UsingLogicalPageNavigation())
{
this.InvalidateVisualState();
}
// Add this code to populate the web view
// with the content of the selected blog post.
Selector list = (Selector)sender;
FeedItem selectedItem = (FeedItem)list.SelectedItem;
if (selectedItem != null)
{
this.contentView.NavigateToString(selectedItem.Content);
}
else
{
this.contentView.NavigateToString("");
}
}
In DetailPage.xaml, we need to bind the title text to the blog post title and add a WebView control to show the blog page. To do that, replace the Grid that contains the back button and page title with this Grid and WebView.
<!-- Back button and page title -->
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Button x:Name="backButton" Click="GoBack"
IsEnabled="{Binding Frame.CanGoBack, ElementName=pageRoot}"
Style="{StaticResource BackButtonStyle}"/>
<TextBlock x:Name="pageTitle" Grid.Column="1"
Text="{Binding Title}"
Style="{StaticResource PageHeaderTextStyle}"/>
</Grid>
<Border x:Name="contentViewBorder" BorderBrush="Gray" BorderThickness="2"
Grid.Row="1" Margin="120,15,20,20">
<WebView x:Name="contentView" />
</Border>
In DetailPage.xaml.cs/vb, add code to the LoadState method override to navigate to the blog post and set the DataContext of the page. Here's the updated LoadState method.
protected override void LoadState(Object navigationParameter, Dictionary<String, Object> pageState)
{
// Add this code to navigate the web view to the selected blog post.
FeedItem feedItem = navigationParameter as FeedItem;
if (feedItem != null)
{
this.contentView.Navigate(feedItem.Link);
this.DataContext = feedItem;
}
}
Press F5 to build and run the app. All the data is hooked up now, but UI doesn't look as nice as we'd like. And there's no way to navigate to the details page we created. We add navigation to the detail page next.
Adding an app bar
Most of the navigation in our blog reader app happens when the user picks an item in the UI. But on the split page, we must provide a way for the user to go to the detail view of the blog post. We could put a button somewhere on the page, but that would distract from the core app experience, which is reading. Instead, we put the button in an app bar that's hidden until the user needs it.
An app bar is a piece of UI that is hidden by default, and is shown or dismissed when the user swipes from the edge of the screen or interacts with the app. It presents navigation, commands, and tools to the user. An app bar can appear at the top of the page, at the bottom of the page, or both. We recommend that you put navigation in the top app bar, and tools and commands in the bottom app bar.
To add an app bar in XAML, we assign an AppBar control to a Page's TopAppBar or BottomAppBar property. We'll add a top app bar with a button to navigate to the detail page. The StandardStyles.xaml file contains a variety of app bar button styles for common scenarios. We use these styles as a guide to create a style for our button. We put our style in the Page.Resources section of SplitPage.xaml, and add the Page.TopAppBar xaml just after the resources section, as shown here.
<Page.Resources> ... <Style x:Key="WebViewAppBarButtonStyle" TargetType="Button" BasedOn="{StaticResource AppBarButtonStyle}"> <Setter Property="AutomationProperties.AutomationId" Value="WebViewAppBarButton"/> <Setter Property="AutomationProperties.Name" Value="View Web Page"/> <Setter Property="Content" Value=""/> </Style> </Page.Resources> <Page.TopAppBar> <AppBar Padding="10,0,10,0"> <Grid> <Button Click="ViewDetail_Click" HorizontalAlignment="Right" Style="{StaticResource WebViewAppBarButtonStyle}"/> </Grid> </AppBar> </Page.TopAppBar>
We can control how and when the app bar is shown and dismissed by setting the IsSticky and IsOpen properties. We can also respond to the app bar being opened or dismissed by handling the Opened and Closed events.
To handle navigation to the detail page we add this code to SplitPage.xaml.cs/vb.
private void ViewDetail_Click(object sender, RoutedEventArgs e) { FeedItem selectedItem = this.itemListView.SelectedItem as FeedItem; if (selectedItem != null && this.Frame != null) { this.Frame.Navigate(typeof(DetailPage), selectedItem); } }
Press F5 to build and run the app. Click a blog to navigate to the split page, and select a blog post to read. Right-click the header to show the app bar, and click the Show Web View button to navigate to the detail page.
Adding animations and transitions
When we talk about animations, we often think of objects bouncing around on the screen. But in XAML, an animation is essentially just a way to change the value of a property on an object. This makes animations useful for a lot more than just bouncing balls. In our blog reader app, we use animations to adapt our UI to different layouts and orientations. We take a closer look at this in the next section, but first, we need to understand how animations work.
To use an animation, we put it inside of a Storyboard. When the Storyboard runs, the property changes as specified by the animation. A Storyboard can have one or many animations in it. Each animation specifies a target object, a property to change on that object, and a new value for the property.
In our blog reader app, we have a ListView named itemListView. Here's an animation that changes the Visibility property of itemListView to Visible when the Storyboard runs.
<Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="itemListView" Storyboard.TargetProperty="Visibility" > <DiscreteObjectKeyFrame KeyTime="0" Value="Visible"/> </ObjectAnimationUsingKeyFrames> </Storyboard>
Adding theme animations
Run the app again, and notice how UI elements slide in smoothly when a page loads. Except for the WebView control we added. It just shows up. Windows 8 uses animations and transitions to enhance the user experience throughout the UI. We want to have the same experience in our app to match the personality of Windows 8. Fortunately, we can use built in theme animations and theme transitions in our app to match the ones used in Windows 8. We find these in the Windows.UI.Xaml.Media.Animation namespace.
A theme animation is a pre-configured animation that we can put inside a Storyboard. The PopInThemeAnimation makes the web view slide in from right to left when the page loads. Increasing the value of the FromHorizontalOffset property makes the effect more extreme. Here, we put the PopInThemeAnimation in a Storyboard and make it a resource in DetailPage.xaml. Set the target of the animation to be the Border that surrounds our web content. This animates the Border and everything in it.
<Page.Resources> <Storyboard x:Name="PopInStoryboard"> <PopInThemeAnimation Storyboard.TargetName="contentViewBorder" FromHorizontalOffset="400"/> </Storyboard> </Page.Resources>
In the code behind page, we start the Storyboard in the LoadState method so that the pop-in animation is applied to the Border when the user navigates to the detail page. Here's the updated LoadState method.
protected override void LoadState(Object navigationParameter, Dictionary<String, Object> pageState)
{
// Run the PopInThemeAnimation
Windows.UI.Xaml.Media.Animation.Storyboard sb =
this.FindName("PopInStoryboard") as Windows.UI.Xaml.Media.Animation.Storyboard;
if (sb != null) sb.Begin();
// TODO: Assign a bindable group to this.DefaultViewModel["Group"]
// TODO: Assign a collection of bindable items to this.DefaultViewModel["Items"]
FeedData feedData = navigationParameter as FeedData;
if (feedData != null)
{
this.DefaultViewModel["Feed"] = feedData;
this.DefaultViewModel["Items"] = feedData.Items;
}
if (pageState == null)
{
// When this is a new page, select the first item automatically unless logical page
// navigation is being used (see the logical page navigation #region below.)
if (!this.UsingLogicalPageNavigation() && this.itemsViewSource.View != null)
{
this.itemsViewSource.View.MoveCurrentToFirst();
}
}
else
{
// Restore the previously saved state associated with this page
if (pageState.ContainsKey("SelectedItem") && this.itemsViewSource.View != null)
{
// TODO: Invoke this.itemsViewSource.View.MoveCurrentTo() with the selected
// item as specified by the value of pageState["SelectedItem"]
}
}
}
Press F5 to build and run the app. Now the WebView control slides in with the other UI elements when the split page is loaded.
For more info, and a full list of theme animations and transitions, see QuickStart: Animations.
Creating a consistent look with styles
We want to make our blog reader app look and feel like the Windows team blogs website. We want our users to have a seamless experience when they move between the website and our app. The default dark theme of our Windows Metro style UI doesn't match very well with the Windows team blogs website. This is most clear on the detail page, where we load the actual blog page into a WebView, as shown here:

To give our app a consistent appearance that we can update as needed, we use brushes and styles. A Brush lets us define a look in one place and use it wherever we need it. A Style lets us set values for a control's properties and reuse those settings across our app.
Before we get into the details, let's look at how we use a brush to set the background color of the pages in our app. Each page in our app has a root Grid with a Background property set to define the page's background color. We could set each page's background individually, like this.
<Grid Background="Blue">
A better way is to define a Brush as a resource and use it to define the background color of all of our pages. We define objects and values as resources to make them reusable. To use an object or value as a resource, we must set its x:Key attribute. We use this key to refer to the resource from our XAML. Here, the background is set to a resource with the key ApplicationPageBackgroundThemeBrush, which is a system defined SolidColorBrush.
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
This is fine to set the Background property of the Grid, but you typically need to set more than one property to get the look you want. You can group settings for any number of properties together is a Style, and apply the Style to the control.
You can define resources in an individual page's XAML file, in the App.xaml file, or in a separate resource dictionary XAML file, like StandardStyles.xaml. Where the resource is defined determines the scope in which it can be used. Visual Studio creates the StandardStyles.xaml file as part of the project template and puts it in the Common folder. It's a resource dictionary that contains the values, styles, and data templates used in the Visual Studio page templates. A resource dictionary XAML file can be shared across apps, and more than one resource dictionary can be merged in a single app.
In our blog reader app, we define resources in App.xaml to make them available across our entire app. And we have some resources defined in the XAML file for individual pages. These resources are available only in the page where they are defined. If resources with the same key are defined in both App.xaml and in a page, the resource in the page overrides the resource in App.xaml. In the same way, a resource defined in App.xaml will override a resource defined with the same key in a separate resource dictionary file. For more info, see Quickstart: Styling controls.
Now let's look at an example of using Styles in our app. The look of the template pages is defined by a style with the key LayoutRootStyle. The Style definition is in the StandardStyles.xaml file.
<Grid Style="{StaticResource LayoutRootStyle}">
<!-- Page layout roots typically use entrance animations and a theme-appropriate background color -->
<Style x:Key="LayoutRootStyle" TargetType="Panel">
<Setter Property="Background" Value="{StaticResource ApplicationPageBackgroundThemeBrush}"/>
<Setter Property="ChildrenTransitions">
<Setter.Value>
<TransitionCollection>
<EntranceThemeTransition/>
</TransitionCollection>
</Setter.Value>
</Setter>
</Style>
In the Style definition, we need a TargetType attribute and a collection of one or more Setters. We set the TargetType to a string that specifies the type that the Style is applied to, in this case, a Panel. If you try to apply a Style to a control that doesn't match the TargetType attribute, an exception occurs. Each Setter element requires a Property and aValue. These property settings indicate what control property the setting applies to, and the value to set for that property.
To change the Background of our pages, we need to replace the ApplicationPageBackgroundThemeBrush with our own custom brush. For our custom brush, we use the Color #FF0A2562, which is a nice blue that fits with the colors on the http://windowsteamblog.com site. To replace the system theme brush, we create a new Style that is based on LayoutRootStyle, and change the Background property there. Here's how we define a new style for the layout root.
<SolidColorBrush x:Key="WindowsBlogBackgroundBrush" Color="#FF0A2562"/>
<Style x:Key="WindowsBlogLayoutRootStyle" TargetType="Panel" BasedOn="{StaticResource LayoutRootStyle}">
<Setter Property="Background" Value="{StaticResource WindowsBlogBackgroundBrush}"/>
</Style>
Put these brush and style definitions in the ResourceDictionary in App.xaml with our other app specific resources.
<ResourceDictionary.MergedDictionaries>
<!--
Styles that define common aspects of the platform look and feel
Required by Visual Studio project and item templates
-->
<ResourceDictionary Source="Common/StandardStyles.xaml"/>
<ResourceDictionary>
<local:FeedDataSource x:Key="feedDataSource"/>
<local:DateConverter x:Key="dateConverter" />
<SolidColorBrush x:Key="WindowsBlogBackgroundBrush"
Color="#FF0A2562"/>
<Style x:Key="WindowsBlogLayoutRootStyle"
TargetType="Panel"
BasedOn="{StaticResource LayoutRootStyle}">
<Setter Property="Background"
Value="{StaticResource WindowsBlogBackgroundBrush}"/>
</Style>
</ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
Important Because we based a style on a system style in StandardStyles.xaml, the ResourceDictionary that includes StandardStyles.xaml has to be declared before our app ResourceDictionary in the MergedDictionaries. If it's not, the XAML parser can't find the LayoutRootStyle that our style is based on.
The line BasedOn="{StaticResource LayoutRootStyle}" tells our new Style to inherit from LayoutRootStyle any properties that we don't explicitly set. Our new Style is just like the default style, but with a blue background, and we can use it for all of our pages like this:
<Grid Style="{StaticResource WindowsBlogLayoutRootStyle}">
Update the root Grid in ItemsPage.xaml, SplitPage.xaml, and DetailPage.xaml to use WindowsBlogLayoutRootStyle. Press F5 to build and run the app, and see the blue pages.
To give our app the look and feel of the Windows team blogs website, we also use custom data templates in addition to Brushes and Styles. We talked about data templates in the section Displaying data. The data templates and styles we add to customize the look of our app are shown here.
In App.xaml, we add a ControlTemplate that defines a square block that shows the date. We define this in App.xaml so we can use it in both ItemsPage.xaml and SplitPage.xaml.
<Application.Resources>
<ResourceDictionary>
...
<ControlTemplate x:Key="DateBlockTemplate">
<Canvas Height="86" Width="86" Margin="8,8,0,8" HorizontalAlignment="Left" VerticalAlignment="Top">
<TextBlock TextTrimming="WordEllipsis" TextWrapping="NoWrap"
Width="Auto" Height="Auto" Margin="8,0,4,0" FontSize="32" FontWeight="Bold">
<TextBlock.Text>
<Binding Path="PubDate" Converter="{StaticResource dateConverter}" ConverterParameter="month" />
</TextBlock.Text>
</TextBlock>
<TextBlock TextTrimming="WordEllipsis" TextWrapping="Wrap"
Width="40" Height="Auto" Margin="8,0,0,0" FontSize="34" FontWeight="Bold" Canvas.Top="36">
<TextBlock.Text>
<Binding Path="PubDate" Converter="{StaticResource dateConverter}" ConverterParameter="day" />
</TextBlock.Text>
</TextBlock>
<Line Stroke="White" StrokeThickness="2" X1="54" Y1="46" X2="54" Y2="80" />
<TextBlock TextWrapping="Wrap"
Width="20" Height="Auto" FontSize="{StaticResource ContentFontSize}" Canvas.Top="42" Canvas.Left="60">
<TextBlock.Text>
<Binding Path="PubDate" Converter="{StaticResource dateConverter}" ConverterParameter="year" />
</TextBlock.Text>
</TextBlock>
</Canvas>
</ControlTemplate>
...
</Application.Resources>
In ItemsPage.xaml, we add these resources to define the look of the grid items in the default view.
<Page.Resources> ... <!-- light blue --> <SolidColorBrush x:Key="BlockBackgroundBrush" Color="#FF557EB9"/> <!-- Grid Styles --> <Style x:Key="GridTitleTextStyle" TargetType="TextBlock" BasedOn="{StaticResource BasicTextStyle}"> <Setter Property="FontSize" Value="26.667"/> <Setter Property="Margin" Value="12,0,12,2"/> </Style> <Style x:Key="GridDescriptionTextStyle" TargetType="TextBlock" BasedOn="{StaticResource BasicTextStyle}"> <Setter Property="VerticalAlignment" Value="Bottom"/> <Setter Property="Margin" Value="12,0,12,60"/> </Style> <DataTemplate x:Key="DefaultGridItemTemplate"> <Grid HorizontalAlignment="Left" Width="250" Height="250"> <Border Background="{StaticResource BlockBackgroundBrush}" /> <TextBlock Text="{Binding Title}" Style="{StaticResource GridTitleTextStyle}"/> <TextBlock Text="{Binding Description}" Style="{StaticResource GridDescriptionTextStyle}" /> <StackPanel VerticalAlignment="Bottom" Orientation="Horizontal" Background="{StaticResource ListViewItemOverlayBackgroundThemeBrush}"> <TextBlock Text="Last Updated" Margin="12,4,0,8" Height="42"/> <TextBlock Text="{Binding PubDate, Converter={StaticResource dateConverter}}" Margin="12,4,12,8" /> </StackPanel> </Grid> </DataTemplate> </Page.Resources>
In ItemsPage.xaml, we also must update the ItemTemplate property of the itemGridView to use our DefaultGridItemTemplate resource instead of Standard250x250ItemTemplate, which is the default template defined in StandardStyles.xaml. Here's the updated XAML for itemGridView.
<GridView
x:Name="itemGridView"
AutomationProperties.AutomationId="ItemsGridView"
AutomationProperties.Name="Items"
Margin="116,0,116,46"
ItemsSource="{Binding Source={StaticResource itemsViewSource}}"
ItemTemplate="{StaticResource DefaultGridItemTemplate}"
SelectionMode="None"
IsItemClickEnabled="True"
ItemClick="ItemView_ItemClick"/>
In SplitPage.xaml, we add these resources to define the look of the list items in the default view.
<Page.Resources> ... <!-- green --> <SolidColorBrush x:Key="BlockBackgroundBrush" Color="#FF6BBD46"/> <DataTemplate x:Key="DefaultListItemTemplate"> <Grid HorizontalAlignment="Stretch" Width="Auto" Height="110" Margin="10,10,10,0"> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <!-- Green date block --> <Border Background="{StaticResource BlockBackgroundBrush}" Width="110" Height="110" /> <ContentControl Template="{StaticResource DateBlockTemplate}" /> <StackPanel Grid.Column="1" HorizontalAlignment="Left" Margin="12,8,0,0"> <TextBlock Text="{Binding Title}" FontSize="26.667" TextWrapping="Wrap" MaxHeight="72" Foreground="#FFFE5815" /> <TextBlock Text="{Binding Author}" FontSize="18.667" /> </StackPanel> </Grid> </DataTemplate> ... </Page.Resources>
In SplitPage.xaml, we also update the ItemTemplate property in itemListView to use our DefaultListItemTemplate resource instead of Standard130ItemTemplate, which is the default template. Here's the updated XAML for itemListView.
<ListView
x:Name="itemListView"
AutomationProperties.AutomationId="ItemsListView"
AutomationProperties.Name="Items"
Margin="120,0,0,60"
ItemsSource="{Binding Source={StaticResource itemsViewSource}}"
SelectionChanged="ItemListView_SelectionChanged"
ItemTemplate="{StaticResource DefaultListItemTemplate}"/>
With our styles applied, our app fits in with the look and feel of the Windows team blogs website:



By using styles and basing them on other styles we can quickly define and apply different looks for our app. In the next section, we combine what we know about animations and styles to make our app fluidly adapt to various layouts and orientations while its running.
Adapting to different layouts
Usually, an app is designed to be viewed full screen in the landscape orientation. But a Metro style UI must adapt to different orientations and layouts. Specifically, it must support both landscape and portrait orientations. In the landscape orientation, it must support Full Screen, Filled, and Snapped layouts. We saw when we made our blog reader page from a blank template that it didn't look as good in the portrait orientation. In this section, we look at how we can make our app look good in any resolution or orientation.
Note To test the app in different orientations and resolutions, you can run it in the simulator. To run your Metro style app in the simulator, select Simulator from the drop-down list next to the Start Debugging button on the Standard toolbar. For more info about the simulator, see Running Metro style apps from Visual Studio.
The Visual Studio templates include code that handles changes to the view state. This code is in the LayoutAwarePage.cs/vb file, and it maps our app state to visual states defined in our XAML. Because the page layout logic is provided for us, we only need to provide the views to be used for each of the page's visual states.
To transition between different views using XAML, we use the VisualStateManger to define different VisualStates for our app. Here we have a VisualStateGroup defined in ItemsPage.xaml. This group has 4 VisualStates named FullScreenLandscape, Filled, FullScreenPortrait, and Snapped. Different VisualStates from the same VisualStateGroup can't be used at the same time. Each VisualState has animations that tell the app what needs to change from the baseline specified in the XAML for the UI.
<!--App Orientation States--> <VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="ApplicationViewStates"> <VisualState x:Name="FullScreenLandscape" /> <VisualState x:Name="Filled"> ... </VisualState> <VisualState x:Name="FullScreenPortrait"> ... </VisualState> <VisualState x:Name="Snapped"> ... </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups>
We use the FullScreenLandscape state when the app is full screen in the landscape orientation. Because we designed our default UI for this view, no changes are needed and this is just an empty VisualState.
We use the Filled state when the user has another app snapped to one side of the screen. The items view page just moves over in this case, and no changes are needed. This is just an empty VisualState, too.
We use the FullScreenPortrait state when our app is rotated from landscape to portrait orientation. In this visual state, we have 2 animations. One changes the style used for the back button, and the other changes the margin of itemGridView, so that everything fits better on the screen.
<!-- The entire page respects the narrower 100-pixel margin convention for portrait --> <VisualState x:Name="FullScreenPortrait"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="backButton" Storyboard.TargetProperty="Style"> <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PortraitBackButtonStyle}"/> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="itemGridView" Storyboard.TargetProperty="Padding"> <DiscreteObjectKeyFrame KeyTime="0" Value="96,0,86,56"/> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState>
We use the Snapped state when the user has two apps showing, and our app is the narrower of the two. In this state, our app is only 320 DIPs wide, so we need to make more drastic changes to the layout. In the XAML for the items page UI, both a GridView and a ListView are defined and bound to the data collection. By default, itemGridViewScroller is shown, and itemListViewScroller is collapsed. In the Snapped state, we have 4 animations that collapse itemListViewScroller, show itemListViewScroller, and change the Style of the back button and page title to make them smaller.
<!-- The back button and title have different styles when snapped, and the list representation is substituted for the grid displayed in all other view states --> <VisualState x:Name="Snapped"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="backButton" Storyboard.TargetProperty="Style"> <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource SnappedBackButtonStyle}"/> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="pageTitle" Storyboard.TargetProperty="Style"> <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource SnappedPageHeaderTextStyle}"/> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="itemListScrollViewer" Storyboard.TargetProperty="Visibility"> <DiscreteObjectKeyFrame KeyTime="0" Value="Visible"/> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="itemGridScrollViewer" Storyboard.TargetProperty="Visibility"> <DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed"/> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState>
In the Creating a consistent look with styles section of this tutorial, we created styles and templates to give our app a custom look. The default landscape view uses these styles and templates . To keep the custom look in different views, we also need to create custom styles and templates for those views.
In ItemsPage.xaml, we created a new data template for the grid items. We also need to provide a new data template for the list items that are shown in Snapped view. We name this template NarrowListItemTemplate and add it to the resources section of ItemsPage.xaml, just after the DefaultGridItemTemplate resource.
<Page.Resources> ... <!-- Used in Snapped view --> <DataTemplate x:Key="NarrowListItemTemplate"> <Grid Height="80"> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <Border Background="{StaticResource BlockBackgroundBrush}" Width="80" Height="80" /> <ContentControl Template="{StaticResource DateBlockTemplate}" Margin="-12,-12,0,0"/> <StackPanel Grid.Column="1" HorizontalAlignment="Left" Margin="12,8,0,0"> <TextBlock Text="{Binding Title}" MaxHeight="56" TextWrapping="Wrap"/> </StackPanel> </Grid> </DataTemplate> </Page.Resources>
To make the ListView show our new data template, we update the ItemTemplate property of itemListView to use our NarrowListItemTemplate resource instead of Standard80ItemTemplate, which is the default template defined in StandardStyles.xaml. Here's the updated XAML for itemListView.
<ListView
x:Name="itemListView"
AutomationProperties.AutomationId="ItemsListView"
AutomationProperties.Name="Items"
Margin="10,0,0,60"
ItemsSource="{Binding Source={StaticResource itemsViewSource}}"
ItemTemplate="{StaticResource NarrowListItemTemplate}"
SelectionMode="None"
IsItemClickEnabled="True"
ItemClick="ItemView_ItemClick"/>
In SplitPage.xaml, we create a similar ListView template that’s used in the Filled and Snapped views, and in the FullScreenLandscape view if the screen width is less than 1366 DIPs. We also name this template NarrowListItemTemplate and add it to the resources section of SplitPage.xaml, just after the DefaultListItemTemplate resource.
<Page.Resources> ... <!-- Used in Filled and Snapped views --> <DataTemplate x:Key="NarrowListItemTemplate"> <Grid Height="80"> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <Border Background="{StaticResource BlockBackgroundBrush}" Width="80" Height="80"/> <ContentControl Template="{StaticResource DateBlockTemplate}" Margin="-12,-12,0,0"/> <StackPanel Grid.Column="1" HorizontalAlignment="Left" Margin="12,8,0,0"> <TextBlock Text="{Binding Title}" MaxHeight="56" Foreground="#FFFE5815" TextWrapping="Wrap"/> <TextBlock Text="{Binding Author}" FontSize="12" /> </StackPanel> </Grid> </DataTemplate> ... </Page.Resources>
To use this data template, we update the visual states where it's used. In the XAML for the Snapped and Filled visual states, we find the animation that targets the ItemTemplate property of itemListView. We then change the value to use the NarrowListItemTemplate resource instead of the default Standard80ItemTemplate resource. Here's the updated XAML for the animation.
<VisualState x:Name="Filled"> <Storyboard> .... <ObjectAnimationUsingKeyFrames Storyboard.TargetName="itemListView" Storyboard.TargetProperty="ItemTemplate"> <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource NarrowListItemTemplate}"/> </ObjectAnimationUsingKeyFrames> .... </Storyboard> </VisualState> ... <VisualState x:Name="Snapped"> <Storyboard> .... <ObjectAnimationUsingKeyFrames Storyboard.TargetName="itemListView" Storyboard.TargetProperty="ItemTemplate"> <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource NarrowListItemTemplate}"/> </ObjectAnimationUsingKeyFrames> .... </Storyboard> </VisualState>
We also replaced the item detail section of the split page with our own detail section that uses a WebView. Because we made this change, some animations in the Snapped_Detail visual state target elements that no longer exist. These will cause errors when we use this visual state, so we need to remove them. In SplitPage.xaml, we remove these animations from the Snapped_Detail visual state.
<VisualState x:Name="Snapped_Detail"> <Storyboard> ... <!--<ObjectAnimationUsingKeyFrames Storyboard.TargetName="itemDetailTitlePanel" Storyboard.TargetProperty="(Grid.Row)"> <DiscreteObjectKeyFrame KeyTime="0" Value="0"/> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="itemDetailTitlePanel" Storyboard.TargetProperty="(Grid.Column)"> <DiscreteObjectKeyFrame KeyTime="0" Value="0"/> </ObjectAnimationUsingKeyFrames>--> ... <!--<ObjectAnimationUsingKeyFrames Storyboard.TargetName="itemSubtitle" Storyboard.TargetProperty="Style"> <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource CaptionTextStyle}"/> </ObjectAnimationUsingKeyFrames>--> </Storyboard> </VisualState>
In DetailPage.xaml, we just need to adjust the margin of our WebView in the Snapped view to use all the available space. In the XAML for the Snapped visual state, we add an animation to change the value of the Margin property on contentViewBorder, as shown here.
<VisualState x:Name="Snapped"> <Storyboard> ... <ObjectAnimationUsingKeyFrames Storyboard.TargetName="contentViewBorder" Storyboard.TargetProperty="Margin"> <DiscreteObjectKeyFrame KeyTime="0" Value="20,5,20,20"/> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState>
Adding a splash screen and logo
The first impression our app makes on a user comes from the logo and splash screen. The logo appears in the Windows Store and on the start screen. The splash screen is shown instantly when a user launches the app, and gives immediate feedback to the user while our app initializes its resources. It's dismissed when the first page of our app is ready to show.
The splash screen consists of a background color and an image that's 620 x 300 pixels. We set these values in the Package.appxmanifest file. Double click this file to open it in the manifest editor. On the Application UI tab of the manifest editor, we set the path to our splash screen image and the background color. The project template provides a default blank image named SplashScreen.png. We replace this with our own splash screen image that clearly identifies our app and immediately draws users into our app. We can also specify a logo by replacing the template logo files with our own. Here's the splash screen for our blog reader.

The basic splash screen works well for our blog reader, but you can also extend the splash screen using the properties and methods of the SplashScreen class. You can use the SplashScreen class to get the coordinates of the splash screen and use them to place the first page of the app. And you can find out when the splash screen is dismissed so you know it's time to start any content entrance animations for the app.
What's next
We learned how to use built-in page templates from Visual Studio Express 2012 RC for Windows 8 to build a complete multi-page app, and how to navigate and pass data between the pages. We learned how to use styles and templates to make our app fit the personality of the Windows team blogs website. We also learned how to use theme animations, an app bar, and a splash screen to make our app fit the personality of Windows 8. Finally, we learned how to adapt our app to various layouts and orientations so that it always looks its best.
For more info about developing apps, see the learning and reference resource list for creating Metro style apps.
Roadmap for Metro style apps using C# or Visual Basic.
Build date: 5/31/2012
