Using Pivot and Panorama Controlsaz12722.vo.msecnd.net/wp7trainingcourse1-3/Labs/Using...application...
Transcript of Using Pivot and Panorama Controlsaz12722.vo.msecnd.net/wp7trainingcourse1-3/Labs/Using...application...
Hands-On Lab
Using Pivot and Panorama Controls
Lab version: 1.0.0
Last updated: 12/8/2010
Push Notifications Hands-on Lab
Page | 2
CONTENTS
Overview .......................................................................................................................................... 3
Exercise 1: Introduction to Navigation in Windows Phone ............................................................. 7
Task 1 – Creating a Windows Phone 7 Application ................................................................. 7
Task 2 – Implementing Digg Page Functionality .................................................................... 20
Task 3 – Implementing Trends Page Functionality ................................................................ 32
Exercise 2: Introduction to Pivot Control ...................................................................................... 43
Task 1 – Adding Twitter Page ................................................................................................ 43
Task 2 – Implementing Twitter Page Functionality ............................................................... 48
Exercise 3: Introduction to Panorama Control .............................................................................. 58
Task 1 – Adding Blog Page ..................................................................................................... 58
Task 2 – Implementing Blog Page Functionality .................................................................... 62
Summary........................................................................................................................................ 77
Push Notifications Hands-on Lab
Page | 3
Overview
Developing applications for Windows® Phone 7 presents new challenges.
How do we manage to navigate between different applications without losing precious battery
power, but still maintain a consistent user experience with our application?
How do we manage to present large quantities of information to the user when screen size is
significantly smaller than our regular PC displays?
All these issues are addressed and in this lab you will become familiar with the solutions.
The lab walks you through creating a fully featured Microsoft Silverlight® for Windows Phone
application, named Wazup. The Wazup application will let you search stories using Digg, check
out the tweets (Twitter messages) for the top 10 active trends on Twitter and read posts from
the Windows Phone Developer Blog.
While developing the Wazup application, you will learn how to use the new controls for
presenting information, Pivot and Panorama, and learn about the new navigation model in
Windows Phone 7.
Audience: The lab assumes knowledge of XAML and familiarity with Silverlight 3.
Objectives
Upon completing the lab you will:
Be familiar with most of the common controls in a Windows Phone 7 application,
including: TextBlock, TextBox, Button, HyperlinkButton, and ListBox
Be familiar with controls specific to a Windows Phone 7 application, including:
ApplicationBar, ApplicationBarIconButton, PhoneApplicationFrame, and
PhoneApplicationPage
Have a high level understand of the overall "Applications" navigation model, and
specifically the page and frame navigation model within Windows Phone 7 applications.
Understand how to handle application state information in order to support navigating
away from the application and back
Have learned about the new controls available for Windows Phone applications,
including Pivot and Panorama
Understand what a Pivot control is, how to use it, and when
Understand what a Panorama control is, how to use it, and when
Have created a Windows Phone 7 Silverlight application that uses both Pivot and
Panorama controls to present content to the user in various ways
Push Notifications Hands-on Lab
Page | 4
Prerequisites
The following are required to complete this hands-on lab:
Microsoft Visual Studio® 2010 Express for Windows Phone or Microsoft Visual Studio
2010
Windows Phone Developer Tools
Note: All of these Tools can be downloaded together in a single package from
http://developer.windowsphone.com.
Setup
For convenience, much of the code used in this hands-on lab is available as Visual Studio code
snippets. To install the code snippets:
1. Run the .vsi installer located in the lab's Source\Setup folder.
Note: If you have issues running the code snippets installer you can install the code
snippets manually by copying all the .snippet files located in the
Source\Setup\CodeSnippets folder of the lab to the following folder:
My Documents\Visual Studio 2010\Code Snippets\Visual C#\My Code Snippets
Push Notifications Hands-on Lab
Page | 5
Using the Code Snippets
With code snippets, you have all the code you need at your fingertips. The lab document will tell
you exactly when you can use them. For example,
Figure 1
Using Visual Studio code snippets to insert code into your project
To add this code snippet in Visual Studio, you simply place the cursor where you would like the
code to be inserted, start typing the snippet name (without spaces or hyphens), watch as
IntelliSense picks up the snippet name, and then press the Tab key twice when the snippet you
want is selected. The code will be inserted at the cursor location.
Figure 2
Start typing the snippet name
Figure 3
Push Notifications Hands-on Lab
Page | 6
Press Tab to select the highlighted snippet
Figure 4
Press Tab again to expand the snippet
To insert a code snippet using the mouse rather than the keyboard, right-click where you want
to insert the code snippet, select Insert Snippet followed by My Code Snippets and then pick
the relevant snippet from the list.
To learn more about Visual Studio IntelliSense Code Snippets, including how to create your own,
see http://msdn.microsoft.com/en-us/library/ms165392.aspx.
Exercises
This hands-on lab comprises the following exercises:
1. Introduction to Navigation in Windows Phone
2. Introduction to Pivot Control
3. Introduction to Panorama Control
Estimated time to complete this lab: 90 minutes.
Push Notifications Hands-on Lab
Page | 7
Exercise 1: Introduction to Navigation
in Windows Phone
In this exercise we will build an application named Wazup. At the end of this exercise the Wazup
application will allow us to search stories on Digg and see the active Trends on Twitter.
The exercise will include the following tasks:
Create basic Windows Phone 7 Application placeholder pages
Implement Digg search page functionality
Implement Trends page functionality
We will use the Microsoft Visual Studio 2010 Express for Windows Phone development
environment, and will deploy to the Windows Phone Emulator for debugging. The solution we
will be working with is based upon the Silverlight for Windows Phone Application template.
During development, we will add Silverlight for Windows Phone project specific items: Windows
Phone Portrait Page, Windows Phone Pivot Page and Windows Phone Panorama Page.
Note: The steps in this hands-on lab illustrate procedures using Microsoft Visual Studio 2010
Express for Windows Phone, but they are equally applicable to Microsoft Visual Studio 2010
with the Windows Phone Developer Tools. Instructions that refer generically to Visual Studio
apply to both products.
Task 1 – Creating a Windows Phone 7 Application
In this task we will create the basic Windows Phone 7 project for the Wazup application.
At the end of this task the Wazup application will have two pages in addition to the main page.
The first page is a placeholder for the Digg functionality and the second page is a placeholder for
the trends functionality. We will add functionality to these two pages in the following two tasks.
During this task we will see how to work with the Windows Phone Application Bar and how to
navigate between pages in a Windows Phone application.
Since this is rather a big application, we’ll start with adding some code, art and XAML that we’ve
prepare in advance to allow you to fully focus on the core Windows Phone fundamentals.
1. Open Microsoft Visual Studio 2010 Express for Windows Phone from Start | All
Programs | Microsoft Visual Studio 2010 Express | Microsoft Visual Studio 2010
Express for Windows Phone.
Push Notifications Hands-on Lab
Page | 8
Visual Studio 2010: Open Visual Studio 2010 from Start | All Programs | Microsoft
Visual Studio 2010.
2. Add a new project of type Windows Phone Application, named Wazup.
Figure 5
Adding new Windows Phone Application project
Push Notifications Hands-on Lab
Page | 9
3. Add the files WazupAppIcon.png and WazupStartIcon.png from the Assets folder of
this lab located in Source\Assets. These icons will be our application icon in the
application list (or Windows Phone Start screen). To do this, right-click on Wazup
(project name) and select AddExisting Item…:
Figure 6
Add Existing Item to project
4. Select the two files added, and change the:
Build Action property to Content
Copy to Output Directory property to Copy if newer
Push Notifications Hands-on Lab
Page | 10
5. Open the file WMAppManifest.xml, located in the project Properties folder.
Figure 7
Location of WMAppManifest.xml
6. Find the element Deployment | App | IconPath and change its value from
ApplicationIcon.png to WazupAppIcon.png. This icon is the tile icon representing the
application in the application list.
7. Find the element Deployment | App | Tokens | PrimaryToken | TemplateType5 |
BackgroundImageURI and change its value from Background.png to
WazupStartIcon.png. This image is used when the application is pinned to the Start
screen.
8. Add the file Styles.xaml from the Assets folder of this lab located in Source\Assets. To
do this, right-click on Wazup (project name) and Select Add Existing Item…
9. Open the file App.xaml and add the following code into the resources section:
(Code Snippet – Using Pivot and Panorama – Ex 1 Task 1 Step 9 – Styles.xaml)
XAML
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Styles.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
Push Notifications Hands-on Lab
Page | 11
10. Add a folder to the project, named Resources. To do this right-click on Wazup (project
name) and select AddNew Folder.
Figure 8
Add new folder to the project
11. Add all the files that are located in this lab’s Source\Assets\Resources folder to the
new Wazup project Resources folder. You’ve just added few images that we’ll use and
reference from our XAML and code during the lab.
Select all the files in the Resources folder and change the Build Action property to Content.
Push Notifications Hands-on Lab
Page | 12
12. This will cause the images to be added to the XAP file instead of as resources inside the
DLL file.
Figure 9
Change Build Action for added resources
Push Notifications Hands-on Lab
Page | 13
13. Add another folder to the project, named Views.
14. Add a new item to the Views folder by right-clicking the Views folder and selecting
Add->New Item…
Figure 10
Add new item to the project
Push Notifications Hands-on Lab
Page | 14
15. Select Windows Phone Portrait Page and name it DiggPage.xaml
Figure 11
Add new Windows Phone Portrait Page
16. Add another Windows Phone Portrait Page named TrendsPage.xaml
17. Open MainPage.xaml
Most of the prep work is behind us. Now it is time to define our application’s UI. We’ll
start by defining the main page UI.
18. Locate the LayoutRoot grid and replace the content with the following code. This code
adds 3 buttons to the main page. Each button will link to a different page in the
application.
(Code Snippet – Using Pivot and Panorama – Ex 1 Task 1 Step 18 – MainPage
LayoutRoot)
XAML
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
Push Notifications Hands-on Lab
Page | 15
</Grid.RowDefinitions>
<StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,16,12,27">
<TextBlock x:Name="ApplicationTitle" Text="WAZUP"
Style="{StaticResource PhoneTextNormalStyle}"/>
<TextBlock x:Name="PageTitle" Text="choose & search"
Style="{StaticResource PhoneTextTitle1Style}" FontSize="60"/>
</StackPanel>
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<StackPanel>
<Button x:Name="ButtonDigg" Content="Digg"
Click="ButtonDigg_Click" />
<Button x:Name="ButtonTwitter" Content="Twitter Trends"
Click="ButtonTwitter_Click" />
<Button x:Name="ButtonBlog" Content="Windows Phone Blog"
Click="ButtonBlog_Click" />
<Image Height="180" Source="/Resources/Logos.png"
Stretch="None" Margin="0,40,0,0" HorizontalAlignment="Center"/>
</StackPanel>
</Grid>
</Grid>
There is a small section at the bottom of the Windows Phone Application Bar screen
that we can use for adding up to 4 button icons. We can also add menu items to the
application bar that will display when the user presses the "three dots" (…) icon.
19. To add buttons to the phone application bar, instead of the commented use of PhoneApplicationPage.ApplicationBar, add the following after the LayoutRoot grid element: (Code Snippet – Using Pivot and Panorama – Ex 1 Task 1 Step 19 – MainPage
ApplicatioBar)
XAML
<phone:PhoneApplicationPage.ApplicationBar>
<shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">
<shell:ApplicationBarIconButton x:Name="AppbarButtonDigg"
IconUri="/Resources/App.Digg.png" Text="Digg"
Click="AppbarButtonDigg_Click" />
<shell:ApplicationBarIconButton x:Name="AppbarButtonTwitter"
IconUri="/Resources/App.Twitter.png" Text="Twitter"
Click="AppbarButtonTwitter_Click" />
<shell:ApplicationBarIconButton x:Name="AppbarButtonBlog"
IconUri="/Resources/App.Blog.png" Text="Blog"
Click="AppbarButtonBlog_Click" />
Push Notifications Hands-on Lab
Page | 16
</shell:ApplicationBar>
</phone:PhoneApplicationPage.ApplicationBar>
20. Add a new class named Navigation by right-clicking Wazup (project name) and selecting
AddClass… This class will provide a helper function to help us navigate between the
application pages.
Now we will implement the Navigation class. First we define an enum that contains
an entry for each page in our final application:
The Navigation class provides an extension method of PhoneApplicationPage,
named GoToPage, which allows us to navigate to a requested page
The GoToPage function uses a property of PhoneApplicationPage, named
NavigationService to trigger the navigation
21. Replace the content of the Navigation.cs file with the following code
(Code Snippet – Using Pivot And Panorama – Ex 1 Task 1 Step 21 – Navigation.cs)
C#
using System;
using Microsoft.Phone.Controls;
namespace Wazup
{
public enum ApplicationPages
{
Digg,
Trends,
Twitter,
Blog
}
public static class Navigation
{
/// <summary>
/// Goes to page.
/// </summary>
/// <param name="applicationPage">The application page.</param>
public static void GoToPage(this PhoneApplicationPage
phoneApplicationPage, ApplicationPages applicationPage)
{
switch (applicationPage)
{
case ApplicationPages.Digg:
Push Notifications Hands-on Lab
Page | 17
phoneApplicationPage.NavigationService.Navigate(new
Uri("/Views/DiggPage.xaml", UriKind.Relative));
break;
case ApplicationPages.Trends:
phoneApplicationPage.NavigationService.Navigate(new
Uri("/Views/TrendsPage.xaml", UriKind.Relative));
break;
case ApplicationPages.Twitter:
phoneApplicationPage.NavigationService.Navigate(new
Uri("/Views/TwitterPage.xaml", UriKind.Relative));
break;
case ApplicationPages.Blog:
phoneApplicationPage.NavigationService.Navigate(new
Uri("/Views/BlogPage.xaml", UriKind.Relative));
break;
}
}
}
}
22. Open the file MainPage.xaml.cs
23. Add the following event handlers below the constructor of the MainPage class. In this
step we handle the button Click events for both the buttons we have added and the
application bar buttons. In each event handler we use the Navigation class to go the
correct page. Note that the blog page doesn't exist yet; it will be created later in this
lab.
(Code Snippet – Using Pivot and Panorama – Ex 1 Task 1 Step 23 – MainPage Event
Handler)
C#
/// <summary>
/// Handles the Click event of the ButtonDigg control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/>
instance containing the event data.</param>
private void ButtonDigg_Click(object sender, RoutedEventArgs e)
{
this.GoToPage(ApplicationPages.Digg);
}
Push Notifications Hands-on Lab
Page | 18
/// <summary>
/// Handles the Click event of the ButtonTwitter control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/>
instance containing the event data.</param>
private void ButtonTwitter_Click(object sender, RoutedEventArgs e)
{
this.GoToPage(ApplicationPages.Trends);
}
/// <summary>
/// Handles the Click event of the ButtonBlog control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/>
instance containing the event data.</param>
private void ButtonBlog_Click(object sender, RoutedEventArgs e)
{
this.GoToPage(ApplicationPages.Blog);
}
#region Appbar handlers
/// <summary>
/// Handles the Click event of the AppbarButtonDigg control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="System.EventArgs"/> instance
containing the event data.</param>
private void AppbarButtonDigg_Click(object sender, EventArgs e)
{
this.GoToPage(ApplicationPages.Digg);
}
/// <summary>
/// Handles the Click event of the AppbarButtonTwitter control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="System.EventArgs"/> instance
containing the event data.</param>
private void AppbarButtonTwitter_Click(object sender, EventArgs e)
{
this.GoToPage(ApplicationPages.Trends);
}
/// <summary>
/// Handles the Click event of the AppbarButtonBlog control.
Push Notifications Hands-on Lab
Page | 19
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="System.EventArgs"/> instance
containing the event data.</param>
private void AppbarButtonBlog_Click(object sender, EventArgs e)
{
this.GoToPage(ApplicationPages.Blog);
}
#endregion
24. Compile and run the application
25. At this stage the application looks like the following:
Figure 12
Opening screen of Wazup application
Push Notifications Hands-on Lab
Page | 20
26. Stop the debugging and return to the code. This step concludes the current task.
Task 2 – Implementing Digg Page Functionality
In this task we will implement the functionality of the Digg search page in the Wazup
application. At the end of this task the Wazup application will have a working Digg search page.
During this task we will create the Digg page UI using some basic controls like TextBox,
TextBlock, HyperlinkButton and ListBox. In addition, we will see how to save and load page state
when navigating away from the application.
1. Add references to the System.Xml.Linq and System.Runtime.Serialization assemblies
(from .NET tab). These assemblies are needed for the Digg service utility class that we
will add shortly.
Figure 13
Add references to System.Xml.Linq and System.Runtime.Serialization
2. Now we will add the utility classes used to work with Digg service. In order to do that,
add a folder named Services to the project.
Push Notifications Hands-on Lab
Page | 21
3. Add to the Services folder the files: DiggService.cs and DiggStory.cs which are located
in Source\Assets\Services folder of this lab. These classes handle the web requests
for you, getting the relevant date from Digg.
Figure 14
Solution Explorer after adding the Digg service files into the Services folder
4. Add a folder named Helpers to the project. In this folder we will store several helper
controls that we will use.
5. Inside the folder Helpers, add a folder named ProgressBar
6. Add to the ProgressBar folder all the files from the Source\Assets\Helpers\ProgressBar
folder of this lab. The following files should be added: BooleanToVisibilityConverter.cs,
ProgressBarWithText.xaml, ProgressBarWithText.xaml.cs and
RelativeAnimatingContentControl.cs. These files encapsulate a progress bar that have
similar UI of the one used by Windows Phone.
Figure 15
Solution Explorer after adding ProgressBar files
Push Notifications Hands-on Lab
Page | 22
7. Open the file DiggPage.xaml
8. Add the following XML namespace to the phone:PhoneApplicationPage element next
to the other XML namespaces definitions:
XAML
xmlns:localHelpers="clr-namespace:Wazup.Helpers"
9. Set the DataContext property of the DiggPage to be the DiggPage itself by adding the
following line to the phone:PhoneApplicationPage element:
XAML
DataContext="{Binding RelativeSource={RelativeSource Self}}"
Now we will define the UI for the Digg page.
10. Locate the LayoutRoot grid and replace the content with the following code. The Digg
page has a TextBox that contains the text to be searched, a search Button, a TextBlock
that presents the last searched text, a ListBox that will present the search results and a
ProgressBarWithText control that will show status information while searching.
Note that the ProgressBarWithText control is a custom control that we have added to
the project.
The ListBox control is used to present a list of items. The ListBox items are set via the
property ItemsSource which is bound to a collection of DiggStory items. In order to
transform each DiggStory object into a valid UI we use the ItemTemplate property to
define the name of the DataTemplate that will do the transformation. The
DataTemplate will be defined in the next step.
(Code Snippet – Using Pivot and Panorama – Ex 1 Task 2 Step 11 – DiggPage
LayoutRoot)
XAML
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid x:Name="ContentPanel" Margin="12,0,12,0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
Push Notifications Hands-on Lab
Page | 23
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBox x:Name="TextBoxSearch" Grid.Column="0" Text="{Binding
SearchText, Mode=TwoWay}" />
<Button x:Name="ButtonSearch" Grid.Column="1"
Click="ButtonSearch_Click" VerticalAlignment="Top" Padding="0"
Style="{StaticResource ButtonGoStyle}" />
<TextBlock x:Name="TextBlock" Grid.Row="1" Grid.ColumnSpan="2"
Text="{Binding LastSearchText}" Margin="18,0,0,5"
HorizontalAlignment="Left" FontSize="24" Height="45" />
<Path Grid.ColumnSpan="2" Data="M0,80 L448,80" Height="1"
Margin="0,2,12,4" Grid.Row="1" Stretch="Fill" Stroke="#B2FFFFFF"
UseLayoutRounding="False" VerticalAlignment="Bottom"/>
<ListBox Grid.Row="2" Grid.ColumnSpan="2" ItemsSource="{Binding
DiggSearchResults}" ItemTemplate="{StaticResource
DiggSearchResultTemplate}" />
<localHelpers:ProgressBarWithText Grid.Row="2"
Grid.ColumnSpan="2" Text="Searching..." ShowProgress="{Binding
IsSearching}" />
</Grid>
</Grid>
Now we define a DataTemplate that will transform each DiggStory object into a
presentable UI that contains the Digg story.
11. Add the following code into DiggPage resources section after the end of the
PhoneApplicationPage element.
(Code Snippet – Using Pivot and Panorama – Ex 1 Task 2 Step 12 – DiggPage Resources)
XAML
<phone:PhoneApplicationPage.Resources>
<DataTemplate x:Key="DiggSearchResultTemplate">
<Grid Margin="0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<StackPanel Background="#FF27580A"
HorizontalAlignment="Left" Height="35" Margin="0,7,0,0"
VerticalAlignment="Top" Orientation="Horizontal">
Push Notifications Hands-on Lab
Page | 24
<TextBlock Text="{Binding Diggs}" Foreground="White"
Margin="5,2,5,3" HorizontalAlignment="Left" VerticalAlignment="Bottom"
/>
<TextBlock TextWrapping="Wrap" Foreground="White"
Text="diggs" d:LayoutOverrides="Width" HorizontalAlignment="Left"
VerticalAlignment="Bottom" FontSize="16" Margin="0,2,5,3"/>
</StackPanel>
<HyperlinkButton Grid.Column="0" Content="{Binding Title}"
NavigateUri="{Binding Link}" TargetName="_blank" FontSize="29.333"
Foreground="#FFFFC425" HorizontalAlignment="Left" Style="{StaticResource
WrappedHyperlinkButtonStyle}" HorizontalContentAlignment="Left"
Grid.Row="1" Margin="0,0,0,3" />
<TextBlock Grid.Row="2" Grid.ColumnSpan="2" Text="{Binding
Description}" Foreground="White" TextWrapping="Wrap" Margin="0,0,12,35"
HorizontalAlignment="Left" />
</Grid>
</DataTemplate>
</phone:PhoneApplicationPage.Resources>
12. We now add buttons to the application bar in the Digg page. After the LayoutRoot grid ends, instead of the commented use of PhoneApplicationPage.ApplicationBar, add the following code: (Code Snippet – Using Pivot and Panorama – Ex 1 Task 2 Step 13 – DiggPage
ApplicationBar)
XAML
<phone:PhoneApplicationPage.ApplicationBar>
<shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">
<shell:ApplicationBarIconButton x:Name="AppbarButtonDigg"
IconUri="/Resources/App.Digg.png" Text="Digg"
Click="AppbarButtonDigg_Click" />
<shell:ApplicationBarIconButton x:Name="AppbarButtonTwitter"
IconUri="/Resources/App.Twitter.png" Text="Twitter"
Click="AppbarButtonTwitter_Click" />
<shell:ApplicationBarIconButton x:Name="AppbarButtonBlog"
IconUri="/Resources/App.Blog.png" Text="Blog"
Click="AppbarButtonBlog_Click" />
</shell:ApplicationBar>
</phone:PhoneApplicationPage.ApplicationBar>
13. Add a new class named StateManager by right-clicking Wazup (project name) and
selecting AddClass… This class will provide helper functions for saving and loading
state information when the application exits.
Push Notifications Hands-on Lab
Page | 25
In order to save battery power Windows Phone 7 doesn't allow applications to run
simultaneously. This means that if you open a new application while your application
is running (for example, Web Browser), it will cause your application to exit. If you
then return to your application by clicking Back, your application will open in a new
instance (that is, an entirely different process). The application will be opened in the
last opened page, since this information is saved by the operating system, but if the
page had any information stored in its variables, that information will be completely
erased, since this is a new instance of the page. In order to overcome this situation
you need to:
Save variables information into a special state object when the page is being
navigated away from (that is, the user is leaving the page)
Load the variables information from the special state object when the page is
being navigated back to (that is, the user is returning to the page)
Do this in the two functions OnNavigateTo and OnNavigateFrom.
14. To prepare a helper class named StateManager that will help us implement these two
functions, replace the content of the StateManager.cs file with the following code
snippet:
(Code Snippet – Using Pivot and Panorama – Ex 1 Task 2 Step 15 – StateManager.cs)
C#
using System;
using Microsoft.Phone.Controls;
namespace Wazup
{
/// <summary>
/// State Manager
/// </summary>
public static class StateManager
{
/// <summary>
/// Saves a key-value pair into the state object
/// </summary>
/// <param name="phoneApplicationPage">The phone application
page.</param>
/// <param name="key">The key.</param>
/// <param name="value">The value.</param>
public static void SaveState(this PhoneApplicationPage
phoneApplicationPage, string key, object value)
{
if (phoneApplicationPage.State.ContainsKey(key))
{
Push Notifications Hands-on Lab
Page | 26
phoneApplicationPage.State.Remove(key);
}
phoneApplicationPage.State.Add(key, value);
}
/// <summary>
/// Loads value from the state object, according to the key.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="phoneApplicationPage">The phone application
page.</param>
/// <param name="key">The key.</param>
/// <returns>The loaded value</returns>
public static T LoadState<T>(this PhoneApplicationPage
phoneApplicationPage, string key)
where T : class
{
if (phoneApplicationPage.State.ContainsKey(key))
{
return (T)phoneApplicationPage.State[key];
}
return default(T);
}
}
}
15. Open the file DiggPage.xaml.cs
16. Replace the using section of DiggPage class with the following code snippet:
(Code Snippet – Using Pivot and Panorama – Ex 1 Task 2 Step 17 – DiggPage Using)
C#
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Windows;
using Microsoft.Phone.Controls;
using Wazup.Services;
17. Add to the DiggPage class the following dependency properties:
SearchText of type string – used to save the current search text
LastSearchText of type string – used to save the last search text
Push Notifications Hands-on Lab
Page | 27
DiggSearchResults of type ObservableCollection<DiggStory> - used to save the
collection of digg search results
IsSearching of type bool – used to indicate whether search is currently in
progress
Use the following code snippet:
(Code Snippet – Using Pivot and Panorama – Ex 1 Task 2 Step 17 – DiggPage
Properties)
C#
#region SearchText
/// <summary>
/// SearchText Dependency Property
/// </summary>
public static readonly DependencyProperty SearchTextProperty =
DependencyProperty.Register("SearchText", typeof(string),
typeof(DiggPage),
new PropertyMetadata((string)""));
/// <summary>
/// Gets or sets the SearchText property. This dependency
property
/// indicates the text to be searched.
/// </summary>
public string SearchText
{
get { return (string)GetValue(SearchTextProperty); }
set { SetValue(SearchTextProperty, value); }
}
#endregion
#region LastSearchText
/// <summary>
/// LastSearchText Dependency Property
/// </summary>
public static readonly DependencyProperty LastSearchTextProperty
=
DependencyProperty.Register("LastSearchText", typeof(string),
typeof(DiggPage),
new PropertyMetadata((string)""));
/// <summary>
/// Gets or sets the LastSearchText property. This dependency
property
Push Notifications Hands-on Lab
Page | 28
/// indicates the last searched text.
/// </summary>
public string LastSearchText
{
get { return (string)GetValue(LastSearchTextProperty); }
set { SetValue(LastSearchTextProperty, value); }
}
#endregion
#region DiggSearchResults
/// <summary>
/// DiggSearchResults Dependency Property
/// </summary>
public static readonly DependencyProperty
DiggSearchResultsProperty =
DependencyProperty.Register("DiggSearchResults",
typeof(ObservableCollection<DiggStory>), typeof(DiggPage),
new
PropertyMetadata((ObservableCollection<DiggStory>)null));
/// <summary>
/// Gets or sets the DiggSearchResults property. This dependency
property
/// indicates digg search results.
/// </summary>
public ObservableCollection<DiggStory> DiggSearchResults
{
get { return
(ObservableCollection<DiggStory>)GetValue(DiggSearchResultsProper
ty); }
set { SetValue(DiggSearchResultsProperty, value); }
}
#endregion
#region IsSearching
/// <summary>
/// IsSearching Dependency Property
/// </summary>
public static readonly DependencyProperty IsSearchingProperty =
DependencyProperty.Register("IsSearching", typeof(bool),
typeof(DiggPage),
new PropertyMetadata((bool)false));
/// <summary>
Push Notifications Hands-on Lab
Page | 29
/// Gets or sets the IsSearching property. This dependency
property
/// indicates whether we are currently searching.
/// </summary>
public bool IsSearching
{
get { return (bool)GetValue(IsSearchingProperty); }
set { SetValue(IsSearchingProperty, value); }
}
#endregion
18. Add a handler for the Click event of the ButtonSearch control. In this handler we
perform initiate a search in Digg service. We do this by calling the asynchronous
method DiggService.Search which accepts the search text, a callback function to call
when the search is complete and a callback function to call if the search failed, for
example, if the Digg service is not available. If the search completes successfully, we add
the results to the DiggSearchResults collection which is bound to the ListBox.
(Code Snippet – Using Pivot and Panorama – Ex 1 Task 2 Step 19 – DiggPage
ButtonSearch Click)
C#
/// <summary>
/// Handles the Click event of the ButtonSearch control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/>
instance containing the event data.</param>
private void ButtonSearch_Click(object sender, RoutedEventArgs e)
{
if (string.IsNullOrEmpty(SearchText))
{
return;
}
IsSearching = true;
DiggService.Search(SearchText,
delegate(IEnumerable<DiggStory> diggSearchResults)
{
IsSearching = false;
LastSearchText = SearchText;
DiggSearchResults = new ObservableCollection<DiggStory>();
Push Notifications Hands-on Lab
Page | 30
foreach (DiggStory diggSearchResult in diggSearchResults)
{
DiggSearchResults.Add(diggSearchResult);
}
},
delegate(string searchText, Exception exception)
{
IsSearching = false;
LastSearchText = string.Format("Error while searching {0}.",
searchText);
System.Diagnostics.Debug.WriteLine(exception);
});
}
19. Override the functions OnNavigateTo and OnNavigateFrom of the page. Use the
StateManager class to save and load page state when the current page is changing.
(Code Snippet – Using Pivot and Panorama – Ex 1 Task 2 Step 20 – DiggPage Navigation)
C#
private const string SearchTextKey = "SearchTextKey";
private const string LastSearchTextKey = "LastSearchTextKey";
private const string DiggSearchResultsKey = "DiggSearchResultsKey";
protected override void
OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
{
this.SaveState(SearchTextKey, SearchText);
this.SaveState(LastSearchTextKey, LastSearchText);
this.SaveState(DiggSearchResultsKey, DiggSearchResults);
}
protected override void
OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
SearchText = this.LoadState<string>(SearchTextKey);
LastSearchText = this.LoadState<string>(LastSearchTextKey);
DiggSearchResults =
this.LoadState<ObservableCollection<DiggStory>>(DiggSearchResultsKey);
}
20. Add the following event handlers in the DiggPage class. In this step we handle the
application bar buttons. In each event handler we use the Navigation class to go to the
correct page. Note that the blog page doesn't exist yet; we we will create it later in this
lab.
Push Notifications Hands-on Lab
Page | 31
(Code Snippet – Using Pivot and Panorama – Ex 1 Task 2 Step 21 – DiggPage Event
Handler)
C#
#region Appbar handlers
/// <summary>
/// Handles the Click event of the AppbarButtonDigg control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="System.EventArgs"/> instance
containing the event data.</param>
private void AppbarButtonDigg_Click(object sender, EventArgs e)
{
SearchText = string.Empty;
LastSearchText = string.Empty;
DiggSearchResults = null;
}
/// <summary>
/// Handles the Click event of the AppbarButtonTwitter control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="System.EventArgs"/> instance
containing the event data.</param>
private void AppbarButtonTwitter_Click(object sender, EventArgs e)
{
this.GoToPage(ApplicationPages.Trends);
}
/// <summary>
/// Handles the Click event of the AppbarButtonBlog control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="System.EventArgs"/> instance
containing the event data.</param>
private void AppbarButtonBlog_Click(object sender, EventArgs e)
{
this.GoToPage(ApplicationPages.Blog);
}
#endregion
21. Compile and run the application. If you get an error while searching Digg it might be
because the Digg search service is down. You can check the status of the service at:
http://developers.digg.com/known_issues
Push Notifications Hands-on Lab
Page | 32
22. At this stage the Digg search page should work and look like the following:
Figure 16
Digg search page with results
Stop the debugging and return to the code.
23. This step concludes the current task.
Task 3 – Implementing Trends Page Functionality
In this task we will implement the functionality of the Trends page in the Wazup application. At
the end of this task the Wazup application will have a working Trends page.
Push Notifications Hands-on Lab
Page | 33
During this task we will create the Trends page UI using some basic controls and handle the
state of the Trends page when navigating away from the application.
1. Add reference to the System.Servicemodel.Web assembly (from the .NET tab). This assembly is needed for the Twitter service utility class that we will add shortly.
Figure 17
Add reference to System.Servicemodel.Web
Now we will add the utility classes used to work with Trends service. Add to the Services
folder the files: TwitterService.cs, Trend.cs and Twit.cs which are located in
Push Notifications Hands-on Lab
Page | 34
Source\Assets\Services folder of this lab.
Figure 18
Solution Explorer after adding trends service files into the Services folder
2. Since the trends service provider limits its access using an application key, you must
create one for your lab. To do this, go to the site http://api.whatthetrend.com/; select
"Request API key," which you can find on the right side of the display. Fill out the
small form to get a free application key that you can use for the lab. Copy the
generated key to the constant Wazup_WhatTheTrendApplicationKey that is defined
in the file TwitterService.cs.
Do not use the default key since it probably will not work.
Push Notifications Hands-on Lab
Page | 35
Figure 19
Requesting an application key from WhatTheTrend.com
3. Open the file TrendsPage.xaml
4. Add the following XML namespace to the phone:PhoneApplicationPage element next
to the other XML namespaces definitions:
XAML
xmlns:localHelpers="clr-namespace:Wazup.Helpers"
5. Set the DataContext property of the TrendsPage to be the TrendsPage itself. Do this by
adding the following line to the phone:PhoneApplicationPage element:
XAML
DataContext="{Binding RelativeSource={RelativeSource Self}}"
6. Now we will define the UI for the trends page. Locate the LayoutRoot grid and replace
the content with the following code.The trends page has a ListBox that will present the
list of top 10 Twitter trends, a ProgressBarWithText control that will show status
information while loading trends and a TextBlock that presents an attribution for the
trends service supplier (whatthetrend.com). The ListBox items are set via the property
ItemsSource which is bound to a collection of Trend items. In order to transform each
Trend object into a valid UI we use the ItemTemplate property to define the name of
the DataTemplate that will do the transformation. We will define the DataTemplate in
the next step.
(Code Snippet – Using Pivot and Panorama – Ex 1 Task 3 Step 7 – TrendsPage
LayoutRoot)
XAML
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,16,0,27">
<TextBlock x:Name="ApplicationTitle" Text="TWITTER TRENDS"
Style="{StaticResource PhoneTextNormalStyle}"/>
<TextBlock x:Name="PageTitle" Text="top trends" Margin="9,-
8,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
Push Notifications Hands-on Lab
Page | 36
</StackPanel>
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ListBox ItemsSource="{Binding Trends}"
ItemTemplate="{StaticResource TrendTemplate}" FontSize="32" />
<localHelpers:ProgressBarWithText Text="Loading Trends..."
ShowProgress="{Binding IsTrendsLoading}" />
<TextBlock HorizontalAlignment="Left" TextWrapping="Wrap"
Text="Trends by whatthetrend.com" VerticalAlignment="Top" Grid.Row="1"
Foreground="#99FFFFFF" Margin="0,0,0,5"/>
</Grid>
</Grid>
7. Now we define a DataTemplate that will transform each Trend object into a
presentable UI that contains the trend. Add the following code into TrendsPage
resources section.
(Code Snippet – Using Pivot and Panorama – Ex 1 Task 3 Step 8 – TrendsPage Resources)
XAML
<phone:PhoneApplicationPage.Resources>
<DataTemplate x:Key="TrendTemplate">
<StackPanel Orientation="Horizontal">
<TextBlock Text="#" FontSize="32" MinHeight="72"
VerticalAlignment="Center" HorizontalAlignment="Left"
Foreground="#FFFFC425" Margin="0,0,1,0" />
<TextBlock Text="{Binding trend_index}" FontSize="32"
MinHeight="72" VerticalAlignment="Center" HorizontalAlignment="Left"
Foreground="#FFFFC425" Margin="0,0,5,0" />
<TextBlock x:Name="TextBlockTrend" Text="{Binding name}"
MouseLeftButtonUp="TextBlockTrend_MouseLeftButtonUp" FontSize="32"
MinHeight="72" VerticalAlignment="Center" HorizontalAlignment="Left" />
</StackPanel>
</DataTemplate>
</phone:PhoneApplicationPage.Resources>
8. We now add buttons to the application bar in the trends page. After the LayoutRoot
grid ends, instead of the commented use of PhoneApplicationPage.ApplicationBar, add
the following code:
Push Notifications Hands-on Lab
Page | 37
(Code Snippet – Using Pivot and Panorama – Ex 1 Task 3 Step 8 – TrendsPage
ApplicationBar)
XAML
<phone:PhoneApplicationPage.ApplicationBar>
<shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">
<shell:ApplicationBarIconButton x:Name="AppbarButtonDigg"
IconUri="/Resources/App.Digg.png" Text="Digg"
Click="AppbarButtonDigg_Click" />
<shell:ApplicationBarIconButton x:Name="AppbarButtonTwitter"
IconUri="/Resources/App.Twitter.png" Text="Twitter"
Click="AppbarButtonTwitter_Click" />
<shell:ApplicationBarIconButton x:Name="AppbarButtonBlog"
IconUri="/Resources/App.Blog.png" Text="Blog"
Click="AppbarButtonBlog_Click" />
</shell:ApplicationBar>
</phone:PhoneApplicationPage.ApplicationBar>
9. Open the file TrendsPage.xaml.cs
10. Replace the using section of the TrendsPage class with the following code snippet:
(Code Snippet – Using Pivot and Panorama – Ex 1 Task 3 Step 11 – TrendsPage Using)
C#
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using Microsoft.Phone.Controls;
using Wazup.Services;
11. Add to the TrendsPage class the following dependency properties:
Trends of type ObservableCollection<Trend> - used to save the collection of
Twitter trends
IsTrendsLoading of type bool – used to indicate whether trends loading is
currently in progress
Use the following code snippet:
(Code Snippet – Using Pivot and Panorama – Ex 1 Task 3 Step 7 – TrendsPage Properties)
C#
Push Notifications Hands-on Lab
Page | 38
#region Trends
/// <summary>
/// Trends Dependency Property
/// </summary>
public static readonly DependencyProperty TrendsProperty =
DependencyProperty.Register("Trends",
typeof(ObservableCollection<Trend>), typeof(TrendsPage),
new PropertyMetadata((ObservableCollection<Trend>)null));
/// <summary>
/// Gets or sets the Trends property. This dependency property
/// indicates the current twitter trends.
/// </summary>
public ObservableCollection<Trend> Trends
{
get { return (ObservableCollection<Trend>)GetValue(TrendsProperty);
}
set { SetValue(TrendsProperty, value); }
}
#endregion
#region IsTrendsLoading
/// <summary>
/// IsTrendsLoading Dependency Property
/// </summary>
public static readonly DependencyProperty IsTrendsLoadingProperty =
DependencyProperty.Register("IsTrendsLoading", typeof(bool),
typeof(TrendsPage),
new PropertyMetadata((bool)false));
/// <summary>
/// Gets or sets the IsTrendsLoading property. This dependency property
/// indicates whether we are currently loading trends.
/// </summary>
public bool IsTrendsLoading
{
get { return (bool)GetValue(IsTrendsLoadingProperty); }
set { SetValue(IsTrendsLoadingProperty, value); }
}
#endregion
Push Notifications Hands-on Lab
Page | 39
12. Add a handler for the MouseLeftButtonUp event of the TextBlockTrend control.
Currently we will leave it empty. We will add functionality as the lab progress.
(Code Snippet – Using Pivot and Panorama – Ex 1 Task 3 Step 13 – TrendsPage
TextBlockTrend MouseLeftButtonUp Empty)
C#
/// <summary>
/// Handles the MouseLeftButtonUp event of the TextBlockTrend control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see
cref="System.Windows.Input.MouseButtonEventArgs"/> instance containing
the event data.</param>
private void TextBlockTrend_MouseLeftButtonUp(object sender,
MouseButtonEventArgs e)
{
}
13. Override the functions OnNavigateTo and OnNavigateFrom of the page. Use the
StateManager class to save and load page state when the current page is changing. In
the function OnNavigateTo we need to check whether we loaded Trends from the state
object – which implies the user have already seen this page and navigated from him. If
we didn't, then it is a sign that we loaded from a new instance this page, and so need to
get the Trends information from the trends service. We do this by calling the
asynchronous method TwitterService.GetTrends, which accepts a callback function to
call when the trends loading is complete and a callback function to call if the trends
loading failed, for example, the trends service is not available. If the trends loading
completed successfully we add the results to the Trends collection which is bound to
the ListBox.
(Code Snippet – Using Pivot and Panorama – Ex 1 Task 3 Step 14 – TrendsPage State
Handling)
C#
private const string TrendsKey = "TrendsKey";
protected override void
OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
{
this.SaveState(TrendsKey, Trends);
}
Push Notifications Hands-on Lab
Page | 40
protected override void
OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
Trends = this.LoadState<ObservableCollection<Trend>>(TrendsKey);
if (Trends == null)
{
IsTrendsLoading = true;
TwitterService.GetTrends(
delegate(IEnumerable<Trend> trends)
{
IsTrendsLoading = false;
Trends = new ObservableCollection<Trend>();
foreach (Trend trend in trends)
{
Trends.Add(trend);
}
},
delegate(Exception exception)
{
IsTrendsLoading = false;
System.Diagnostics.Debug.WriteLine(exception);
});
}
}
Add the following event handlers in the TrendsPage class.
14. In this step we handle the application bar buttons. In each event handler we use the
Navigation class to go the correct page. Note that the blog page doesn't exist yet; it will
be created later in this lab.
(Code Snippet – Using Pivot and Panorama – Ex 1 Task 3 Step 15 – TrendsPage Event
Handler)
C#
#region Appbar handlers
/// <summary>
/// Handles the Click event of the AppbarButtonDigg control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="System.EventArgs"/> instance
containing the event data.</param>
private void AppbarButtonDigg_Click(object sender, EventArgs e)
Push Notifications Hands-on Lab
Page | 41
{
this.GoToPage(ApplicationPages.Digg);
}
/// <summary>
/// Handles the Click event of the AppbarButtonTwitter control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="System.EventArgs"/> instance
containing the event data.</param>
private void AppbarButtonTwitter_Click(object sender, EventArgs e)
{
}
/// <summary>
/// Handles the Click event of the AppbarButtonBlog control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="System.EventArgs"/> instance
containing the event data.</param>
private void AppbarButtonBlog_Click(object sender, EventArgs e)
{
this.GoToPage(ApplicationPages.Blog);
}
#endregion
15. Compile and run the application.
At this stage the trends page should work and look like the following:
Push Notifications Hands-on Lab
Page | 42
Figure 20
Trends page showing Twitter trends
16. Stop the debugging and return to the code. This step concludes the exercise.
During this exercise you learned how to create an application with several pages using
common controls, how to navigate between the pages and how to save and load page
state information.
Note: The complete solution for this exercise is provided at the following location:
Source\Ex1-Navigation\End.
Push Notifications Hands-on Lab
Page | 43
Exercise 2: Introduction to Pivot
Control
In this exercise we continue to develop the Wazup application. At the end of this exercise the
Wazup application will allow us to select a trend from the trends page and see a list of tweets
(Twitter messages) relevant to this trend, in addition to what we've accomplished in the
previous exercise.
The exercise will include the following tasks:
Add Twitter page that uses a Pivot control
Implement Twitter page functionality
Task 1 – Adding Twitter Page
In this task we will add a placeholder page for Twitter functionality. The page will contain a pivot
control that can display several pages of information. We will use the pivot control on the next
task to show a page of tweets for each trend in the trends list.
During this task we will see how to add a new page that contains a pivot control.
1. Open Microsoft Visual Studio 2010 Express for Windows Phone from Start | All
Programs | Microsoft Visual Studio 2010 Express | Microsoft Visual Studio 2010
Express for Windows Phone.
Visual Studio 2010: Open Visual Studio 2010 from Start | All Programs | Microsoft
Visual Studio 2010.
2. Open the Begin.sln starter solution from the Source\Ex2-Pivot\Begin folder of this lab.
Alternatively, you can continue working on the solution created in previous exercise.
3. Add a folder to the project, named Themes. To do this right-click on Wazup (project
name) and select AddNew Folder
Push Notifications Hands-on Lab
Page | 44
4. Add generic.xaml file to the Themes folder located in the Source\Assets\Themes
folder in this lab.
Figure 21
Solution Explorer after adding the file generic.xaml to Themes folder
5. Inside the folder Helpers, add a folder named LinkLabel.
6. Add to the LinkLabel folder all the files from the Source\Assets\Helpers\LinkLabel
folder of this lab. These should include Link.cs, LinkClickedEventArgs.cs,
LinkCollection.cs, LinkLabel.cs and LinkMatchMethod.cs, which we are going to use in
this exercise.
Figure 22
Solution Explorer after adding LinkLabel files
Push Notifications Hands-on Lab
Page | 45
7. Inside the folder Helpers, add a folder named WrapPanel.
8. Add to the WrapPanel folder all the files from the Source\Assets\Helpers\WrapPanel
folder of this lab. These should include LengthConverter.cs, NumericExtensions.cs,
OrientedSize.cs, TypeConverters.cs and WrapPanel.cs.
Figure 23
Solution Explorer after adding WrapPanel files
9. Add a new item to the Views folder by right-clicking the Views folder and selecting
AddNew Item…
Push Notifications Hands-on Lab
Page | 46
Figure 24
Add new item to the project
10. Select Windows Phone Pivot Page and name it TwitterPage.xaml.
Figure 25
Add new Windows Phone Pivot Page
11. Open the file TwitterPage.xaml.cs.
12. Replace the using section of the TwitterPage class with the following code snippet:
(Code Snippet – Using Pivot and Panorama – Ex 2 Task 1 Step12 – TwitterPage Using)
C#
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;
using Microsoft.Phone.Controls;
using Wazup.Services;
Push Notifications Hands-on Lab
Page | 47
13. Add to the TwitterPage class two public static variables that will be used to pass
information between the TrendsPage and TwitterPage. Use the following code snippet:
(Code Snippet – Using Pivot and Panorama – Ex 2 Task 1 Step12 – TwitterPage Static
Variables)
C#
/// <summary>
/// Used to transfer the Trends collection between the trends page and
the twitter page
/// </summary>
public static ObservableCollection<Trend> Global_Trends;
/// <summary>
/// Used to transfer the current Trend between the trends page and the
twitter page
/// </summary>
public static Trend Global_CurrentTrend;
14. Open the file TrendsPage.xaml.cs.
15. Now we want to open the Twitter page when a trend gets clicked on the trends page.To
do that we will go back and implement the MouseLeftButtonUp event handler of the
TextBlockTrend control. Our implementation will pass the trends collection and
selected trend to the Twitter page by using static variables on the Twitter page. Replace
the TextBlockTrend event handler of the MouseLeftButtonUp event with the following
code snippet:
(Code Snippet – Using Pivot and Panorama – Ex 2 Task 1 Step15 – TwitterPage
TextBlockTrend MouseLeftButtonUp Implementation)
C#
/// <summary>
/// Handles the MouseLeftButtonUp event of the TextBlockTrend control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see
cref="System.Windows.Input.MouseButtonEventArgs"/> instance containing
the event data.</param>
private void TextBlockTrend_MouseLeftButtonUp(object sender,
MouseButtonEventArgs e)
{
Trend trend = (sender as TextBlock).DataContext as Trend;
Push Notifications Hands-on Lab
Page | 48
this.GoToPage(ApplicationPages.Twitter);
TwitterPage.Global_Trends = Trends;
TwitterPage.Global_CurrentTrend = trend;
}
16. Compile and run the application.
17. Stop the debugging and return to the code. This step concludes the current task.
Task 2 – Implementing Twitter Page Functionality
In this task we will implement the functionality of the Twitter page in the Wazup application. At
the end of this task the Wazup application will have a working Twitter page.
During this task we will use the Pivot control to show multiple pages of data, one page for each
trend in the trends list. Each page in the pivot control will show a list of tweets relevant to the
page trend. We will also see how to handle changes in the pivot selected page. When the pivot
selected page will change we will load the current twits for the new page.
1. Open the file TwitterPage.xaml
2. Add the following XML namespaces to the phone:PhoneApplicationPage element next
to the other XML namespaces definitions:
XAML
xmlns:localHelpers="clr-namespace:Wazup.Helpers"
xmlns:localWindowsControls="clr-namespace:System.Windows.Controls"
3. Set the DataContext property of the TwitterPage to be the TwitterPage itself. Do this by
adding the following line to the phone:PhoneApplicationPage element:
XAML
DataContext="{Binding RelativeSource={RelativeSource Self}}"
4. Now we will define the UI for the Twitter page. Locate the LayoutRoot grid and replace
the content with the code below. The Twitter page contains two controls: a Pivot
control that will show a different page for each trend and a ProgressBarWithText
control that will show status information while loading tweets. The Pivot control is used
to show multiple pages which are easily navigated by flicking or panning horizontally on
the page. When you reach the last page of the pivot you can flick once more to return
to the first page. The Pivot control items are set via the property ItemsSource which is
bound to a collection of Trend items. To transform each Trend object into a valid UI
Push Notifications Hands-on Lab
Page | 49
page, we use the ItemTemplate property, which defines the name of the DataTemplate
that will perform the transformation. We can also control the look of the page header
using the HeaderTemplate property to define the name of the DataTemplate that will
perform the transformation between a Trend object and the UI for the header. We will
define the DataTemplate in the next step.
(Code Snippet – Using Pivot and Panorama – Ex 2 Task 2 Step 4 – TwitterPage
LayoutRoot)
XAML
<Grid x:Name="LayoutRoot" Background="Transparent">
<controls:Pivot
x:Name="PivotControl"
Title="Wazup"
ItemsSource="{Binding Trends}"
HeaderTemplate="{StaticResource TrendHeaderTemplate}"
ItemTemplate="{StaticResource TrendTemplate}"
SelectionChanged="PivotControl_SelectionChanged"
>
</controls:Pivot>
<localHelpers:ProgressBarWithText Text="Loading Tweets..."
ShowProgress="{Binding IsTwitsLoading}" />
</Grid>
5. Here we define three data templates:
TrendHeaderTemplate defines a DataTemplate that transforms a Trend object
into a TextBlock that contains the trend name. This template is used as the
header for each item in the Pivot control.
TrendTemplate defines a DataTemplate that transforms a Trend object into
the page UI for each item in the Pivot control. The page UI consists of a single
ListBox control that contains the Twitter messages related to the trend. The UI
for the ListBox items is defined by the third data template named
TwitTemplate.
TwitTemplate defines a DataTemplate that transforms a Twit object into a
proper UI presentation of a Twitter message that includes an Image for
showing the profile image of the tweet author, a LinkLabel control that shows
the tweet text with clickable links and two TextBlocks that show the tweet
author name and tweet creation time.
Add the following code into the TwitterPage resources section.
(Code Snippet – Using Pivot and Panorama – Ex 2 Task 2 Step 5 – TwitterPage
Resources)
Push Notifications Hands-on Lab
Page | 50
XAML
<phone:PhoneApplicationPage.Resources>
<DataTemplate x:Key="TrendHeaderTemplate">
<TextBlock Text="{Binding name}" />
</DataTemplate>
<DataTemplate x:Key="TwitTemplate">
<Grid Margin="0,0,12,25">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Image Grid.RowSpan="2" Width="60" Height="60"
Source="{Binding profile_image_url}" VerticalAlignment="Top"
Margin="0,5,7,0" />
<localWindowsControls:LinkLabel
Grid.Row="0"
Grid.Column="1"
Text="{Binding DecodedText}"
LinkMatchMethod="ByUriAndLinkPattern"
LinkStyle="{StaticResource WrappedHyperlinkButtonStyle}"
VerticalAlignment="Top" Foreground="White" Background="Black"
FontSize="20"
/>
<StackPanel Grid.Row="1" Grid.Column="1"
Orientation="Horizontal">
<TextBlock Text="{Binding from_user}"
Foreground="#99FFFFFF" VerticalAlignment="Top" />
<TextBlock Text=", " Foreground="#99FFFFFF"
VerticalAlignment="Top" />
<TextBlock Text="{Binding created_at}"
Foreground="#99FFFFFF" VerticalAlignment="Top" />
</StackPanel>
</Grid>
</DataTemplate>
<DataTemplate x:Key="TrendTemplate">
<ListBox ItemsSource="{Binding Twits}"
ItemTemplate="{StaticResource TwitTemplate}" />
</DataTemplate>
</phone:PhoneApplicationPage.Resources>
Push Notifications Hands-on Lab
Page | 51
6. We now add buttons to the application bar in the Twitter page. After the LayoutRoot
grid ends, instead of the commented use of PhoneApplicationPage.ApplicationBar, add
the following code:
(Code Snippet – Using Pivot and Panorama – Ex 2 Task 2 Step 6 – TwitterPage
ApplicationBar)
XAML
<phone:PhoneApplicationPage.ApplicationBar>
<shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">
<shell:ApplicationBarIconButton x:Name="AppbarButtonDigg"
IconUri="/Resources/App.Digg.png" Text="Digg"
Click="AppbarButtonDigg_Click" />
<shell:ApplicationBarIconButton x:Name="AppbarButtonTwitter"
IconUri="/Resources/App.Twitter.png" Text="Twitter"
Click="AppbarButtonTwitter_Click" />
<shell:ApplicationBarIconButton x:Name="AppbarButtonBlog"
IconUri="/Resources/App.Blog.png" Text="Blog"
Click="AppbarButtonBlog_Click" />
</shell:ApplicationBar>
</phone:PhoneApplicationPage.ApplicationBar>
7. Open the file TwitterPage.xaml.cs
8. Add the following dependency properties to the TwitterPage class:
Trends of type ObservableCollection<Trend> - used to save the collection of
Twitter trends
CurrentTrend of type Trend – used to save the currently selected trend
Note: We implement an OnCurrentTrendChanged function in order to set the
PivotControl.SelectedItem property with the current trend. The reason why
we don't do this by binding the SelectedItem property to the CurrentTrend
property is due to a bug in the current version of the Pivot control for setting a
new page that is "far" from the current page (not a neighbor) that might result
in an exception. Our code works around this.
a. IsTwitsLoading of type bool – used to indicate whether Twitter messages
loading is currently in progress
Use the following code snippet:
(Code Snippet – Using Pivot and Panorama – Ex 2 Task 2 Step 4 – TwitterPage
Properties)
Push Notifications Hands-on Lab
Page | 52
C#
#region Trends
/// <summary>
/// Trends Dependency Property
/// </summary>
public static readonly DependencyProperty TrendsProperty =
DependencyProperty.Register("Trends",
typeof(ObservableCollection<Trend>), typeof(TwitterPage),
new PropertyMetadata((ObservableCollection<Trend>)null));
/// <summary>
/// Gets or sets the Trends property. This dependency property
/// indicates what are the current twitter trends.
/// </summary>
public ObservableCollection<Trend> Trends
{
get { return (ObservableCollection<Trend>)GetValue(TrendsProperty);
}
set { SetValue(TrendsProperty, value); }
}
#endregion
#region CurrentTrend
/// <summary>
/// CurrentTrend Dependency Property
/// </summary>
public static readonly DependencyProperty CurrentTrendProperty =
DependencyProperty.Register("CurrentTrend", typeof(Trend),
typeof(TwitterPage),
new PropertyMetadata((Trend)null,
new PropertyChangedCallback(OnCurrentTrendChanged)));
/// <summary>
/// Gets or sets the CurrentTrend property. This dependency property
/// indicates what is the current trend.
/// </summary>
public Trend CurrentTrend
{
get { return (Trend)GetValue(CurrentTrendProperty); }
set { SetValue(CurrentTrendProperty, value); }
}
/// <summary>
/// Handles changes to the CurrentTrend property.
Push Notifications Hands-on Lab
Page | 53
/// </summary>
private static void OnCurrentTrendChanged(DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
TwitterPage target = (TwitterPage)d;
Trend oldCurrentTrend = (Trend)e.OldValue;
Trend newCurrentTrend = target.CurrentTrend;
target.OnCurrentTrendChanged(oldCurrentTrend, newCurrentTrend);
}
/// <summary>
/// Provides derived classes an opportunity to handle changes to the
CurrentTrend property.
/// </summary>
protected virtual void OnCurrentTrendChanged(Trend oldCurrentTrend,
Trend newCurrentTrend)
{
if (newCurrentTrend != oldCurrentTrend)
{
Dispatcher.BeginInvoke((Action)delegate
{
PivotControl.SelectedItem = newCurrentTrend;
});
}
}
#endregion
#region IsTwitsLoading
/// <summary>
/// IsTwitsLoading Dependency Property
/// </summary>
public static readonly DependencyProperty IsTwitsLoadingProperty =
DependencyProperty.Register("IsTwitsLoading", typeof(bool),
typeof(TwitterPage),
new PropertyMetadata((bool)false));
/// <summary>
/// Gets or sets the IsTwitsLoading property. This dependency property
/// indicates whether we are currently loading twits.
/// </summary>
public bool IsTwitsLoading
{
get { return (bool)GetValue(IsTwitsLoadingProperty); }
set { SetValue(IsTwitsLoadingProperty, value); }
}
#endregion
Push Notifications Hands-on Lab
Page | 54
9. Add a handler for the SelectionChanged event of the Pivot control. Here we respond to
a page change in the Pivot control by searching for Twitter messages relevant to the
new selected page. We do this by calling the asynchronous method
TwitterService.Search that accepts a search text, a callback function to call when the
Twitter search is complete, and a callback function to call if the Twitter search failed, for
example, the Twitter service is not available. If the Twitter search completed
successfully, we add the tweets to the Twits collection of the current trend, which is
bound to the page ListBox.
(Code Snippet – Using Pivot and Panorama – Ex 2 Task 2 Step 9 – TwitterPage
PivotControl SelectionChanged)
C#
private void PivotControl_SelectionChanged(object sender,
SelectionChangedEventArgs e)
{
if (e.AddedItems.Count == 0)
{
return;
}
Trend selectedTrend = e.AddedItems[0] as Trend;
if ((selectedTrend.Twits == null) || (selectedTrend.Twits.Count ==
0))
{
IsTwitsLoading = true;
}
TwitterService.Search(selectedTrend.name,
delegate(IEnumerable<Twit> twits)
{
IsTwitsLoading = false;
selectedTrend.Twits = new ObservableCollection<Twit>();
foreach (Twit twit in twits)
{
selectedTrend.Twits.Add(twit);
}
},
delegate(Exception exception)
{
IsTwitsLoading = false;
});
}
Push Notifications Hands-on Lab
Page | 55
Override the functions OnNavigateTo and OnNavigateFrom of the page. Use the StateManager
class to save and load page state when the current page is changing. In the function
OnNavigateTo, check whether the Global_Trends variable has a value; if it has, we know that
the Twitter page was loaded after clicking a trend in the trends page.
10. Otherwise, we assume that the Twitter page got loaded due to a return to the
application via the Back button, in which case we load the Trends information from the
state object.
(Code Snippet – Using Pivot and Panorama – Ex 2 Task 2 Step 10 – TwitterPage State
Handling)
C#
private const string TrendsKey = "TrendsKey";
private const string CurrentTrendKey = "CurrentTrendKey";
protected override void
OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
{
this.SaveState(TrendsKey, Trends);
this.SaveState(CurrentTrendKey, CurrentTrend);
}
protected override void
OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
if (Global_Trends != null)
{
// get data from trends page, if we got from trends page
Trends = Global_Trends;
CurrentTrend = Global_CurrentTrend;
}
else
{
// get data from state object
Trends = this.LoadState<ObservableCollection<Trend>>(TrendsKey);
CurrentTrend = this.LoadState<Trend>(CurrentTrendKey);
}
}
11. Add the following event handlers in the TwitterPage class. In this step we handle the
application bar buttons. In each event handler we use the Navigation class to go to the
correct page. Note that the blog page doesn't exist yet; it will be created later in this
lab.
Push Notifications Hands-on Lab
Page | 56
(Code Snippet – Using Pivot and Panorama – Ex 2 Task 2 Step 4 – TwitterPage Event
Handler)
C#
#region Appbar handlers
/// <summary>
/// Handles the Click event of the AppbarButtonDigg control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="System.EventArgs"/> instance
containing the event data.</param>
private void AppbarButtonDigg_Click(object sender, EventArgs e)
{
this.GoToPage(ApplicationPages.Digg);
}
/// <summary>
/// Handles the Click event of the AppbarButtonTwitter control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="System.EventArgs"/> instance
containing the event data.</param>
private void AppbarButtonTwitter_Click(object sender, EventArgs e)
{
NavigationService.GoBack();
//this.GoToPage(ApplicationPages.Trends);
}
/// <summary>
/// Handles the Click event of the AppbarButtonBlog control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="System.EventArgs"/> instance
containing the event data.</param>
private void AppbarButtonBlog_Click(object sender, EventArgs e)
{
this.GoToPage(ApplicationPages.Blog);
}
#endregion
12. Compile and run the application.
At this stage the Twitter page should work and look like the following:
Push Notifications Hands-on Lab
Page | 57
Figure 26
Twitter page showing tweets for a specific trend
13. Stop the debugging and return to the code. This step concludes the exercise.
During this exercise you learned how to use the Pivot control to show multiple pages.
Note: The complete solution for this exercise is provided at the following location:
Source\Ex2-Pivot\End.
Push Notifications Hands-on Lab
Page | 58
Exercise 3: Introduction to Panorama
Control
In this exercise we continue to develop the Wazup application. At the end of this exercise the
Wazup application will have a blog page that will show us posts from the Windows Phone
Developer Blog, in addition to what we've accomplished in the previous exercises.
The exercise will include the following tasks:
Add a blog page that uses a Panorama control
Implement Blog page functionality
Task 1 – Adding Blog Page
In this task we will add a placeholder page for the Blog. The page will contain a panorama
control that can show several pages of information. We will use the panorama control on the
next task to show 4 different sub-pages of the blog page.
1. Open Microsoft Visual Studio 2010 Express for Windows Phone from Start | All
Programs | Microsoft Visual Studio 2010 Express | Microsoft Visual Studio 2010
Express for Windows Phone.
Visual Studio 2010: Open Visual Studio 2010 from Start | All Programs | Microsoft
Visual Studio 2010.
2. Open the Begin.sln starter solution from the Source\Ex3-Panorama\Begin folder of this
lab. Alternatively, you can continue working on the solution created in previous
exercise.
Push Notifications Hands-on Lab
Page | 59
3. Add a folder to the project, named BlogImages by right-clicking on Wazup (project
name) and selecting Add New Folder.
Figure 27
Add new folder to the project
4. Add to the BlogImages folder all the files which are located in the
Source\Assets\BlogImages folder in this lab.
5. Select all the files in the BlogImages folder and change the Build Action property to
Content.
This will cause the images to be added to the XAP file instead of as resources inside the DLL file.
Push Notifications Hands-on Lab
Page | 60
Figure 28
Change Build Action for added blog images
Add a new item to the Views folder by right-clicking the Views folder and selecting AddNew
Item…
Push Notifications Hands-on Lab
Page | 61
Figure 29
Add new item to the project
Select Windows Phone Panorama Page and name it BlogPage.xaml.
Figure 30
Add new Windows Phone Panorama Page
Push Notifications Hands-on Lab
Page | 62
6. Compile and run the application.
7. Stop the debugging and return to the code. This step concludes the current task.
Task 2 – Implementing Blog Page Functionality
In this task we will implement the functionality of the Blog page in the Wazup application. At the
end of this task the Wazup application will have a working Blog page.
During this task we will use the Panorama control to show 4 sub-pages of the blog page.
What distinguishes the Panorama control from the Pivot control is that where the Pivot control
shows multiple different pages, the Panorama control presents a single page divided to sub-
pages that we can scroll, like a long horizontal canvas that extends the confines of the screen.
Unlike the Pivot control, the Panorama control has a background image that stretches across all
the sub-pages giving the feel of a wide screen.
1. Add reference to the System.ServiceModel.Syndication assembly (from the Browse
tab), located in \Source\Assets\Binaries \System.ServiceModel.Syndication.dll.
This assembly is needed for the blog service utility class that we will add shortly.
Figure 31
Add reference to System.ServiceModel.Syndication
Push Notifications Hands-on Lab
Page | 63
2. Now we will add the utility classes used to work with the blog service. Add the
BlogService.cs, ImageItem.cs, ImageService.cs, and RssItem.cs files that are located
in Source\Assets\Services folder of this lab to the Services folder .
Figure 32
Solution Explorer after adding blog service files into the Services folder
3. Open the file BlogPage.xaml
4. Add the following XML namespaces to phone:PhoneApplicationPage element next
to the other XML namespaces definitions:
XAML
xmlns:localHelpers="clr-namespace:Wazup.Helpers"
xmlns:localWindowsControls="clr-namespace:System.Windows.Controls"
5. Set the DataContext property of the BlogPage to be the BlogPage itself. Do this by
adding the following line to the phone:PhoneApplicationPage element:
XAML
DataContext="{Binding RelativeSource={RelativeSource Self}}"
Now we will define the UI for the blog page. Locate the LayoutRoot grid and replace
the content with the following code. The blog page contains a single control: a
Panorama control that will show 4 different sub-pages. In the Panorama control we
first define the background image. This background image will stretch across all the
sub-pages of the Panorama control, giving the feeling of a wide horizontal canvas
Push Notifications Hands-on Lab
Page | 64
which we will see section by section.Next we define the 4 sub-pages of the Panorama
control:
The first sub-page shows the last 5 blog posts
The second sub-page shows all the posts in the blog
The third sub-page shows all the comments in the blog
The fourth sub-page shows a list of phone images
The DataTemplates we used in each of these sub-pages will be defined in the next
step.
(Code Snippet – Using Pivot and Panorama – Ex 3 Task 1 Step 5 – BlogPage LayoutRoot)
XAML
<Grid x:Name="LayoutRoot">
<controls:Panorama x:Name="PanoramaControl" Title="windows phone
blog">
<controls:Panorama.Background>
<ImageBrush ImageSource="/Resources/PanoramaBG.png"/>
</controls:Panorama.Background>
<controls:PanoramaItem Header="last 5 posts">
<Grid>
<ListBox
ItemsSource="{Binding LastPosts}"
ItemTemplate="{StaticResource PostLargeTemplate}"
/>
<localHelpers:ProgressBarWithText Text="Loading
Posts..." ShowProgress="{Binding IsPostsLoading}" />
</Grid>
</controls:PanoramaItem>
<controls:PanoramaItem Header="all posts">
<Grid>
<ListBox
ItemsSource="{Binding Posts}"
ItemTemplate="{StaticResource PostSmallTemplate}"
/>
<localHelpers:ProgressBarWithText Text="Loading
Posts" ShowProgress="{Binding IsPostsLoading}" />
</Grid>
</controls:PanoramaItem>
<controls:PanoramaItem Header="comments">
<Grid>
<ListBox
ItemsSource="{Binding Comments}"
ItemTemplate="{StaticResource CommentTemplate}"
Push Notifications Hands-on Lab
Page | 65
/>
<localHelpers:ProgressBarWithText Text="Loading
Comments" ShowProgress="{Binding IsCommentsLoading}" />
</Grid>
</controls:PanoramaItem>
<controls:PanoramaItem Header="images">
<Grid>
<ListBox
ItemsSource="{Binding Images}"
ItemTemplate="{StaticResource ImageTemplate}"
>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<localWindowsControls:WrapPanel />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
</Grid>
</controls:PanoramaItem>
</controls:Panorama>
</Grid>
6. Here we define four data templates:
PostLargeTemplate defines a DataTemplate that is used in the "Last 5 Posts"
sub-page. It transforms an RssItem object into a HyperlinkButton control that
contains the title of the post and navigates to the post when clicked, and a
TextBlock that contains the start of the post content.
PostSmallTemplate defines a DataTemplate that is used in the "All Posts" sub-
page. It transforms an RssItem object into a HyperlinkButton control that
contains the title of the post and navigates to the post when clicked, and a
TextBlock that contains the start of the post content.
CommentTemplate defines a DataTemplate that is used in the "Comments"
sub-page. It transforms an RssItem object into a HyperlinkButton control that
contains the title of the comment and navigates to the comment's post when
clicked, and a TextBlock that contains the start of the comment content.
ImageTemplate defines a DataTemplate that is used in the "Images" sub-page.
It transforms an ImageItem object into an Image control that contains the
loaded image and a TextBlock that contains the image name.
Add the following code into BlogPage resources section.
(Code Snippet – Using Pivot and Panorama – Ex 3 Task 1 Step 6 – BlogPage Resources)
Push Notifications Hands-on Lab
Page | 66
XAML
<phone:PhoneApplicationPage.Resources>
<DataTemplate x:Key="PostLargeTemplate">
<Grid Margin="12,0,12,40">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<HyperlinkButton
Content="{Binding Title}"
NavigateUri="{Binding Url}"
TargetName="_blank" FontSize="29.333" Margin="0,0,0,3"
HorizontalContentAlignment="Left"
MaxHeight="75"
Style="{StaticResource WrappedHyperlinkButtonStyle}"
/>
<TextBlock
Grid.Row="1"
Text="{Binding PlainSummary}"
MaxHeight="80"
TextWrapping="Wrap" Margin="0"
Foreground="White"
/>
</Grid>
</DataTemplate>
<DataTemplate x:Key="PostSmallTemplate">
<Grid Margin="12,0,12,40">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<HyperlinkButton
Content="{Binding Title}"
NavigateUri="{Binding Url}"
TargetName="_blank"
HorizontalContentAlignment="Left"
FontSize="24"
MaxHeight="60"
Style="{StaticResource WrappedHyperlinkButtonStyle}"
Margin="0,0,0,3"
/>
<TextBlock
Grid.Row="1"
Text="{Binding PlainSummary}"
FontSize="20"
MaxHeight="50"
TextWrapping="Wrap" Margin="0"
Push Notifications Hands-on Lab
Page | 67
Foreground="White"
/>
</Grid>
</DataTemplate>
<DataTemplate x:Key="CommentTemplate">
<Grid Margin="12,0,12,40">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<HyperlinkButton
Content="{Binding Title}"
NavigateUri="{Binding Url}"
TargetName="_blank"
HorizontalContentAlignment="Left"
FontSize="20"
MaxHeight="60"
Style="{StaticResource WrappedHyperlinkButtonStyle}"
Margin="0,0,0,2"
/>
<TextBlock
Grid.Row="1"
Text="{Binding PlainSummary}"
FontSize="20"
MaxHeight="30"
TextWrapping="Wrap" Margin="0"
Foreground="White"
/>
</Grid>
</DataTemplate>
<DataTemplate x:Key="ImageTemplate">
<StackPanel Margin="0,3,20,12">
<Border Background="#19FFFFFF" BorderBrush="#FFFFC425"
BorderThickness="1" Margin="0">
<Image
Source="{Binding FileName}"
Stretch="None"
Height="173" Width="173"
/>
</Border>
<TextBlock Text="{Binding Name}" HorizontalAlignment="Left"
Margin="0,0,0,3" Foreground="White" />
</StackPanel>
</DataTemplate>
</phone:PhoneApplicationPage.Resources>
Push Notifications Hands-on Lab
Page | 68
7. We now add buttons to the application bar in the blog page. After the LayoutRoot
grid ends, add the following code:
(Code Snippet – Using Pivot and Panorama – Ex 3 Task 1 Step 7 – BlogPage
ApplicationBar)
XAML
<phone:PhoneApplicationPage.ApplicationBar>
<shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">
<shell:ApplicationBarIconButton x:Name="AppbarButtonDigg"
IconUri="/Resources/App.Digg.png" Text="Digg"
Click="AppbarButtonDigg_Click" />
<shell:ApplicationBarIconButton x:Name="AppbarButtonTwitter"
IconUri="/Resources/App.Twitter.png" Text="Twitter"
Click="AppbarButtonTwitter_Click" />
<shell:ApplicationBarIconButton x:Name="AppbarButtonBlog"
IconUri="/Resources/App.Blog.png" Text="Blog"
Click="AppbarButtonBlog_Click" />
</shell:ApplicationBar>
</phone:PhoneApplicationPage.ApplicationBar>
8. Open the file BlogPage.xaml.cs
9. Replace the using section of the BlogPage class with the following code snippet:
(Code Snippet – Using Pivot and Panorama – Ex 3 Task 1 Step 9 – BlogPage Using)
C#
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Windows;
using Microsoft.Phone.Controls;
using Wazup.Services;
10. Add to the BlogPage class the following dependency properties:
LastPosts of type ObservableCollection<RssItem> - used to save the collection
of last 5 posts
Posts of type ObservableCollection<RssItem> - used to save the collection of
posts
Comments of type ObservableCollection<RssItem> - used to save the collection
of comments
Push Notifications Hands-on Lab
Page | 69
Images of type ObservableCollection<ImageItem> - used to save the collection
of images
IsPostsLoading of type bool – used to indicate whether posts loading is
currently in progress
IsCommentsLoading of type bool – used to indicate whether comments loading
is currently in progress
Use the following code snippet:
(Code Snippet – Using Pivot and Panorama – Ex 3 Task 1 Step 10 – BlogPage Properties)
C#
#region LastPosts
/// <summary>
/// LastPosts Dependency Property
/// </summary>
public static readonly DependencyProperty LastPostsProperty =
DependencyProperty.Register("LastPosts",
typeof(ObservableCollection<RssItem>), typeof(BlogPage),
new PropertyMetadata((ObservableCollection<RssItem>)null));
/// <summary>
/// Gets or sets the LastPosts property. This dependency property
/// indicates what are the last posts.
/// </summary>
public ObservableCollection<RssItem> LastPosts
{
get { return
(ObservableCollection<RssItem>)GetValue(LastPostsProperty); }
set { SetValue(LastPostsProperty, value); }
}
#endregion
#region Posts
/// <summary>
/// Posts Dependency Property
/// </summary>
public static readonly DependencyProperty PostsProperty =
DependencyProperty.Register("Posts",
typeof(ObservableCollection<RssItem>), typeof(BlogPage),
new PropertyMetadata((ObservableCollection<RssItem>)null));
/// <summary>
/// Gets or sets the Posts property. This dependency property
Push Notifications Hands-on Lab
Page | 70
/// indicates what are all the posts.
/// </summary>
public ObservableCollection<RssItem> Posts
{
get { return (ObservableCollection<RssItem>)GetValue(PostsProperty);
}
set { SetValue(PostsProperty, value); }
}
#endregion
#region Comments
/// <summary>
/// Comments Dependency Property
/// </summary>
public static readonly DependencyProperty CommentsProperty =
DependencyProperty.Register("Comments",
typeof(ObservableCollection<RssItem>), typeof(BlogPage),
new PropertyMetadata((ObservableCollection<RssItem>)null));
/// <summary>
/// Gets or sets the Comments property. This dependency property
/// indicates what are the posts comments.
/// </summary>
public ObservableCollection<RssItem> Comments
{
get { return
(ObservableCollection<RssItem>)GetValue(CommentsProperty); }
set { SetValue(CommentsProperty, value); }
}
#endregion
#region Images
/// <summary>
/// Images Dependency Property
/// </summary>
public static readonly DependencyProperty ImagesProperty =
DependencyProperty.Register("Images",
typeof(ObservableCollection<ImageItem>), typeof(BlogPage),
new PropertyMetadata((ObservableCollection<ImageItem>)null));
/// <summary>
/// Gets or sets the Images property. This dependency property
/// indicates what are the images.
/// </summary>
Push Notifications Hands-on Lab
Page | 71
public ObservableCollection<ImageItem> Images
{
get { return
(ObservableCollection<ImageItem>)GetValue(ImagesProperty); }
set { SetValue(ImagesProperty, value); }
}
#endregion
#region IsPostsLoading
/// <summary>
/// IsPostsLoading Dependency Property
/// </summary>
public static readonly DependencyProperty IsPostsLoadingProperty =
DependencyProperty.Register("IsPostsLoading", typeof(bool),
typeof(BlogPage),
new PropertyMetadata((bool)false));
/// <summary>
/// Gets or sets the IsPostsLoading property. This dependency property
/// indicates whether we are currently loading posts.
/// </summary>
public bool IsPostsLoading
{
get { return (bool)GetValue(IsPostsLoadingProperty); }
set { SetValue(IsPostsLoadingProperty, value); }
}
#endregion
#region IsCommentsLoading
/// <summary>
/// IsCommentsLoading Dependency Property
/// </summary>
public static readonly DependencyProperty IsCommentsLoadingProperty =
DependencyProperty.Register("IsCommentsLoading", typeof(bool),
typeof(BlogPage),
new PropertyMetadata((bool)false));
/// <summary>
/// Gets or sets the IsCommentsLoading property. This dependency
property
/// indicates whether we are currently loading comments.
/// </summary>
public bool IsCommentsLoading
{
Push Notifications Hands-on Lab
Page | 72
get { return (bool)GetValue(IsCommentsLoadingProperty); }
set { SetValue(IsCommentsLoadingProperty, value); }
}
#endregion
11. Override the functions OnNavigateTo and OnNavigateFrom of the page. Use the
StateManager class to save and load page state when the current page is changing.
In the function OnNavigateTo, we first try to load the values from the state object,
then we check if LastPosts has a value; if it doesn't, we load the data using the
BlogService and ImageService functions. he BlogService.GetBlogPosts function
accepts a callback function to call if the posts loading id complete and a callback
function to call if the posts loading failed, for example, the blog rss feed is currently
down. BlogService.GetBlogComments work similarly. The ImageService.GetImages
function returns a list of ImageItem objects that represents an image.
Use the following code snippet:
(Code Snippet – Using Pivot and Panorama – Ex 3 Task 1 Step 11 – BlogPage State
Handling)
C#
private const string LastPostsKey = "LastPostsKey";
private const string PostsKey = "PostsKey";
private const string CommentsKey = "CommentsKey";
private const string ImagesKey = "ImagesKey";
protected override void
OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
{
this.SaveState(LastPostsKey, LastPosts);
this.SaveState(PostsKey, Posts);
this.SaveState(CommentsKey, Comments);
this.SaveState(ImagesKey, Images);
}
protected override void
OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
// try to load data from state object
LastPosts =
this.LoadState<ObservableCollection<RssItem>>(LastPostsKey);
Posts = this.LoadState<ObservableCollection<RssItem>>(PostsKey);
Comments =
this.LoadState<ObservableCollection<RssItem>>(CommentsKey);
Push Notifications Hands-on Lab
Page | 73
Images = this.LoadState<ObservableCollection<ImageItem>>(ImagesKey);
if (LastPosts != null)
{
return;
}
// if data wasn't loaded we get it from the blog service
IsPostsLoading = true;
BlogService.GetBlogPosts(
delegate(IEnumerable<RssItem> rssItems)
{
const int NumberOfLastPosts = 5;
LastPosts = new ObservableCollection<RssItem>();
Posts = new ObservableCollection<RssItem>();
foreach (RssItem rssItem in rssItems)
{
IsPostsLoading = false;
Posts.Add(rssItem);
if (LastPosts.Count < NumberOfLastPosts)
{
LastPosts.Add(rssItem);
}
}
},
delegate(Exception exception)
{
IsPostsLoading = false;
System.Diagnostics.Debug.WriteLine(exception);
});
IsCommentsLoading = true;
BlogService.GetBlogComments(
delegate(IEnumerable<RssItem> rssItems)
{
IsCommentsLoading = false;
Comments = new ObservableCollection<RssItem>();
foreach (RssItem rssItem in rssItems)
{
Comments.Add(rssItem);
}
},
Push Notifications Hands-on Lab
Page | 74
delegate(Exception exception)
{
IsCommentsLoading = false;
System.Diagnostics.Debug.WriteLine(exception);
});
// load images from somewhere
Images = new ObservableCollection<ImageItem>();
IEnumerable<ImageItem> images = ImageService.GetImages();
foreach (ImageItem imageItem in images)
{
Images.Add(imageItem);
}
}
12. Add the following event handlers in the BlogPage class. In this step we handle the
application bar buttons. In each even handler we use the Navigation class to go to
the correct page.
(Code Snippet – Using Pivot and Panorama – Ex 3 Task 1 Step 12 – BlogPage Event
Handler)
C#
#region Appbar handlers
/// <summary>
/// Handles the Click event of the AppbarButtonDigg control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="System.EventArgs"/> instance
containing the event data.</param>
private void AppbarButtonDigg_Click(object sender, EventArgs e)
{
this.GoToPage(ApplicationPages.Digg);
}
/// <summary>
/// Handles the Click event of the AppbarButtonTwitter control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="System.EventArgs"/> instance
containing the event data.</param>
private void AppbarButtonTwitter_Click(object sender, EventArgs e)
{
this.GoToPage(ApplicationPages.Trends);
}
Push Notifications Hands-on Lab
Page | 75
/// <summary>
/// Handles the Click event of the AppbarButtonBlog control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="System.EventArgs"/> instance
containing the event data.</param>
private void AppbarButtonBlog_Click(object sender, EventArgs e)
{
// Set "last 5 posts" as default item
// this has the side effect of changing the selected item
PanoramaControl.DefaultItem = PanoramaControl.Items[0];
}
#endregion
13. Compile and run the application.
Push Notifications Hands-on Lab
Page | 76
14. At this stage the blog page should work and look like the following:
Figure 33
Blog page showing blog posts
15. Stop the debugging and return to the code. This step concludes the exercise and the
lab.
During this exercise you learned how to use the Panorama control to show a wide page
with several sub-pages.
Note: The complete solution for this exercise is provided at the following location:
Source\Ex3-Panorama\End.
Push Notifications Hands-on Lab
Page | 77
Summary
During this lab you learned about the new controls in Windows Phone 7 for presenting
information, Pivot and Panorama. You also learned how to navigate between the application
pages and how to handle page state information when your page gets navigated away to a
different application.