Windows 8 Tutorial
Windows 8 Tutorial
1: app
Create
a "Hello,
world"
(Windows
Store
apps
C#/VB and
XAML)using
(Windows)
This tutorial teaches you how to create a simple "Hello, world" Windows Store app using
Extensible Application Markup Language (XAML) with Microsoft Visual Basic or C#. It's the first
tutorial in a series that teach you what you need to know to build Windows Store apps.
In this tutorial, you learn how to:
We show you how to create a Windows Store app using XAML with Visual Basic or C#.
For the JavaScript, HTML, and CSS versions of these tutorials, see Create your first
Windows Store app using JavaScript.
For the C++ and XAML tutorial, see Create your first Windows Store app using C++.
For the DirectX and C++ tutorial, see Create your first Windows Store app using
DirectX.
To complete this tutorial, you need Windows 8 and Microsoft Visual Studio
Express 2012 for Windows 8. To download them, see Get the tools.
You also need a developer license. For instructions, see Get a developer license.
We assume you have a basic understanding of XAML and the concepts in the XAML
overview.
We assume you're using the default window layout in Microsoft Visual Studio. If you
change the default layout, you can reset it in the Window menu by picking the Reset
Window Layout command.
You can see the complete code for this tutorial in Part 1 complete code.
templates to display.
In the left pane, expand Installed > Templates, then expand Visual Basic or Visual
C# and pick the Windows Store template type. The dialog's center pane displays a
list of project templates for Windows Store apps.
In the center pane, select the Blank App template.
The Blank App template creates a minimal Windows Store app that compiles and
runs, but contains no user interface controls or data. You add controls and data to the
app over the course of these tutorials.
Although the Blank App is a minimal template, it still contains a lot of files:
A manifest file (package.appxmanifest) that describes your app (its name, description,
tile, start page, and so on) and lists the files that your app contains.
A set of large and small logo images (logo.png and smalllogo.png)to display in the start
screen.
XAML and code files for the app (App.xaml and App.xaml.cs/.vb) .
These files are essential to all Windows Store apps using Visual Basic or C#. Any project that
you create in Visual Studio contains them.
Select Project > Add New Item. The Add New Item dialog box opens. It looks
Under Visual C# or Visual Basic in the left pane, pick the Windows Store template
type.
In the center pane, pick Basic Page as the type of page to add to your project.
Click Add.
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 the addition depends on 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.
The XAML and code behind files for your page are added to the project.
At this point, you created a very simple app. If you want to see what it looks like, press F5 to
build, deploy, and launch your app in debugging mode. A default splash screen appears first.
The splash screen is defined by an image (splashscreen.png) and a background color (specified
in our app's manifest file). We don't cover it here, but it's easy to customize your splash
screen. (To find out how, see Adding a splash screen.)
The splash screen disappears, and then your app appears. It contains a black screen and the
title "My Application".
There's no button or command to close the app. You can use the close gesture or Alt+F4 to
close it, but you typically don't close Windows Store apps, as we discuss more in Part 2:
Manage app lifecycle and state. Press the Windows key to go to the Start screen; notice that
deploying the app adds its tile to the last group on the Start screen. To run the app again, tap
or click its tile on the start screen, or press F5 in Visual Studio to run it in debugging mode.
It doesn't do muchyetbut congratulations, you've built your first Windows Store app!
To stop debugging the app, press Alt+Tab to return to Visual Studio. In Visual Studio,
click Debug > Stop debugging to close the app. You can't edit in Visual Studio while you're
debugging.
For more info, see Running Windows Store apps from Visual Studio.
When you create a new project that uses the Blank App template, Visual Studio creates an
app that contains a handful of files. To view and edit the files, double-click the file in
the Solution Explorer. You can expand a XAML file just like a folder to see its associated code
file. By default, XAML files open in a split view that shows both the design surface and the
XAML editor.
In this tutorial, you work with just a few of the files listed previously: App.xaml,
App.xaml.cs/.vb, MainPage.xaml, and MainPage.xaml.cs/.vb.
App.xaml
App.xaml is where you declare resources that are used across the app. This file contains
a ResourceDictionary that has a reference to the
<Application
x:Class="HelloWorld.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:HelloWorld">
<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"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
App.xaml.cs/vb
App.xaml.cs/.vb is the code-behind file for App.xaml. Code-behind is the code that is joined
with the XAML page's partial class. Together, the XAML and code-behind make a complete
class. App.xaml.cs/.vb is the entry point for your app. Like all code-behind pages, it contains a
constructor that calls the InitializeComponent method. You don't write
theInitializeComponent method. It's generated by Visual Studio, and its main purpose is
to initialize the elements declared in the XAML file. App.xaml.cs/.vb also contains methods to
handle activation and suspension of the app. You add some code to these methods in Part 2:
Manage app lifecycle and state.
C#
VB
using
using
using
using
using
System;
Windows.ApplicationModel;
Windows.ApplicationModel.Activation;
Windows.UI.Xaml;
Windows.UI.Xaml.Controls;
class.
/// </summary>
sealed partial class App : Application
{
/// <summary>
/// Initializes the singleton application object. This is the first line of authored
code
/// executed, and as such is the logical equivalent of main() or WinMain().
/// </summary>
public App()
{
this.InitializeComponent();
this.Suspending += OnSuspending;
}
/// <summary>
/// Invoked when the application is launched normally by the end user. Other
entry points
/// will be used when the application is launched to open a specific file, to display
/// search results, and so forth.
/// </summary>
/// <param name="args">Details about the launch request and
process.</param>
protected override void OnLaunched(LaunchActivatedEventArgs args)
{
Frame rootFrame = Window.Current.Content as Frame;
// Do not repeat app initialization when the Window already has content,
// just ensure that the window is active
if (rootFrame == null)
{
// Create a Frame to act as the navigation context and navigate to the first
page
rootFrame = new Frame();
if (args.PreviousExecutionState == ApplicationExecutionState.Terminated)
{
//TODO: Load state from previously suspended application
}
// Place the frame in the current Window
Window.Current.Content = rootFrame;
}
if (rootFrame.Content == null)
{
// When the navigation stack isn't restored navigate to the first page,
// configuring the new page by passing required information as a navigation
// parameter
if (!rootFrame.Navigate(typeof(MainPage), args.Arguments))
{
MainPage.xaml
In the MainPage.xaml file you define the UI for your app. You can add elements directly using
XAML markup, or you can use the design tools provided by Visual Studio. The Basic
Page template creates a new class called MainPage (or whatever name you enter) that
inherits from LayoutAwarePage. The LayoutAwarePage class extends the base Page class
and provides methods for navigation, state management, and view management. The Basic
Page template also includes some simple content, like a back button and page title.
XAML
<common:LayoutAwarePage
x:Name="pageRoot"
x:Class="HelloWorld.MainPage"
DataContext="{Binding DefaultViewModel, RelativeSource={RelativeSource
Self}}"
IsTabStop="false"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:HelloWorld"
xmlns:common="using:HelloWorld.Common"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Page.Resources>
<!-- TODO: Delete this line if the key AppName is declared in App.xaml -->
<x:String x:Key="AppName">My Application</x:String>
</Page.Resources>
<!-This grid acts as a root panel for the page that defines two rows:
* Row 0 contains the back button and page title
* Row 1 contains the rest of the page layout
-->
<Grid Style="{StaticResource LayoutRootStyle}">
<Grid.RowDefinitions>
<RowDefinition Height="140"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- 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="{StaticResource
AppName}" Style="{StaticResource PageHeaderTextStyle}"/>
</Grid>
<VisualStateManager.VisualStateGroups>
<!-- Visual states reflect the application's view state -->
<VisualStateGroup x:Name="ApplicationViewStates">
<VisualState x:Name="FullScreenLandscape"/>
<VisualState x:Name="Filled"/>
<!-- 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>
</Storyboard>
</VisualState>
<!-- The back button and title have different styles when snapped -->
<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>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Grid>
</common:LayoutAwarePage>
MainPage.xaml.cs/vb
MainPage.xaml.cs/.vb is the code-behind page for MainPage.xaml. Here you add your app logic
and event handlers. TheBasic Page template includes 2 methods where you can save and
load the page state.
C#
VB
using System;
using System.Collections.Generic;
using Windows.UI.Xaml.Controls;
// The Basic Page item template is documented at http://go.microsoft.com/fwlink/?
LinkId=234237
namespace HelloWorld
{
/// <summary>
/// A basic page that provides characteristics common to most applications.
/// </summary>
public sealed partial class MainPage : HelloWorld.Common.LayoutAwarePage
{
public MainPage()
{
this.InitializeComponent();
}
/// <summary>
/// Populates the page with content passed during navigation. Any saved state
is also
/// provided when recreating a page from a prior session.
/// </summary>
/// <param name="navigationParameter">The parameter value passed to
/// <see cref="Frame.Navigate(Type, Object)"/> when this page was initially
requested.
/// </param>
To change the page title, select the "My Application" text near the top of the page in
the XAML designer.
Make sure the TextBlock named pageTitle is showing in the Properties panel. By
default, the Properties panel is below the Solution Explorer panel.
The Properties panel contains a list of properties and values for the selected object.
Next to each property value is a property marker, a small box symbol that you can
click to open a property menu. The Text property marker is green to indicate that it's
set to a resource.
Under Common in the Properties panel, click the property marker for
the Text property. The property menu opens.
In the property menu, select Edit Resource. The Edit Resource dialog opens.
In the Edit Resource dialog, change the value from "My Application" to "Hello,
world!".
Click OK.
Instead of entering the app name directly into the text block, you updated a string
resource that the text block'sText property is bound to. Using a resource like this
makes text reusable, easier to maintain, and easier to localize. In MainPage.xaml, the
XAML for the AppName resource definition is updated like this.
XAML
We talk more about XAML layout in Part 3: Navigation, layout, and views.
Press F5 to run the app. It looks like this.
You can type in the TextBox, but right now, clicking the Button doesn't do anything.
In the next steps, you create an event handler for the button's Click event that
displays a personalized greeting. You add the event handler code to your
MainPage.xaml.cs/.vb file.
XAML elements can send messages when certain events occur. These event messages give
you the opportunity to take some action in response to the event. You put your code to
respond to the event in an event handler method. One of the most common events in many
apps is a user clicking a Button.
Let's create an event handler for your button's Click event. The event handler will get the
user's name from thenameInput TextBox control and use it to output a greeting to
the greetingOutput TextBlock.
Using events that work for touch, mouse, and pen input
What event should you handle? Because they can run on a variety of devices, design your
Windows Store apps with touch input in mind. Your app must also be able to handle input from
a mouse or a stylus. Fortunately, events such asClick and DoubleTapped are deviceindependent. If you're familiar with Microsoft .NET programming, you might have seen
separate events for mouse, touch, and stylus input, like MouseMove, TouchMove,
and StylusMove. In Windows Store apps, these separate events are replaced with a
single PointerMoved event that works equally well for touch, mouse, and stylus input.
To add an event handler
In XAML or design view, select the "Say Hello" Button that you added to
MainPage.xaml.
).
Find the Click event at the top of the event list. In the text box for the event, type the
name of the function that handles the Click event. For this example, type
"Button_Click".
Press Enter. The event handler method is created and opened in the code editor so you
can add code that's executed when the event occurs.
In the XAML editor, the XAML for the Button is updated to declare the Click event
handler like this.
XAML
Add code to the event handler that you created in the code behind page. In the event
handler, retrieve the user's name from the nameInput TextBox control and use it to
create a greeting. Use the greetingOutput TextBlock to display the result.
C#
VB
Press F5 to build and run the app. When you enter your name in the text box and click
the button, the app displays a personalized greeting.
In the opening Application tag, add the RequestedTheme property with its value set
to Light.
XAML
RequestedTheme="Light"
Here's the full Application tag with the light theme added.
XAML
<Application
x:Class="HelloWorld.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:HelloWorld"
RequestedTheme="Light">
Press F5 to build and run the app. Now it uses the light theme.
Which theme should you use? Whichever one you want. For apps that mostly display images or
video, we recommend using the dark theme, and for apps that contain a lot of text, we
recommend using the light theme. If you're using a custom color scheme, use the theme that
goes best with your app's look and feel.
Note The theme is applied when the app is started. You can't change themes while the app is
running.
<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.MergedDictionaries>
Right now, all the text is very small and difficult to read. You can easily apply the standard
styles to elements in your app to make them look great.
To style an element
In XAML or design view, select the "What's your name?" TextBlock that you added
previously.
Click the property marker next to the Style property to open the menu.
).
In the XAML design surface, the appearance of the text changes. In the XAML editor,
the XAML for the TextBlockis updated.
XAML
Press F5 to build and run the app. It now looks like this.
In XAML or design view, select the greetingOutput TextBlock that you added to
MainPage.xaml.
Click the property marker next to the Style property to open the menu.
In the Create Style Resource dialog, enter "BigGreenTextStyle" as the resource key,
and select the option to define the resource in the application.
Click OK. The new style is created in App.xaml and the TextBlock is updated to use
the new style resource.
XAML
Click the property marker next to the Style property to open the menu again.
Press F5 to build and run the app. The greeting is now displayed in large, green letters.
Summary
Congratulations, you're done with the first tutorial! You learned how to add content to a
Windows Store app. You also learned how to add interactivity and how to style the app.
Next steps
In the next part of this tutorial series, you learn how to app lifecycle works and how to save
your app's state. Go to Part 2: Manage app lifecycle and state.
Part
2:
Manage
app
lifecycle
and
state
(Windows
Store
apps
using
C#/VB
and XAML)
(Windows)
In Windows 8, you can launch a bunch of apps and switch between them without having to
worry about slowing down the system or running the battery down. That's because the system
automatically suspends (and sometimes terminates) apps that are running in the background
for you. A well-designed app can be suspended, terminated, and relaunched by the system and
seem as though it were running the entire time.
In this tutorial, you learn how to:
Restore your app's state the next time the app is launched
This is the second tutorial in a series. Before you start this tutorial, read Part 1: Create
a "Hello, world!" app.
You can see the complete code for this tutorial in Part 2 complete code.
In Part 1: Create a "Hello, world" app, you replaced the default MainPage file with one based on
the Basic Page template. When you used the Basic Page template, Microsoft Visual Studio
added several files to the project in the Common folder. One of these files contains
HelloWorld.Common.SuspensionManager.RegisterFrame(rootFrame,
"appFrame");
Add this code after the new Frame is created, as shown here.
C#
VB
if (rootFrame == null)
{
// Create a Frame to act as the navigation context and navigate to the first
page
rootFrame = new Frame();
HelloWorld.Common.SuspensionManager.RegisterFrame(rootFrame,
"appFrame");
...
container makes it easy to store data in a way that is accessible to the user across multiple
machines. Basically, the data is uploaded to the cloud in the background for you. You can also
use the local settings app data container (LocalSettings), but you should only use it when
you want to store machine-specific info.
Save persistent app data as often as it makes sense in your application. Here, you handle
the TextBox.TextChangedevent and save the user name as the user enters it.
To save app data
Find the TextChanged event in the event list. In the text box for the event, type
"NameInput_TextChanged" as the name of the function that handles
the TextChanged event.
Press Enter. The event handler method is created and opened in the code editor so you
can add code that's executed when the event occurs.
Add this code to the event handler in the code behind page. In the event handler, you
save the nameInput text inroamingSettings.
).
C#
VB
Windows.Storage.ApplicationDataContainer roamingSettings =
Windows.Storage.ApplicationData.Current.RoamingSettings;
roamingSettings.Values["userName"] = nameInput.Text;
Press F5 to build and run the app. Your name is saved as you enter it into the text box.
Session data is temporary data that is relevant to the users current session in your app. A
session ends when the user closes the app using the close gesture or Alt + F4, reboots the
computer, or logs off the computer. In your app, the Textof
the greetingOutput TextBlock is session data. You restore it only if Windows suspends and
terminates the app. You need to save the navigation state of the app Frame, so the app can
be restored to the same page is was on, and so the SuspensionManager knows which page to
restore the state of. You also need to save the state of the page itself. This is where you save
the greetingOutput text. You use the SuspensionManager class to save session state in
theApplication.Suspending event handler.
(For more info about the other ways you can save state, see Managing app data and Working
with state efficiently.)
The App.xaml.cs/vb file contains a handler for the Application.Suspending event. This event
handler gets called when Windows is about to suspend your app. This is your opportunity to
save the state of the app in case it gets terminated. You use the SuspensionManager class to
simplify saving session state. It saves the navigation state of the app, and gives you the
opportunity to save the session state of the active page.
To save the session state
await HelloWorld.Common.SuspensionManager.SaveAsync();
Calling SaveAsync saves the navigation state of the Frame and then gives
your Page the opportunity to save its content.
Here's the full OnSuspending method with the updates made.
C#
VB
/// <summary>
/// Invoked when application execution is being suspended. Application
state is saved
/// without knowing whether the application will be terminated or
resumed with the contents
/// of memory still intact.
/// </summary>
/// <param name="sender">The source of the suspend
request.</param>
/// <param name="e">Details about the suspend request.</param>
private async void OnSuspending(object sender, SuspendingEventArgs e)
{
var deferral = e.SuspendingOperation.GetDeferral();
//TODO: Save application state and stop any background activity
await HelloWorld.Common.SuspensionManager.SaveAsync();
deferral.Complete();
}
In MainPage.xaml.cs/vb, add this code to the SaveState method to save the page
state.
C#
VB
pageState["greetingOutputText"] = greetingOutput.Text;
/// <summary>
/// Preserves state associated with this page in case the application is
suspended or the
/// page is discarded from the navigation cache. Values must conform to
the serialization
/// requirements of <see cref="SuspensionManager.SessionState"/>.
/// </summary>
/// <param name="pageState">An empty dictionary to be populated
with serializable state.</param>
protected override void SaveState(Dictionary<String, Object>
pageState)
{
pageState["greetingOutputText"] = greetingOutput.Text;
// The user name is already saved, so you don't need to save it here.
}
Click Build > Build solution to make sure the app builds with no errors.
That's all you need to do to save your app's state before your app is terminated. Now you need
to learn how to restore your app's state the next time the user launches the app.
Earlier, you saw that the App.xaml.cs/vb file contains code that handles your app's activation.
There are many different ways to activate an app. Here we look at the Launch activation and
the OnLaunched method.
An app is launched whenever it wasn't running and then the user activates it. When an app is
launched, Windows displays a splash screen for the app.
Let's take a look at the code in App.xaml.cs/vb that handles app activation. The code defines
an override of theOnLaunched method. The code in this method is executed only if the
activation is a Launch activation. (You can override other methods to handle other kinds of
activation, but we don't do it here. For more info, see Application lifecycle.)
First, the code declares a Frame and tries to assign the current window contents to it.
C#
VB
// Do not repeat app initialization when the Window already has content,
// just ensure that the window is active
if (rootFrame == null)
{
// Create a Frame to act as the navigation context and navigate to the first
page
rootFrame = new Frame();
HelloWorld.Common.SuspensionManager.RegisterFrame(rootFrame,
"appFrame");
if (args.PreviousExecutionState == ApplicationExecutionState.Terminated)
{
//TODO: Load state from previously suspended application
}
// Place the frame in the current Window
Window.Current.Content = rootFrame;
}
Next, the code checks if the Frame contains any content. If the app is already running, or the
navigation state was restored, the Frame already has content. Otherwise,
the Frame navigates to the first page in the app. In this case, it navigates to MainPage.
C#
VB
if (rootFrame.Content == null)
{
// When the navigation stack isn't restored navigate to the first page,
// configuring the new page by passing required information as a navigation
// parameter
if (!rootFrame.Navigate(typeof(MainPage), args.Arguments))
{
throw new Exception("Failed to create initial page");
}
}
VB
Now that you know what happens when the app is launched, let's look at how to restore the
app state.
To restore the app's state
if (args.PreviousExecutionState ==
ApplicationExecutionState.Terminated)
{
//TODO: Load state from previously suspended application
await HelloWorld.Common.SuspensionManager.RestoreAsync();
}
In MainPage.xaml.cs/vb, add code to the LoadState method to restore the page state.
First, check to see if the pageState dictionary exists and has a key
named greetingOutputText. If the key exists, use it to restore
the greetingOutput text.
C#
VB
Next, load the user name. Because you want the user name data to persist
over multiple sessions, you store it in the RoamingSettings app data
container. Let's add some code to see whether the user name exists and, if it
does, display it.
C#
VB
C#
VB
/// <summary>
/// Populates the page with content passed during navigation. Any saved
state is also
/// provided when recreating a page from a prior session.
/// </summary>
/// <param name="navigationParameter">The parameter value passed
to
/// <see cref="Frame.Navigate(Type, Object)"/> when this page was
initially requested.
/// </param>
/// <param name="pageState">A dictionary of state preserved by this
page during an earlier
/// session. This will be null the first time a page is visited.</param>
protected override void LoadState(Object navigationParameter,
Dictionary<String, Object> pageState)
{
// Restore values stored in session state.
if (pageState != null &&
pageState.ContainsKey("greetingOutputText"))
{
greetingOutput.Text = pageState["greetingOutputText"].ToString();
}
Now you can build and run the app, and see how the session state is saved and restored. So
far, you've tested your app by running it in debug mode, and stopped it by
selecting Debug > Stop Debugging in Visual Studio. But doing this causes the app to
perform a normal shutdown, and the Suspending event doesn't occur. Fortunately, Visual
Studio lets you simulate suspending, terminating, and restoring an app.
To simulate suspending, terminating, and restoring an app in Visual Studio
Enter your name in the input box and click "Say "Hello"". The greeting is displayed.
Open the drop down menu next to the Suspend button on the Debug
Location toolbar.
The Debug Location toolbar appears by default while the debugger is running. If you
don't see it, click View >Toolbars > Debug Location to show it.
Press F5 to run the app again. The app is restored to its previous state.
Change the name in the text box, and click "Say "Hello"".
Summary
Congratulations, you're done with the second tutorial! You learned how to save app data and
session state in a Windows Store app.
Next steps
In the next part of this tutorial series, you learn how to use the design tools in Visual Studio to
create a more complex UI. Go to Part 3: Navigation, layout, and views.
Part
3:
Navigation,
layout,
and views (Windows)
The UI design for your Windows Store app is about organizing and presenting content to your
users, and providing commands that enable your users to act on the content. UI design
includes the organization of pages in the app, the navigation between pages, and the layout of
content and commands on each page.
In this tutorial, you learn how to:
This is the third tutorial in a series. Before you start this tutorial, read Part 1: Create a
"Hello, world!" app and Part 2: Manage app lifecycle and state.
You can see the complete code for this tutorial in Part 3 complete code.
Select Project > Add New Item. The Add New Item dialog box opens.
Tip Make sure the project, and not the solution, is selected in Solution Explorer.
Under Visual C# or Visual Basic in the left pane, pick the Windows Store template
type.
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), Microsoft Visual Studio shows a dialog with a message that you need to add
files that are missing from your project. You added these files in Part 1, so you should
not see this warning. If you do, click Yes to add these files. Files for several utility
classes are added to your project in the Common folder.)
To change the page title, select the "My Application" text near the top of
PhotoPage.xaml.
Make sure the TextBlock named pageTitle is showing in the Properties panel and
) is selected.
Under Common in the Properties panel, click the property marker for
the Text property. The property menu opens.
Note The property marker is the small box symbol to the right of each property value.
The Text property marker is green to indicate that it's set to a resource.
In the property menu, select Edit Resource. The Edit Resource dialog opens.
In the Edit Resource dialog, change the value from "My Application" to "Hello,
photo!".
Click OK.
The XAML for the resource definition is updated like this.
XAML
Add navigation
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 also pass data between pages as you navigate.
In Part 1 and Part 2, you saw the code in App.xaml.cs/.vb that creates a Frame and navigates
to MainPage when the app is started. Here, you add a command to MainPage to navigate to
the new PhotoPage in the same way.
To navigate between pages
BigGreenTextStyle}"/>
<Button x:Name="photoPageButton" Content="Go to photo page"/>
</StackPanel>
In the XAML editor or design view, select the "Go to photo page" Button that you
added to MainPage.xaml.
Find the Click event at the top of the event list. In the text box for the event, type
"PhotoPageButton_Click" as the name of the function that handles the Click event.
Press Enter. The event handler method is created and opened in the code editor so you
can add code that's executed when the event occurs.
Add this code to the event handler that you created in the code behind page. In the
event handler, navigate to the new photo page that you added to the app.
).
C#
VB
Press F5 to build and run the app. Click the Go to photo page button. The photo page
opens. Click the back button to navigate back to the main page.
You don't need to add a back button to the photo page. The photo page is based on
the LayoutAwarePage class, which has built-in support for navigation. The back button uses
the Frame history to go back to the previous page, and is shown only when
the Frame.CanGoBack property is true. For more examples of navigation support, see the
"Navigation support" region of the LayoutAwarePage.cs/.vb file in the Common folder of the
project.
Now you add content to the photo page. Before you start working on the layout of the photo
page, it's helpful to understand the fundamentals of layout using XAML.
places, but make sure that the overall UI is fluid and adapts to different resolutions, layouts,
and views.
Most app content can be organized into some form of groupings or hierarchies. You use layout
containers to group and arrange UI elements. The XAML layout system provides
various Panel controls, such as Grid, StackPanel, and Canvas, that serve as containers in
which you arrange your content. Most containers do some automatic sizing of their child
elements if the elements don't have an explicit size set.
You use a Grid to arrange content in rows and columns. You position elements using
the Grid.Row and Grid.Columnattached properties. You can make elements span multiple
rows and columns by using the Grid.RowSpan andGrid.ColumnSpan attached properties.
You use a StackPanel to arrange content in single line. You can set the Orientation property
to stack items either vertically or horizontally.
You use a Canvas when you want to control all aspects of positioning and sizing of content. In
a Canvas, you position elements absolutely using Canvas.Top and Canvas.Left attached
properties. A canvas doesn't do any sizing of child elements, so you have to size them
explicitly.
To control the size and position of an element, you set its layout properties. Here are some
common layout properties and their effect.
Margin: Specifies the amount of empty space around the control, between the outside
of the child object and the boundaries of the panel.
You use these containers and layout properties to create a fluid layout for the photo viewer
page.
Image
Description
Use to manage
files in your
project.
Double-click
a file to
open it. If
the file is
already
open, it's
made the
active
document.
Properti
es
XAML
Designe
r
Show
advanced
properties
by clicking
the down
arrow at
the bottom
of a
category.
Common
interaction
s are drag
-and-drop
to arrange
items, and
click to
select an
item.
XAML
editor
Toolbox
Use to add
controls and other
items to your app
UI.
Drag and
drop
controls
onto the
surface of
the
designer.
Device
Use to simulate
different settings
of a physical
device in the
designer.
Click the
view
buttons to
simulate
different
app views
in the
designer.
Docume
nt
Outline
Change the
Display
settings to
simulate
different
resolutions
in the
designer.
contiguous
items.
Use
Shift+Click
to select
multiple
contiguous
items.
Drag-anddrop items
to
rearrange
them.
We assume that you're using the default window layout in Visual Studio. If you change the
default layout, you can reset it in the Window menu by picking the Reset Window
Layout command.
There are some common tasks that you repeat often while creating a UI. Knowing how to
complete these tasks before we start will make creating the UI easier.
To open a file
Double-click the file name in Solution Explorer. If the file is already open, it is made
active in the designer and XAML editor.
By default, the Toolbox, Device, and Document Outline panels are collapsed to the left of the
designer.
To open the Toolbox, Device, or Document Outline panels
Open any of the panels by clicking the name of the panel you want to open.
To keep the panel open, click the Auto Hide (pin) icon in the panel header.
Tip If the Toolbox covers a part of the XAML designer where you need to drop a control,
pin the Toolboxopen.
Here are various ways you can select an item and make it active. In some situations, one way
might be easier than others. In that case, we will suggest the easiest way to select the item.
To select an item
In the Document Outline, click the element or the element name if it has a name.
In the XAML editor, click the opening tag for the element.
In the XAML designer, do one of these:
Move your mouse cursor over the item until a blue highlight appears around it.
Click the highlighted item to make it active.
Right-click an object in the designer. In the context menu, open the Set Current
Selection sub-menu and pick the item to make active.
The Properties panel has views for managing both properties and events.
Bottom
Anchors to the bottom but stretches to the top when resized.
Center
Always anchored to the vertical center regardless of resizing.
Top
Anchors to the top but stretches to the bottom when resized.
Stretch
Stretches in both vertical directions when resized.
To change the margins of an element
Select the element to set margins on.
Under Layout in the Properties panel, set one or more of the Margin values: Left, Right,
Top, Bottom.
Click the New button next to TopAppBar. An AppBar control is added to the page.
Select the "photoPageButton" element, drag it onto the AppBar, and drop it.
Press F5 to build and run the app. To test the app bar, right-click on the main page. The
) to show
Move this Style outside of the comment tags (<!-- comment -->) to make it
available to use.
Click the property marker next to the Style property to open the menu.
<common:LayoutAwarePage.TopAppBar>
<AppBar>
<Button x:Name="photoPageButton"
Click="PhotoPageButton_Click"
HorizontalAlignment="Right"
Style="{StaticResource PicturesAppBarButtonStyle}"/>
</AppBar>
</common:LayoutAwarePage.TopAppBar>
Press F5 to build and run the app. To open the app bar, swipe from the top or bottom
edge of the screen, or right-click the app.
You used the app bar to clean up the layout of the main page. Now we turn our attention the
new photo viewer page.
Open PhotoPage.xaml.
Drag a Grid from the Toolbox and drop it onto the design surface in the middle of the
page.
The Grid is added to the page, and the designer sets some properties based on its
best guess at the layout you want. A blue highlight appears around the Grid to
indicate that it is now the active object.
Reset
these Grid properties: Width, Height, HorizontalAlignment, VerticalAlignment,
and Margin. The Gridnow completely fills the content area of the page.
Under Layout, set the left Margin and bottom Margin to "120".
In the designer, dotted lines called grid rails appear along the top and left sides of
the Grid. Move your cursor over the left side grid rail. The pointer changes to an arrow
with a plus (+) sign, and an orange line shows where a row will be added.
Place your cursor over the grid rail in the first row until the flyout appears.
Click the down arrow to open the flyout menu. Select Pixel in the menu.
Place your cursor over the grid rail again until the flyout appears. In the flyout, click
the number value.
Type "50" and press Enter to set the Height property to 50 pixels.
Repeat the process in steps 9-12 to set the second row Height to 70 pixels.
The last row is set to the default value of "1*" (1 star), which means it will use any
remaining space.
Now, let's look at the XAML that's produced by this.
XAML
Reset
these StackPanel properties: Width, Height, HorizontalAlignment, Vertic
alAlignment, andMargin.
In the Name text box for the StackPanel, type "imagePanel", then press
Enter.
With the StackPanel selected, drag a Border control from the Toolbox and
drop it in the StackPanel.
Pick the solid color brush tab, then set the color value to "#FF808080".
Drag an Image control from the Toolbox and drop it in the Border.
In the Name text box for the Image, type "displayImage", then press Enter.
In the drop-down list for the Image Source property, select "Logo.png".
In the Document Outline, select the Border that contains the Image.
Select the first TextBlock and set its Text property to "File name:".
Select the third TextBlock and set its Text property to "Path:".
Select the fifth TextBlock and set its Text property to "Date created:".
The photo viewer UI looks like this now. The layout is nearly complete, but you still need to fix
the appearance of theTextBlocks that show the picture info.
In the Document Outline, click the first TextBlock in the "imagePanel" StackPanel.
Press Shift, then click the last TextBlock in the group. The 6 TextBlock controls are
now selected.
Under Layout in the Properties panel, set the StackPanel Orientation property
to Vertical.
The last thing to do is to format the picture info text. You use built-in styles for the text, and set
some margins to create space between the elements.
To style the text
In the Document Outline, click the first TextBlock in the "imagePanel" StackPanel.
Press Ctrl, then click the third and fifth TextBlock in the group.
Three TextBlock controls are now selected.
Select the second, fourth, and sixth TextBlock controls in the group.
Set the left Margin property value to 10, and the bottom value to 30.
The XAML for the picture info text now looks like this.
XAML
<StackPanel Margin="20,0,0,0">
<TextBlock TextWrapping="Wrap" Text="File name:"
Style="{StaticResource CaptionTextStyle}"/>
<TextBlock TextWrapping="Wrap" Text="TextBlock"
Style="{StaticResource ItemTextStyle}" Margin="10,0,0,30"/>
<TextBlock TextWrapping="Wrap" Text="Path:"
Style="{StaticResource CaptionTextStyle}"/>
<TextBlock TextWrapping="Wrap" Text="TextBlock"
Style="{StaticResource ItemTextStyle}" Margin="10,0,0,30"/>
<TextBlock TextWrapping="Wrap" Text="Date created:"
Style="{StaticResource CaptionTextStyle}"/>
<TextBlock TextWrapping="Wrap" Text="TextBlock"
Style="{StaticResource ItemTextStyle}" Margin="10,0,0,30"/>
</StackPanel>
Press F5 to build and run the app. Navigate to the photo page. It now looks like this.
This is what the app looks like when the user snaps another app next to it. This view
looks okay, so you can leave it as is.
This is what the app looks when the user snaps it next to another app. This view is too
narrow to show the whole app, so you need to make some adjustments for this to
work.
This is what the app looks like when the user rotates it to portrait orientation. This view
is also too narrow. You need to make some adjustments similar to those you make for
the snapped view.
Under Layout in the Properties panel, set the panel's Orientation property
to Vertical.
Under Layout in the Properties panel, set the panel's Orientation property
to Vertical.
Summary
Congratulations, you're done with the third tutorial! You learned how to save app data and
session state in a Windows Store app.
Next steps
In the next part of this tutorial series, you learn how to access and work with files. Go to Part 4:
File access and pickers.
Part
4:
File
access
and
pickers (Windows)
In Part 2 of this tutorial series, Manage app lifecycle and state, you learned aboutapp
data and session data, and how to save this data in ApplicationDatastorage. Your app can
access certain file system locations, like app data locations, the app install directory, and items
it creates in the Downloads folder, by default.
In contrast, user data, such as pictures, videos, and document files, is independent of your app
and is typically stored in other locations in the file system, such as the users library folders. To
access these locations, your app needs to declare capabilities to access the data
programmatically, or use a file picker to let the user open the file manually. Here, you use a file
picker to access the users Pictures library, so you don't need to declare any app capabilities.
For more info about capabilities, see App capability declarations.
In this tutorial, you add functionality to the photo page layout you created in Part 3:
Navigation, layout, and views. First, you handle the "Get photo" button click event to open a
file picker and let the user select an image from their Pictures library. Then you bind UI controls
to file properties to show the picture info. Finally, we revisit what you learned in Part 2 about
how to save app state. Here, you use aMostRecentlyUsedList to keep access to the image
selected by the user.
In this tutorial, you learn how to:
This is the fourth tutorial in a series. Before you start, read Part 1: Create a "Hello,
world!" app, Part 2: Manage app lifecycle and state, and Part 3: Navigation, layout, and
views.
You can see the complete code for this tutorial in Part 4 complete code.
The first thing you need to do is handle the GetPhotoButton_Click event to get a picture to
show.
We start here with the code from Part 3: Navigation, layout, and views.
To add a file picker
Find the Click event at the top of the event list. In the text box for the event, type
"GetPhotoButton_Click" as the name of the method that handles the Click event.
Press Enter. The event handler method is created and opened in the code editor so you
can add code that's executed when the event occurs.
Add the async keyword to the method signature of the event handler.
).
C#
VB
Add this code to the event handler method. It opens a file picker to let the user select a
picture from their Pictures library. When they pick a file, it's set as the source of the
image and the data context of the page.
C#
VB
openPicker.FileTypeFilter.Clear();
openPicker.FileTypeFilter.Add(".bmp");
openPicker.FileTypeFilter.Add(".png");
openPicker.FileTypeFilter.Add(".jpeg");
openPicker.FileTypeFilter.Add(".jpg");
// Open the file picker.
Windows.Storage.StorageFile file = await
openPicker.PickSingleFileAsync();
// file is null if user cancels the file picker.
if (file != null)
{
// Open a stream for the selected file.
Windows.Storage.Streams.IRandomAccessStream fileStream =
await file.OpenAsync(Windows.Storage.FileAccessMode.Read);
// Set the image source to the selected bitmap.
Windows.UI.Xaml.Media.Imaging.BitmapImage bitmapImage =
new Windows.UI.Xaml.Media.Imaging.BitmapImage();
bitmapImage.SetSource(fileStream);
displayImage.Source = bitmapImage;
this.DataContext = file;
// mruToken =
Windows.Storage.AccessCache.StorageApplicationPermissions.MostRecentlyUs
edList.Add(file);
}
}
Press F5 to build and run the app. Navigate to the photo page, and click the "Get
photo" button to launch theFileOpenPicker. The photo appears, but the photo info
text is not updated. You'll fix that in the next step.
Here's what the app looks like with a picture selected.
Lets take a closer look at the code to use the FileOpenPicker. To use a file picker you need to
do 3 basic steps: ensure that the file picker can be opened, create and customize a file picker
object, and show the file picker so the user can pick an item.
You cant open the file picker UI in snapped view. So, before you call a file picker you must first
make sure that your app isnt snapped, or if it is, you must call the TryUnsnap method to
unsnap it.
C#
VB
if (Windows.UI.ViewManagement.ApplicationView.Value !=
Windows.UI.ViewManagement.ApplicationViewState.Snapped ||
Windows.UI.ViewManagement.ApplicationView.TryUnsnap() == true)
Set the properties on the file picker object that are relevant to your users and your app. For
guidelines to help you decide how to customize the file picker, see Guidelines for file pickers.
Because the user is picking a picture, you set the SuggestedStartLocation to the Pictures
library and the ViewMode toThumbnail. You also add file type filters so the picker shows only
the file types you specify for image files.
C#
VB
openPicker.SuggestedStartLocation =
Windows.Storage.Pickers.PickerLocationId.PicturesLibrary;
openPicker.ViewMode = Windows.Storage.Pickers.PickerViewMode.Thumbnail;
// Filter to include a sample subset of file types.
openPicker.FileTypeFilter.Clear();
openPicker.FileTypeFilter.Add(".bmp");
openPicker.FileTypeFilter.Add(".png");
openPicker.FileTypeFilter.Add(".jpeg");
openPicker.FileTypeFilter.Add(".jpg");
When the user picks a file, PickSingleFileAsync returns a StorageFile object that represents
the picked file. You process the image stream to create a BitmapImage and set
the BitmapImage as the Source of the Image control in the UI. You also set the file as
the DataContext of the page so that you can bind UI elements to its properties.
C#
VB
this.DataContext = file;
Here, you show the file name by binding the Text property of the title TextBlock to
the StorageFile.DisplayNameproperty of the selected file.
Because you dont specify a binding Source, the data binding engine looks for
the DisplayName property on theDataContext. If the DataContext is null or doesn't have
a DisplayName property, the binding fails silently and no text is shown in the TextBlock.
Here, you bind the TextBlock controls to StorageFile properties .
To bind controls to data
Select the TextBlock for the photo name that's under the "Get photo" button.
) to show
Under Common in the Properties panel, click the property marker for
the Text property. The property menu opens.
Note The property marker is the small box symbol to the right of each property value.
The Text property marker is black to indicate that it's set to a string value.
In the property menu, select Create Data Binding.... The Create Data
Binding dialog opens.
In the Create Data Binding dialog, select Data context in the Binding type dropdown list.
Click OK.
Here's the Extensible Application Markup Language (XAML) for the TextBlock after you
add the binding.
XAML
Here's the XAML for the photo info StackPanel after you add the bindings.
XAML
<StackPanel Margin="20,0,0,0">
<TextBlock Text="File name:" Style="{StaticResource
CaptionTextStyle}"/>
<TextBlock Text="{Binding Name}" Style="{StaticResource
ItemTextStyle}" Margin="10,0,0,30"/>
<TextBlock Text="Path:" Style="{StaticResource
CaptionTextStyle}"/>
<TextBlock Text="{Binding Path}" Style="{StaticResource
ItemTextStyle}" Margin="10,0,0,30"/>
<TextBlock Text="Date created:" Style="{StaticResource
CaptionTextStyle}"/>
<TextBlock Text="{Binding DateCreated}"
Style="{StaticResource ItemTextStyle}" Margin="10,0,0,30"/>
</StackPanel>
Press F5 to build and run the app. Navigate to the photo page. Click the "Get photo"
button to launch theFileOpenPicker. With bindings in place, file properties are now
shown when you pick a file.
Here's what the app looks like with a picture selected and the text blocks bound to
data.
FutureAccessList - use for general storage of up to 1000 files for future access.
You only need access to the last file the user picked so you can use it to restore the page state.
For this, theMostRecentlyUsedList fits your needs.
When a user picks a file, you add it to the MostRecentlyUsedList. When you add a file to this
list, theMostRecentlyUsedList returns a token that you use to retrieve the file later. You save
this token in the pageStatedictionary and use it to retrieve the current image file when you
restore the page state.
To save state
At the top of the PhotoPage class, add this code. It declares a variable to hold the
token returned by theMostRecentlyUsedList.
C#
VB
In the GetPhotoButton_Click event handler, add this code. It adds the picked file to
the MostRecentlyUsedListand gets the token.
C#
VB
this.DataContext = file;
// Add picked file to MostRecentlyUsedList.
mruToken =
Windows.Storage.AccessCache.StorageApplicationPermissions.MostRecentlyUs
edList.Add(file);
}
In the SaveState method, add this code. It checks if the token exists, and saves it in
the pageState dictionary if it does.
C#
VB
if (!String.IsNullOrEmpty(mruToken))
{
pageState["mruToken"] = mruToken;
}
Here's the complete code for the SaveState method.
C#
VB
Here, you get the token from the pageState dictionary. You use the token to retrieve
the file from theMostRecentlyUsedList and restore the UI state.
C#
VB
Press F5 to build and run the app. Navigate to the photo page, and click the "Get
photo" button to launch theFileOpenPicker and pick a file. Now, when the app is
suspended, terminated, and restored, the image is re-loaded.
Note Review Part 2: Manage app lifecycle and state for instructions on how to
suspend, terminate, and restore an app.
Summary
Congratulations, you're done with the fourth tutorial! You learned how to use file pickers and
data binding in a Windows Store app.
Next steps
In the next part of this tutorial series, you learn how to create a full blog reader app. Go to Part
5: Create a blog reader.
Part
5: Create
a apps
blog reader
(Windows
Store
using
C#/VB
and XAML)
(Windows)
We introduce the essential code and concepts you need to create a Windows Store 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 Windows Store apps using
C# or Visual Basic.
This is the last tutorial in a series. Before you start this tutorial, we recommend that
you read Part 1: Create a "Hello, world!" app, Part 2: Manage app lifecycle and
state, Part 3: Navigation, layout, and views, andPart 4: File access and pickers. This
tutorial introduces new concepts, and adds to concepts from the previous tutorials.
You can complete this tutorial without reading the previous ones. However, we assume
that you understand concepts from previous tutorials and can complete basic tasks in
Microsoft Visual Studio.
We assume you have a basic understanding of XAML and the concepts in the XAML
overview.
We assume you're using the default window layout in Visual Studio. If you change the
default layout, you can reset it in the Window menu by picking the Reset Window
Layout command.
You can see the complete code for this tutorial in Blog reader complete code.
Objectives
In this tutorial, we take a quick tour of the features that you'll use to build Windows Store 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. You learn
how to use the page templates and navigation that are built into Microsoft Visual Studio
Express 2012 for Windows 8 to quickly start your app development. You then learn how to use
custom styles to modify the look of the app, and how to adapt the UI to various layouts and
views. Finally, we briefly discuss integrating the app with Windows 8 and publishing it to the
Windows Store. By the time you complete this tutorial, you'll be prepared to start building your
own Windows Store apps.
Hello World
When you create your Windows Store 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 Windows Store 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
Windows Store app using 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.
XAML
<Page
x:Class="WindowsBlogReader.MainPage"
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>
C#
VB
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 Windows Store apps. The
sample app that you 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. When you're done, the app looks like this.
create a new Windows Store app project in Visual Studio Express 2012 for
Windows 8.
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 you'll use Visual Studio Express 2012 for Windows 8. You
can download it for free along with the Windows Software Development Kit (SDK) for Windows
8 so that you have everything you need to build, package and deploy your Windows Store
apps.
To get started creating an app, you create a new Windows Store project using C# or Visual
Basic. Visual Studio Express 2012 for Windows 8 includes several templates for Windows
Store 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 Store app.
For more info about Visual Studio Express 2012 for Windows 8, see Develop Windows Store
apps using Visual Studio 2012.
To create a new Windows Store project
Select File > New Project. The New Project dialog opens.
When you create your project, Visual Studio creates the project files and displays them
in Solution Explorer. Let's look at the folders and files that the Blank App (XAML) template
creates.
File Name
Description
Properties/AssemblyInfo (.vb
or .cs)
Package.appxmanifest
Assets/*
The default logo and splash screen images that you can
replace with your own.
Common/StandardStyles.xa
ml
App.xaml, App.xaml.cs/vb
MainPage.xaml
The default start page that you use to create the user
interface.
MainPage.xaml.cs/vb
The code-behind file that contains the logic for the default start
page.
To learn more about these files and templates, see Templates to speed up your app
development.
Before you create the UI for the app, you write the code to get the blog feed data so you have
something to show in the UI. The Windows team blogs expose the full text of the posts in both
RSS and Atom form. The blog data that you want to display in the reader app is the title,
author, date, and content from each of the latest blog posts.
To start, you 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
you. You find these classes in theWindows.Web.Syndication namespace. Its possible to use
these classes directly to show the data in the UI. But in the blog reader, you create your own
data classes. This gives you some additional flexibility and allows you to treat RSS and Atom
feeds in the same way.
You use 3 classes to hold and retrieve the feed data in the blog reader app. You put all 3
classes in one file named FeedData.cs/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.
To add data classes to the project
Select Project > Add Class. The New Item dialog box opens.
Copy this code into the FeedData.cs/vb file. Replace any code that is in the file.
C#
VB
using
using
using
using
using
using
System;
System.Collections.Generic;
System.Collections.ObjectModel;
System.Linq;
System.Threading.Tasks;
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.asp
x");
Task<FeedData> feed2 =
GetFeedAsync("http://windowsteamblog.com/windows/b/windowsexperience/a
tom.aspx");
Task<FeedData> feed3 =
GetFeedAsync("http://windowsteamblog.com/windows/b/extremewindows/ato
m.aspx");
Task<FeedData> feed4 =
GetFeedAsync("http://windowsteamblog.com/windows/b/business/atom.aspx")
;
Task<FeedData> feed5 =
GetFeedAsync("http://windowsteamblog.com/windows/b/bloggingwindows/ato
m.aspx");
Task<FeedData> feed6 =
GetFeedAsync("http://windowsteamblog.com/windows/b/windowssecurity/ato
m.aspx");
Task<FeedData> feed7 =
GetFeedAsync("http://windowsteamblog.com/windows/b/springboard/atom.asp
x");
Task<FeedData> feed8 =
GetFeedAsync("http://windowsteamblog.com/windows/b/windowshomeserver/
atom.aspx");
// There is no Atom feed for this blog, so 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.a
spx");
Task<FeedData> feed13 =
GetFeedAsync("http://windowsteamblog.com/windows_phone/b/wmdev/atom.
aspx");
Task<FeedData> feed14 =
GetFeedAsync("http://windowsteamblog.com/windows_phone/b/windowsphon
e/atom.aspx");
this.Feeds.Add(await
this.Feeds.Add(await
this.Feeds.Add(await
this.Feeds.Add(await
this.Feeds.Add(await
this.Feeds.Add(await
this.Feeds.Add(await
this.Feeds.Add(await
this.Feeds.Add(await
this.Feeds.Add(await
this.Feeds.Add(await
this.Feeds.Add(await
this.Feeds.Add(await
this.Feeds.Add(await
feed1);
feed2);
feed3);
feed4);
feed5);
feed6);
feed7);
feed8);
feed9);
feed10);
feed11);
feed12);
feed13);
feed14);
}
private async Task<FeedData> GetFeedAsync(string feedUriString)
{
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 the feed and copy the data you want into the FeedData
and FeedItem classes.
FeedData feedData = new FeedData();
if (feed.Title != null && feed.Title.Text != null)
{
feedData.Title = feed.Title.Text;
}
if (feed.Subtitle != null && feed.Subtitle.Text != null)
{
feedData.Description = feed.Subtitle.Text;
}
if (feed.Items != null && feed.Items.Count > 0)
{
// 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();
if (item.Title != null && item.Title.Text != null)
{
feedItem.Title = item.Title.Text;
}
if (item.PublishedDate != null)
{
feedItem.PubDate = item.PublishedDate.DateTime;
}
if (item.Authors != null && item.Authors.Count > 0)
{
feedItem.Author = item.Authors[0].Name.ToString();
}
// Handle the differences between RSS and Atom feeds.
if (feed.SourceFormat == SyndicationFormat.Atom10)
{
if (item.Content != null && item.Content.Text != null)
{
feedItem.Content = item.Content.Text;
}
if (item.Id != null)
{
feedItem.Link = new Uri("http://windowsteamblog.com" +
item.Id);
}
}
else if (feed.SourceFormat == SyndicationFormat.Rss20)
{
if (item.Summary != null && item.Summary.Text != null)
{
feedItem.Content = item.Summary.Text;
}
if (item.Links != null && item.Links.Count > 0)
{
feedItem.Link = item.Links[0].Uri;
}
}
feedData.Items.Add(feedItem);
}
}
return feedData;
}
catch (Exception)
{
return null;
}
}
// Returns the feed that has the specified title.
public static FeedData GetFeed(string title)
{
// Simple linear search is acceptable for small data sets
var _feedDataSource = App.Current.Resources["feedDataSource"] as
FeedDataSource;
var matches = _feedDataSource.Feeds.Where((feed) =>
feed.Title.Equals(title));
if (matches.Count() == 1) return matches.First();
return null;
}
// Returns the post that has the specified title.
public static FeedItem GetItem(string uniqueId)
{
// Simple linear search is acceptable for small data sets
var _feedDataSource = App.Current.Resources["feedDataSource"] as
FeedDataSource;
var _feeds = _feedDataSource.Feeds;
var matches = _feedDataSource.Feeds.SelectMany(group =>
group.Items).Where((item) => item.Title.Equals(uniqueId));
if (matches.Count() == 1) return matches.First();
return null;
}
}
}
Click Build > Build solution to make sure the solution builds without error.
data that you want to show. If there's no Atom feed, use the RSS feed. When each blog feed is
returned, you add it to the FeedDataSource.Feeds collection.
To do this using synchronous methods, your code might look like this. Here,
the GetFeed method returns a FeedDataobject. When the FeedData is returned, it's added
to the Feeds collection.
C#
VB
this.Feeds.Add(await feed1);
the call to GetFeedAsync is made, and a Task<FeedData> is returned. Then the next line of
code is executed (to getfeed2), but feed1 is not added to the Feeds collection until
the FeedData object is actually passed to theTask<FeedData> that's waiting for it. We come
back to this shortly. Now let's look at what happens in the GetFeedAsyncmethod.
You specify the return type of GetFeedAsync as Task<FeedData>. This tells the compiler to
generate a Task that represents the FeedData object that the method retrieves.
C#
VB
{
// 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();
if (item.Title != null && item.Title.Text != null)
{
feedItem.Title = item.Title.Text;
}
if (item.PublishedDate != null)
{
feedItem.PubDate = item.PublishedDate.DateTime;
}
if (item.Authors != null && item.Authors.Count > 0)
{
feedItem.Author = item.Authors[0].Name.ToString();
}
// Handle the differences between RSS and Atom feeds.
if (feed.SourceFormat == SyndicationFormat.Atom10)
{
if (item.Content != null && item.Content.Text != null)
{
feedItem.Content = item.Content.Text;
}
if (item.Id != null)
{
feedItem.Link = new Uri("http://windowsteamblog.com" + item.Id);
}
}
else if (feed.SourceFormat == SyndicationFormat.Rss20)
{
if (item.Summary != null && item.Summary.Text != null)
{
feedItem.Content = item.Summary.Text;
}
if (item.Links != null && item.Links.Count > 0)
{
feedItem.Link = item.Links[0].Uri;
}
}
feedData.Items.Add(feedItem);
}
}
return feedData;
When the code gets to the return statement, it's not actually returning in the sense that a
synchronous method returns. Remember that the method returned to the caller immediately
after the "await" statement. It returned aTask<FeedData> to represent the eventual result of
the method. Here, you finally get the result. The line return feedData;, gives
the FeedData object that is the result of the method to the Task<FeedData> that is waiting
for it.
The Task was awaited at this line in the GetFeedsAsync method.
C#
VB
this.Feeds.Add(await feed1);
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.
To use the data in the app, you create an instance of the data source as a resource in
App.xaml. You name the instancefeedDataSource.
To add a resource to an app
Double-click App.xaml in Solution Explorer. The file opens in the XAML editor.
Here's the complete XAML for the Application.Resources section after you add the new
resource.
XAML
<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"/>
</ResourceDictionary.MergedDictionaries>
<local:FeedDataSource x:Key="feedDataSource"/>
</ResourceDictionary>
</Application.Resources>
To retrieve the feeds, you add code to the OnLaunched method override in the
App.xaml.cs/vb file. This method is executed each time a user launches the app.
Here, you add the async keyword to the method declaration because you use
the await keyword inside the method. Because the app requires an active internet connection
to download feeds, you use the NetworkInformation class to check for a connection. If the
app is connected, you download the feeds; otherwise, you notify the user. You add code to get
the app's instance of FeedDataSource and check to see if it already contains feeds. If it
doesn't, you call theFeedDataSource.GetFeedsAsync method to retrieve the feeds.
To retrieve the feeds
Double-click App.xaml.cs/vb in Solution Explorer. The file opens in the code editor.
Add this code to the OnLaunched method, immediately after the instantiation of the
new Frame, rootFrame = New Frame().
C#
VB
{
// Create a Frame to act as the navigation context and navigate to the first
page
rootFrame = new Frame();
// Add this code after "rootFrame = new Frame();"
var connectionProfile =
Windows.Networking.Connectivity.NetworkInformation.GetInternetConnectionProfile();
if (connectionProfile != null)
{
FeedDataSource feedDataSource =
(FeedDataSource)App.Current.Resources["feedDataSource"];
if (feedDataSource != null)
{
if (feedDataSource.Feeds.Count == 0)
{
await feedDataSource.GetFeedsAsync();
}
}
}
else
{
var messageDialog = new Windows.UI.Popups.MessageDialog("An
internet connection is needed to download feeds. Please check your connection and
restart the app.");
var result = messageDialog.ShowAsync();
}
if (args.PreviousExecutionState == ApplicationExecutionState.Terminated)
{
//TODO: Load state from previously suspended application
}
// Place the frame in the current Window
Window.Current.Content = rootFrame;
}
if (rootFrame.Content == null)
{
// When the navigation stack isn't restored navigate to the first page,
// configuring the new page by passing required information as a navigation
// parameter
if (!rootFrame.Navigate(typeof(ItemsPage), args.Arguments))
{
throw new Exception("Failed to create initial page");
}
}
// Ensure the current window is active
Window.Current.Activate();
}
You can build and run the app in debugging mode to make sure it builds and retrieves the
feeds without error. If there are no errors, the app runs, but only shows a black screen. If there
are errors, Visual Studio shows info about the error. To learn more about running apps in Visual
Studio, see Running Windows Store apps from Visual Studio.
To run the app in debugging mode
Press F5.
To stop debugging:
1.
2.
Press Shift+F5.
Page templates
Fortunately, you don't have to create each page from a blank template. Visual Studio
Express 2012 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
Items Page
Split Page
Basic Page
An empty page that can adapt to different orientations and views, and has
a title and back button.
Blank Page
You use the Items Page template to show the list of Windows team blogs. You use the Split
Page template to show the posts for each blog, and the text of the selected post. You use
the Basic Page template for the detail page.
To add pages to the app
Select Project > Add New Item. The Add New Item dialog opens.
Here's the Add New Item dialog.
Under Visual C# or Visual Basic in the left pane, pick the Windows Store template
type.
In the center pane, select the type of page to add to your project. Select the Items
Page template.
Click Add.
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.
The XAML and code behind files for your page are added to the project.
Click Build > Build solution to build the app. The new page will show an error in the
designer until you build the helper classes it depends on.
When you add the page templates to your project and look at the XAML and code behind, it's
apparent that these page templates do a lot of work for you. 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 XAML page
templates for Windows Store 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 theVisualStateManager section. We talk more
about this in the Adapting to different layouts section.
The template pages you use are all derived from the LayoutAwarePage class and can do
much more by default than theBlank Page that's used for the MainPage.xaml in a Blank
app. LayoutAwarePage is an implementation of Page that enables important functionality for
Windows Store app development:
The mapping of application view state to visual state lets the page adapt to different
resolutions, orientations, and views.
The page templates also use styles and templates found in StandardStyles.xaml that apply the
design guidelines for Windows Store apps. You'll use some of these styles as a starting point
and modify copies of them to customize the look of the app.
Navigating to ItemsPage
In the Visual Studio project templates, a Frame named rootFrame is set as the content of the
app window. This Framehosts all the Pages in the app. Let's look at the relevant code in
App.xaml.cs/vb.
C#
VB
// parameter
if (!rootFrame.Navigate(typeof(MainPage), args.Arguments))
{
throw new Exception("Failed to create initial page");
}
}
// Ensure the current window is active
Window.Current.Activate();
}
This code gets an existing Frame if there is one; otherwise, it creates a new one and sets it as
the window's content. It then navigates to MainPage. Because you want the first page in the
app to be ItemsPage, you change the call to theNavigate method and pass in ItemsPage as
the Page to navigate to.
To navigate to ItemsPage
Double-click App.xaml.cs/vb in Solution Explorer. The file opens in the code editor.
if (!rootFrame.Navigate(typeof(ItemsPage), args.Arguments))
{
throw new Exception("Failed to create initial page");
}
Press F5 to build and run the app. Now the ItemsPage is loaded instead of the default
MainPage.
Note The default MainPage.xaml file is no longer needed in this project, and you can
safely delete it.
In the items page, you don't see any content yet because you haven't connected any data to
the UI. You do that now.
Loading ItemsPage
When ItemsPage is loaded, you need to get the app's instance of the data source and hook it
up to the UI. For pages that are derived from LayoutAwarePage, you can hook up your data
to the DefaultViewModel provided by LayoutAwarePage. You do this in
the LoadState method override.
To load data in the items page
VB
FeedDataSource feedDataSource =
(FeedDataSource)App.Current.Resources["feedDataSource"];
if (feedDataSource != null)
{
this.DefaultViewModel["Items"] = feedDataSource.Feeds;
}
Now the ItemsPage is loaded and shows a grid of all the blogs. It looks something like this,
but the items might be arranged differently depending on your screen resolution.
Navigating to SplitPage
When the user picks a blog from the collection, you navigate from the items page to the split
page . To do this navigation, you want the GridView items to respond to a click like a button,
instead of being selected. To make theGridView items clickable, you set
the SelectionMode and IsItemClickEnabled properties as shown here. You then add a
handler for GridView's ItemClick event.
To navigate to SplitPage
In the Properties panel, expand the Common section, then click the down arrow at
the bottom of the section to expand the advanced properties.
Check the box for the IsItemClickEnabled property. This sets the property to true.
).
Find the ItemClick event in the event list. In the text box for the event, type
"ItemView_ItemClick" for the name of the method that handles
the ItemClick event.
Press Enter. The event handler method is created and opened in the code
editor so you can add code that's executed when the event occurs.
Add this code to the ItemView_ItemClick event handler in the code behind
page.
Here, you navigate to the split page and pass the title of the selected feed.
C#
VB
if (e.ClickedItem != null)
{
string title = ((FeedData)e.ClickedItem).Title;
this.Frame.Navigate(typeof(SplitPage), title);
}
).
The itemListView list is shown in place of the grid when the app is Snapped. We talk more
about this in the sectionAdapting to different layouts. For now, you just make the same
changes to the ListView that you made to the GridViewso they have the same behavior.
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 theFrame.GoBack method.
The Navigate(TypeName, Object) method lets you navigate and pass a data object to the
new page. You use this method to pass data between your pages. The first
parameter, typeof(SplitPage), is the Type of the page that you are navigating to. The
second parameter is the data object that you pass to the page you're navigating to. In this
case, you pass the title of the clicked item.
You could pass your custom data objects as navigation parameters, but they won't be persisted
and will even cause an exception when you save the app's session state using
the SuspensionManager class. In order to save the navigation state of the app
using SuspensionManager, you must pass only basic, serializable types as the navigation
parameter. That's why you pass the title of the item, and have a method in
the FeedDataSource class to get the item from the title.
Before you move on to the split page, you need to make one more change to the items page.
The default page title is "My Application". You change this to "Windows Team Blogs".
To change the page title
Under Common in the Properties panel, click the property marker for
the Text property. The property menu opens.
).
Note The property marker is the small box symbol to the right of each property value.
The Text property marker is green to indicate that it's set to a resource.
In the property menu, select Edit Resource.... The Edit Resource dialog opens.
In the Edit Resource dialog, change the value from "My Application" to "Windows
Team Blogs".
Click OK.
In ItemsPage.xaml, the page title is bound to a static resource with the key AppName. The text
in this resource is updated to "Windows Team Blogs", and the XAML now looks like this.
XAML
Loading SplitPage
In the SplitPage.xaml.cs/vb code behind page, you need to do something with the object that
was just passed from the items page. For this, you again override the LoadState method. This
method is already added in the page template code, so you just need to modify it to hook up
your data. The navigationParameter has the data object that was passed from the items
page. You cast this back to a string, and then pass it as the parameter to
the FeedDataSource.GetFeedmethod. You add the returned feed data
to DefaultViewModel with the key Feed, and add the FeedData.Items property
to DefaultViewModel with the key Items.
To load data in the split page
Add this code to the top of the LoadState method, after the "TODO" comments.
Tip Expand the "Page state management" region to see the LoadState method.
C#
VB
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
//
}
}
}
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. You'll
fix that now.
In the Visual Studio page template, the "TODO" comments indicate where you add your data
object to DefaultViewModelwith the key Group.
C#
VB
You can think of a blog feed as a group of blog posts, but it makes the code easier to read if
you use the key Feed in place of Group. Because you used the key Feed instead, you need to
change the binding in the page title to bind to the Feed property instead of Group. You also
make the title span 2 columns so it's not cut off.
To update the page title
Under Layout in the Properties panel, set the ColumnSpan property to "2" and
press Enter.
Note At the default width of the Properties panel, the ColumnSpan property is
shown as Colum....
The XAML is updated as shown here.
XAML
Under Common in the Properties panel, click the property marker for
the Text property. The property menu opens.
Note The Text property marker is orange to indicate that it's set to a binding.
In the property menu, select Create Data Binding.... The Create Data
Binding dialog opens.
In the Create Data Binding dialog, change the value in the Path text box to
"Feed.Title" and click OK.
The XAML for the TextBlock is updated like this.
XAML
Press F5 to build and run the app. Now when you navigate to the split page, the page
title is shown.
In SplitPage.xaml, delete the ScrollViewer named itemDetail and all of its contents.
In the XAML editor, add this XAML in place of the itemDetail ScrollViewer you
deleted.
XAML
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>
The WebView control gives you a way to host HTML data within your app. But if you look at
its Source property, you see that it takes the Uri of the web page to display. Your HTML data is
just a string of HTML. It doesn't have a Uri that you can bind to the Source property. Luckily,
there is a NavigateToString method that you can pass your string of HTML to.
Whenever you use a WebView control to view content that might not be available, handle any
failures that occur.
Here, you handle the NavigationFailed event to show the error message in
the WebView control if the navigation fails.
To handle navigation errors
Select the WebView named contentView that you added in the previous step.
Find the NavigationFailed event in the event list. In the text box for the event, type
"ContentView_NavigationFailed" for the name of the method that handles
the NavigationFailed event.
Press Enter. The event handler method is created and opened in the code editor so you
can add code that's executed when the event occurs.
).
The split page is looking better now, and shows the selected blog post in a more readable
format.
Load DetailPage
Now you add content to the detail page. In DetailPage.xaml, you need to bind the
title TextBlock to the blog post title and add a WebView control to show the blog page.
To update the detail page
Bind the page title TextBlock to the Title property of the selected blog post.
).
Under Common in the Properties panel, click the property marker for
the Text property. The property menu opens.
In the property menu, select Create Data Binding.... The Create Data
Binding dialog opens.
In the Create Data Binding dialog, select Data context in the Binding
type drop-down list.
In the XAML editor, add this XAML after the Grid that has the page title, and before
theVisualStateManager.VisualStateGroups section.
XAML
// Add this code to navigate the web view to the selected blog post.
string itemTitle = (string)navigationParameter;
FeedItem feedItem = FeedDataSource.GetItem(itemTitle);
if (feedItem != null)
{
this.contentView.Navigate(feedItem.Link);
this.DataContext = feedItem;
}
C#
VB
Most of the navigation in the blog reader app happens when the user picks an item in the UI.
But on the split page, you must provide a way for the user to go to the detail view of the blog
post. You could put a button somewhere on the page, but that would distract from the core app
experience, which is reading. Instead, you 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. You can control how and when the app bar is shown and
dismissed by setting the IsSticky and IsOpen properties. You can also respond to the app bar
being opened or dismissed by handling the Opened and Closed events.
To add an app bar in XAML, you assign an AppBar control to
a Page's TopAppBar or BottomAppBar property. You'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. You use these styles as a guide to create a style for your button.
You put your style in the Page.Resources section of SplitPage.xaml, and add
the Page.TopAppBar XAML just after the resources section.
To add an app bar
In the XAML editor, add this XAML in the Page.Resources section near the top of the
page.
This adds the Style resource for the app bar button. We talk more about styles later in
the section Creating a consistent look with styles.
XAML
Page"/>
<Setter Property="Content" Value=""/>
</Style>
<Page.TopAppBar>
<AppBar Padding="10,0,10,0">
<Grid>
<Button HorizontalAlignment="Right"
Style="{StaticResource WebViewAppBarButtonStyle}"/>
</Grid>
</AppBar>
</Page.TopAppBar>
Find the Click event at the top of the event list. In the text box for the event, enter
"ViewDetail_Click" for the name of the method that handles the Click event.
Press Enter. The event handler method is created and opened in the code editor so you
can add code that's executed when the event occurs.
Add this code to the event handler method to handle navigation to the detail page.
).
C#
VB
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 page header to show the app bar, and click
the Show Web View button to navigate to the detail page.
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 the blog reader app,
you use animations to adapt your UI to different layouts and orientations. You take a closer
look at this in the next section, but first, you need to understand how animations work.
To use an animation, you 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.
For example, in the blog reader app, you have a ListView named itemListView. Here's an
animation that changes theVisibility property of itemListView to Visible when
the Storyboard runs.
XAML
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="itemListView"
Storyboard.TargetProperty="Visibility" >
<DiscreteObjectKeyFrame KeyTime="0" Value="Visible"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
<Storyboard x:Name="PopInStoryboard">
<PopInThemeAnimation Storyboard.TargetName="contentViewBorder"
FromHorizontalOffset="400"/>
</Storyboard>
In the code behind page, you 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.
To start an animation storyboard
Press F5 to build and run the app. Navigate to the detail page. Now
the WebView control slides in with the other UI elements when the split page is
loaded.
You want to make the blog reader app look and feel like the Windows team blogs website. You
want your users to have a seamless experience when they move between the website and the
app. The default dark theme for the project doesn't match very well with the Windows team
blogs website. This is most clear on the detail page, where you load the actual blog page into
a WebView, as shown here:
To give the app a consistent appearance that you can update as needed, you use brushes and
styles. A Brush lets you define a look in one place and use it wherever you need it.
A Style lets you set values for a control's properties and reuse those settings across your app.
Before we get into the details, let's look at how you use a brush to set the background color of
the pages in your app. Each page in your app has a root Grid with a Background property set
to define the page's background color. You could set each page's background individually, like
this.
XAML
<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 your pages. You define objects and values as resources to make them reusable. To use an
object or value as a resource, you must set its x:Keyattribute. You use this key to refer to the
resource from your XAML. Here, the background is set to a resource with the
key ApplicationPageBackgroundThemeBrush, which is a system
defined SolidColorBrush.
XAML
XAML
<SolidColorBrush x:Key="WindowsBlogBackgroundBrush"
Color="#FF0A2562"/>
<Style x:Key="WindowsBlogLayoutRootStyle"
TargetType="Panel"
BasedOn="{StaticResource LayoutRootStyle}">
<Setter Property="Background"
Value="{StaticResource
WindowsBlogBackgroundBrush}"/>
</Style>
<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"/>
</ResourceDictionary.MergedDictionaries>
<local:FeedDataSource x:Key="feedDataSource"/>
<SolidColorBrush x:Key="WindowsBlogBackgroundBrush"
Color="#FF0A2562"/>
<Style x:Key="WindowsBlogLayoutRootStyle"
TargetType="Panel"
BasedOn="{StaticResource LayoutRootStyle}">
<Setter Property="Background"
Value="{StaticResource WindowsBlogBackgroundBrush}"/>
</Style>
</ResourceDictionary>
</Application.Resources>
Important Because you based a style on a system style in StandardStyles.xaml,
the ResourceDictionary that includes StandardStyles.xaml has to be declared in the XAML
before your style that's based on it. If it's not, the XAML parser can't find
the LayoutRootStyle that your style is based on.
The line BasedOn="{StaticResource LayoutRootStyle}" tells your new Style to inherit
from LayoutRootStyle any properties that you don't explicitly set. Your new Style is just like
the default style, but with a blue background, and you can use it for all of your pages.
To change the background of each page
Click the property marker next to the Style property to open the menu.
Press F5 to build and run the app, and see the blue pages.
To give the app the look and feel of the Windows team blogs website, you also use custom data
templates in addition toBrushes and Styles. Let's start by using templates to format the list
items in the split page.
<ListView
x:Name="itemListView"
AutomationProperties.AutomationId="ItemsListView"
AutomationProperties.Name="Items"
TabIndex="1"
Grid.Row="1"
Margin="-10,-10,0,0"
Padding="120,0,0,60"
ItemsSource="{Binding Source={StaticResource itemsViewSource}}"
IsSwipeEnabled="False"
SelectionChanged="ItemListView_SelectionChanged"
DisplayMemberPath="Title"/>
When you run the app, the list items look like this. This is closer to what you want to show.
But what you really want is to show the title, author, and published date for each post in the
list. To show more than one property of the data item, you define a template that tells
the ListView exactly how you want the data displayed. The controls for viewing collections of
data items are derived from the ItemsControl class. These controls have
anItemTemplate property that you can assign a DataTemplate to.
The DataTemplate defines how your data looks.
Important You can't use the DisplayMemberPath and an ItemTemplate at the same time.
When you set theItemTemplate property, be sure to remove
the DisplayMemberPath setting.
The default item template is close to what you want to show. Lets use it as the starting point
for your template.
Under Miscellaneous in the Properties panel, click the property marker for
the ItemTemplate property. The property menu opens.
Note The property marker is the small box symbol to the right of each property value.
The ItemTemplateproperty marker is green to indicate that it's set to a resource.
Click OK.
<DataTemplate x:Key="DefaultListItemTemplate">
<Grid Height="110" Margin="6">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Border Background="{StaticResource
ListViewItemPlaceholderBackgroundThemeBrush}"
Width="110" Height="110">
<Image Source="{Binding Image}" Stretch="UniformToFill"
AutomationProperties.Name="{Binding Title}"/>
</Border>
<StackPanel Grid.Column="1" VerticalAlignment="Top"
Margin="10,0,0,0">
<TextBlock Text="{Binding Title}"
Style="{StaticResource TitleTextStyle}"
TextWrapping="NoWrap"/>
Select Project > Add Class. The New Item dialog box opens.
Copy this code into the DateConverter.cs/vb file. Replace any code that's in the file.
C#
VB
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();
}
}
Click Build > Build solution to make sure the solution builds without error.
Before you can use the DateConverter class, you must declare an instance of it in your
XAML. You declare it as an app resource with the key dateConverter in App.xaml. Declaring
it here makes it available for every page in your app to use.
To add the dateConverter app resource
Now you can use the DateConverter in the bindings of the date block you create next. With
the converter added, the binding engine uses your custom DateConverter to change
a DateTime to a string. The string that it returns is formatted the way you want, with only the
day, month, and year.
In App.xaml, you add a ControlTemplate that defines a square block that shows the date. You
define this in App.xaml so you can use it in both ItemsPage.xaml and SplitPage.xaml.
To add a control template to App.xaml
Add this XAML in the ResourceDictionary with your other app specific resources,
after theWindowsBlogLayoutRootStyle resource.
XAML
<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
Replace the XAML for the Border element with this XAML.
XAML
Replace the XAML for the 3 TextBlocks in the StackPanel element with this XAML.
XAML
TextWrapping="Wrap"
MaxHeight="72" Foreground="#FFFE5815" />
<TextBlock Text="{Binding Author}" FontSize="18.667" />
Heres the updated XAML for the data template.
XAML
<DataTemplate x:Key="DefaultListItemTemplate">
<Grid Height="110" Margin="6">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Border Background="#FF6BBD46" Width="110" Height="110">
<ContentControl Template="{StaticResource DateBlockTemplate}" />
</Border>
<StackPanel Grid.Column="1" VerticalAlignment="Top"
Margin="10,0,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>
Important This template is used in the default full screen landscape view. If your screen
resolution is less than 1366 pixels wide, the split page uses the FilledOrNarrow view state,
and you will not see this template in the list view. To see this template, run the app in the
simulator in Visual Studio with a resolution of 1366 x 768 or greater. For more info about
testing the app in the simulator, see Running Windows Store apps from Visual Studio.
To finish styling the split page, you need to change the background color of the app bar and
the color of the selected item in the list view.
To update the app bar background
Add this XAML in the ResourceDictionary after your other app specific resources.
XAML
<SolidColorBrush x:Key="ListViewItemSelectedBackgroundThemeBrush"
Color="#FF465985"/>
<SolidColorBrush
x:Key="ListViewItemSelectedPointerOverBackgroundThemeBrush"
Color="#FF384A72"/>
<SolidColorBrush
x:Key="ListViewItemSelectedPointerOverBorderThemeBrush"
Color="#FF384A72" />
To finish styling the app, you apply similar styles to the items page. In ItemsPage.xaml, you
add these resources to define the look of the grid items in the default view.
To style ItemsPage.xaml
In the XAML editor, add this XAML in the Page.Resources section after
the AppName resource.
XAML
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>
Under Miscellaneous in the Properties panel, click the property marker for
the ItemTemplate property. The property menu opens.
Press F5 to build and run the app. The items page now uses the new template.
With your styles applied, the app fits in with the look and feel of the Windows team blogs
website:
By using styles and basing them on other styles you can quickly define and apply different
looks for your app. In the next section, you combine what you know about animations and
styles to make the app fluidly adapt to various layouts and orientations while its running.
Note In this section, you apply concepts discussed in Part3: Navigation, layout, and views. For
more info about adapting your UI to different views, and tool support that's available, review
Part 3.
Usually, an app is designed to be viewed full screen in the landscape orientation. But a
Windows Store app 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.
Tip To test the app in different orientations and resolutions, you can run it in the simulator. To
run your Windows Store 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 Windows Store 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 the app state to visual states defined in your
XAML. Because the page layout logic is provided for you, you only need to provide the views to
be used for each of the page's visual states.
To transition between different views using XAML, you use the VisualStateManager to define
different VisualStates for your app. Here you have a VisualStateGroup defined in
ItemsPage.xaml. This group has 4 VisualStates
namedFullScreenLandscape, Filled, FullScreenPortrait, and Snapped.
Different VisualStates from the sameVisualStateGroup 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.
XAML
<!-- The entire page respects the narrower 100-pixel margin convention for portrait
-->
<VisualState x:Name="FullScreenPortrait">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="backButton"
Storyboard.TargetProperty="Style">
You use the Snapped state when the user has two apps showing, and your app is the narrower
of the two. In this state, your app is only 320 device-independent pixels (DIPs) wide, so you
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, itemGridView is shown, and itemListView is collapsed. In the Snapped state, you
have 4 animations that collapseitemGridView, show itemListView, and change
the Style of the back button and page title to make them smaller.
XAML
<!-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="itemListView"
Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0" Value="Visible"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="itemGridView"
Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
In the Creating a consistent look with styles section of this tutorial, you created styles and
templates to give the app a custom look. The default landscape view uses these styles and
templates . To keep the custom look in different views, you also need to create custom styles
and templates for those views.
In ItemsPage.xaml, you created a new data template for the grid items. You also need to
provide a new data template for the list items that are shown in Snapped view. You name this
template NarrowListItemTemplate and add it to the resources section of ItemsPage.xaml,
just after the DefaultGridItemTemplate resource.
To add a template for the snapped view
In the XAML editor, add this XAML in the Page.Resources section after
the DefaultGridItemTemplate resource.
XAML
Under Miscellaneous in the Properties panel, click the property marker for
the ItemTemplate property. The property menu opens.
Grid.Row="1"
Visibility="Collapsed"
Margin="0,-10,0,0"
Padding="10,0,0,60"
ItemsSource="{Binding Source={StaticResource itemsViewSource}}"
ItemTemplate="{StaticResource NarrowListItemTemplate}"
SelectionMode="None"
IsSwipeEnabled="false"
IsItemClickEnabled="True"
ItemClick="ItemView_ItemClick"/>
In ItemsPage, you have both a GridView and a ListView, and you apply the templates in the
default XAML. You show the GridView for the default view. When the app is snapped, you
replace the grid with the ListView by using theVisualStateManager to change
the Visibility properties of the two views.
In SplitPage, you use a different way to change the UI when the view changes. You have a
single ListView that you show in all views. To change it's look when the view changes, you use
the VisualStateManager to apply a new template to theListView.
In SplitPage.xaml, you create a similar ListView template thats used in
the Filled and Snapped views, and in theFullScreenLandscape view if the screen width
is less than 1366 DIPs. You also name this templateNarrowListItemTemplate and add it to
the resources section of SplitPage.xaml, just after the DefaultListItemTemplateresource.
To add a narrow template
In the XAML editor, add this XAML in the Page.Resources section after
the DefaultListItemTemplate resource.
XAML
</StackPanel>
</Grid>
</DataTemplate>
To use this data template, you update the visual states where it's used.
To update the visual states
In the XAML for the FilledOrNarrow and Snapped visual states, find the animation
that targets the ItemTemplateproperty of itemListView.
Tip Press Ctrl+F to open the Quick Find box, and search for "Standard80ItemTemplate"
if you have trouble finding it.
<VisualState x:Name="FilledOrNarrow">
<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>
You also replaced the item detail section of the split page with your own detail section that
uses a WebView. Because you made this change, some animations in
the Snapped_Detail visual state target elements that no longer exist. These will cause errors
when the app is snapped, so you need to remove them.
To remove unused animations
XAML
<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>
When you select a blog and navigate to the split page in the snapped view, you expect the list
of blog posts to be shown. Instead, the text of the first blog post is shown because it's selected
by default. To change this behavior, you make sure nothing is selected when you navigate to
the split page in the snapped view.
To unselect the first item
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();
}
}
Add the else clause as shown here. The call MoveCurrentToPosition(-1) makes
the current item not set.
C#
VB
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
{
this.itemsViewSource.View.MoveCurrentToPosition(-1);
}
}
In DetailPage.xaml, you just need to adjust the margin of the WebView in the Snapped view
to use all the available space.
To update DetailPage.xaml
In the XAML for the Snapped visual state, add an animation to change the value of
the Margin property oncontentViewBorder.
XAML
<ObjectAnimationUsingKeyFrames
Storyboard.TargetName="contentViewBorder"
Storyboard.TargetProperty="Margin">
<DiscreteObjectKeyFrame KeyTime="0" Value="20,5,20,20"/>
</ObjectAnimationUsingKeyFrames>
>
Here's the full XAML for the snapped state.
XAML
<!-- The back button and title have different styles when snapped -->
<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="contentViewBorder" Storyboard.TargetProperty="Margin">
<DiscreteObjectKeyFrame KeyTime="0" Value="20,5,20,20"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
Press F5 to build and run the app. Try it in different views and orientations.
Note In this section, you apply concepts discussed in Part 2: Manage app lifecycle and state.
For more info about saving app state, review Part 2.
To conserve system resources, the system automatically suspends (and sometimes terminates)
Windows Store apps that are running in the background. A well-designed app can be
suspended, terminated, and relaunched by the system and seem as though it were running the
entire time. Here, you add code to handle suspending and resuming the app. Fortunately, most
of the infrastructure is provided by the LayoutAwarePage and SuspensionManager classes
in the Visual Studio templates, so you just need to add a bit of code to save and restore
settings.
Add this code to the OnSuspending method, after the "TODO" comment.
In App.xaml.cs/vb, add this code in the OnLaunched method immediately after the
instantiation of the newFrame.
Here, you register the Frame with the SuspensionManager class.
C#
VB
Add this code in the OnLaunched method after the "TODO" comment.
Add this code in the SaveState method after the "TODO" comment.
The SuspensionManager class serializes and saves the pageState dictionary to an
XML file. Data saved in pageStateis saved only for this session. Here, you save the
title of the blog post selected in the list.
C#
VB
In SplitPage.xaml.cs/vb, add this code in the LoadState method after the third
"TODO" comment.
C#
VB
Did you get stuck, or do you want to check your work? If so, see Blog reader complete code.
What's next
You learned how to use built-in page templates from Visual Studio Express 2012 for Windows 8
to build a complete multi-page app, and how to navigate and pass data between the pages.
You learned how to use styles and templates to make your app fit the personality of the
Windows team blogs website. You also learned how to use theme animations, an app bar, and
a splash screen to make your app fit the personality of Windows 8. Finally, you learned how to
adapt your 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
Windows Store apps.
Roadmap for Windows Store apps using C# or Visual Basic.