Advanced About Page for Windows Phone apps
This article shows how to create an advanced "About" or "Information" page for a Windows Phone application that includes mechanisms for feedback, sharing and technical support.
Dados do artigo
Exemplo de código
Testado com
Compatibilidade
Artigo
Contents |
Introduction
Applications should have an "About Page" which contains relevant information about the application and its author. Most applications will provide the following minimal information:
- Application name
- Application version
- Copyright
- Summary/overview of app
- Website, Support and Privacy Policy
Some applications need to show more details, including application history, external rules, credits, thanks etc.
This article explains how create and reuse an advanced "About Page" which also includes functionality to:
- Rate the application
- Send feedback to the author
- Share application by email
- Share application by social network
Screenshots
The first two screenshots below show the About Page with open and closed menu, respectively.
The following screenshots show the application home page with menu bar from which you can launch the About page. Note that it is the menu which is of interest here - the page itself is just a placeholder.
Source Code
The source code can be found in Nokia Projects: About Page Sample
Pre-requisites
This example uses Model-View-ViewModel (MVVM), a design pattern recommended for Windows Phone application development.
Elements of the MVVM pattern:
- Views - represents all the class that are pages (is related with the UI).
- ViewModel - represents the class that has model's connection with the page (with the UI).
- Model - represents the class for the entities and business logic.
There are a number of toolkits that can help make it easier to use the MVVM pattern. For this example we use:
- Cimbalino Windows Phone Toolkit - a set of useful and powerful items that will help you build your Silverlight applications for Windows Phone. The Toolkit is divided in projects which deliver different features. The base project (Cimbalino.Phone.Toolkit) contains base MVVM services, some very useful converters, helper classes and extension methods, and the bindable Application Bar behaviour.
- MVVM Light Toolkit (PCL version) - a set of components to help people use the MVVM pattern. It may be used in all XAML/C# frameworks.
These packages are available in Nuget Package Manager (for both targets) and can be installed as follows:
- Open the project and select References, open the context menu with mouse (right click) and select Manage "Manage NuGet Packages ..."
- Install MVVM Light toolkit (for information about this package go here)
- Install Cimbalino toolkit (for information about this package go here)
- Following this step we can see both packages installed
Creating an "About Page"
This code example is valid for both Windows Phone 7.5 and Windows Phone OS 8.0, and contains a complete sample for both platforms. The example app was created using the Windows Phone App template.
The project has the following files and folders:
- ViewModels - folder that will contain all view models
- Views - folder that will contain all views.
- HomePage.xaml - represents the main page
- About Page.xaml - represents the about page
- HomeViewModel.cs - represent the file that contains the view model class for the HomePage
- AboutViewModel.cs- represent the file that contains the view model class for the AboutPage
- ViewModelLocator.cs - represent the file that class that helps to binding the ViewModel with the Page's DataContext
The resulting project structure is:
Home Page.xaml
The HomePage will be the first page showed when the application is launched. This page contains the WebBrowser control to show this article and has the button "About Page".
This XAML defines the user interface for the Home page. Note that because we are using MVVM pattern, all logical code will be inside the view model HomeViewModel that is binding to DataContext.
<phone:PhoneApplicationPage
x:Class="NokiaDev.AboutPageSample.Views.HomePage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:cimbalino="clr-namespace:Cimbalino.Phone.Toolkit.Behaviors;assembly=Cimbalino.Phone.Toolkit"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
DataContext="{Binding HomeViewModel, Source={StaticResource Locator}}"
mc:Ignorable="d"
shell:SystemTray.IsVisible="True">
<!--LayoutRoot is the root grid where all page content is placed-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!--TitlePanel contains the name of the application and page title-->
<StackPanel Grid.Row="0" Margin="12,17,0,28">
<TextBlock Text="Nokia Developer Wiki Samples" Style="{StaticResource PhoneTextNormalStyle}"/>
<TextBlock Text="Article" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
<TextBlock Text="About page for Windows Phone applications"
FontSize="{StaticResource PhoneFontSizeSmall}"
Foreground="{StaticResource PhoneAccentBrush}"
Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
</StackPanel>
<!--ContentPanel - place additional content here-->
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<phone:WebBrowser Source="http://www.developer.nokia.com/Community/Wiki/Advanced_About_Page_for_Windows_Phone_apps" />
</Grid>
<i:Interaction.Behaviors>
<cimbalino:ApplicationBarBehavior>
<cimbalino:ApplicationBarIconButton Command="{Binding AboutCommand, Mode=OneTime}"
IconUri="/Images/appbar.about.png"
Text="About" />
<cimbalino:ApplicationBarBehavior.MenuItems>
<cimbalino:ApplicationBarMenuItem Command="{Binding AboutCommand, Mode=OneTime}"
Text="About"/>
</cimbalino:ApplicationBarBehavior.MenuItems>
</cimbalino:ApplicationBarBehavior>
</i:Interaction.Behaviors>
</Grid>
</phone:PhoneApplicationPage>
At the end of the XAML code, is possible to see the definition for the ApplicationBar that uses the ApplicationBarBehavior from Cimbalino Toolkit. The reason we did not used the Application Bar control from SDK is related with the fact that it is not a FrameworkElement and hence it cannot be used to apply a binding; this is a problem for for anyone implementing the MVVM pattern.
See more about the ApplicationBarBehavior from Cimbalino Toolkit, here:
- Cimbalino Windows Phone Toolkit: ApplicationBarBehavior
- Cimbalino Windows Phone Toolkit: MultiApplicationBarBehavior
About Page.xaml
AboutPage represents the "About" or "Information" page itself. This page contains some controls for the fields decsribed in the #Introduction|introduction]] and contains the buttons for the additional features.
The user interface for the About page is as follows. Note that because we are using MVVM pattern, all logical code will be inside the view model AboutViewModel that is binding to DataContext.
<phone:PhoneApplicationPage
x:Class="NokiaDev.AboutPageSample.Views.AboutPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:cimbalino="clr-namespace:Cimbalino.Phone.Toolkit.Behaviors;assembly=Cimbalino.Phone.Toolkit"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
DataContext="{Binding AboutViewModel, Source={StaticResource Locator}}"
mc:Ignorable="d"
shell:SystemTray.IsVisible="True">
<!--LayoutRoot is the root grid where all page content is placed-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!--TitlePanel contains the name of the application and page title-->
<StackPanel Grid.Row="0" Margin="12,17,0,28">
<TextBlock Text="Nokia Developer Wiki Samples" Style="{StaticResource PhoneTextNormalStyle}"/>
<TextBlock Text="About" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
</StackPanel>
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<StackPanel Margin="0,-12,0,24">
<TextBlock Style="{StaticResource PhoneTextExtraLargeStyle}"
Text="About Page Sample"
Foreground="{StaticResource PhoneAccentBrush}" />
<TextBlock Style="{StaticResource PhoneTextLargeStyle}">
by <Run Text="{Binding Author}" />
</TextBlock>
<StackPanel Orientation="Horizontal" Margin="0,18,0,0">
<TextBlock FontWeight="Bold"
FontSize="{StaticResource PhoneFontSizeMedium}"
Style="{StaticResource PhoneTextNormalStyle}" Text="Version:" />
<TextBlock Margin="0" Text="{Binding Version}"
Style="{StaticResource PhoneTextNormalStyle}" x:Name="AppVersion" />
</StackPanel>
<TextBlock Style="{StaticResource PhoneTextNormalStyle}"
FontSize="{StaticResource PhoneFontSizeMedium}"
Margin="12,12,0,0" FontWeight="Bold"
Text="Copyright (c) 2013 Nokia Developer Wiki." />
<TextBlock Style="{StaticResource PhoneTextNormalStyle}"
Margin="12,24,0,0" FontSize="{StaticResource PhoneFontSizeSmall}"
TextWrapping="Wrap">
This application show an 'About page' sample for Windows Phone applications.
<LineBreak/>See more about it, please see the following reference:
</TextBlock>
<HyperlinkButton NavigateUri="http://www.developer.nokia.com/Community/Wiki/About_page_for_Windows_Phone_applications"
Foreground="{StaticResource PhoneAccentBrush}"
TargetName="_new" FontSize="{StaticResource PhoneFontSizeSmall}"
HorizontalAlignment="Left"
Content="About page for Windows Phone applications" />
<TextBlock Style="{StaticResource PhoneTextNormalStyle}"
Margin="12,24,0,12" FontWeight="Bold"
Text="More informations:"
FontSize="{StaticResource PhoneFontSizeMedium}" />
<HyperlinkButton NavigateUri="http://www.developer.nokia.com/"
Foreground="{StaticResource PhoneAccentBrush}"
TargetName="_new"
HorizontalAlignment="Left"
Content="Website" />
<HyperlinkButton NavigateUri="http://www.developer.nokia.com/"
Foreground="{StaticResource PhoneAccentBrush}"
TargetName="_new"
HorizontalAlignment="Left"
Content="Support" />
<HyperlinkButton NavigateUri="http://www.developer.nokia.com/"
Foreground="{StaticResource PhoneAccentBrush}"
TargetName="_new"
HorizontalAlignment="Left"
Content="Privacy Policy" />
</StackPanel>
</Grid>
<i:Interaction.Behaviors>
<cimbalino:ApplicationBarBehavior>
<cimbalino:ApplicationBarIconButton Command="{Binding RateCommand, Mode=OneTime}"
IconUri="/Images/appbar.rate.png"
Text="Rate it" />
<cimbalino:ApplicationBarIconButton Command="{Binding SendFeedbackCommand, Mode=OneTime}"
IconUri="/Images/appbar.reply.email.png"
Text="Feedback" />
<cimbalino:ApplicationBarIconButton Command="{Binding ShareToMailCommand, Mode=OneTime}"
IconUri="/Images/appbar.email.png"
Text="Email" />
<cimbalino:ApplicationBarIconButton Command="{Binding ShareSocialNetworkCommand, Mode=OneTime}"
IconUri="/Images/appbar.share.png"
Text="Share it" />
</cimbalino:ApplicationBarBehavior>
</i:Interaction.Behaviors>
</Grid>
</phone:PhoneApplicationPage>
As in HomePage, we use the ApplicationBarBehavior from Cimbalino Toolkit to define the application bar with binding support.
HomeViewModel.cs
The Home Page view model is as below:
namespace NokiaDev.AboutPageSample.ViewModels
{
using System;
using System.Windows.Input;
using Cimbalino.Phone.Toolkit.Services;
using GalaSoft.MvvmLight.Command;
/// <summary>
/// The home view model.
/// </summary>
public class HomeViewModel
{
/// <summary>
/// The navigation service.
/// </summary>
private readonly INavigationService _navigationService;
/// <summary>
/// Initializes a new instance of the <see cref="HomeViewModel"/> class.
/// </summary>
/// <param name="navigationService">
/// The navigation service.
/// </param>
public HomeViewModel(INavigationService navigationService)
{
this._navigationService = navigationService;
this.AboutCommand = new RelayCommand(this.ShowAbout);
}
/// <summary>
/// Gets the about command.
/// </summary>
/// <value>
/// The about command.
/// </value>
public ICommand AboutCommand { get; private set; }
/// <summary>
/// The show about.
/// </summary>
private void ShowAbout()
{
this._navigationService.NavigateTo(new Uri("/Views/AboutPage.xaml", UriKind.Relative));
}
}
}
Here we used:
- INavigationService interface from Cimbalino toolkit (source code is here). This represents an interface for a service capable of handling the application navigation and the implementation for this interface will be NavigationService.
- RelayCommand class from MVVM Light toolkit (source code here).
A simple image that shows the flow:
AboutViewModel.cs
The About Page view model is as below:
namespace NokiaDev.AboutPageSample.ViewModels
{
using System;
using System.Windows.Input;
using Cimbalino.Phone.Toolkit.Helpers;
using Cimbalino.Phone.Toolkit.Services;
using GalaSoft.MvvmLight.Command;
/// <summary>
/// The about view model.
/// </summary>
public class AboutViewModel
{
/// <summary>
/// The email compose service.
/// </summary>
private readonly IEmailComposeService _emailComposeService;
/// <summary>
/// The marketplace review service.
/// </summary>
private readonly IMarketplaceReviewService _marketplaceReviewService;
/// <summary>
/// The share link service.
/// </summary>
private readonly IShareLinkService _shareLinkService;
/// <summary>
/// The public application url.
/// </summary>
private readonly string _appUrl;
/// <summary>
/// The application manifest.
/// </summary>
private readonly ApplicationManifest _applicationManifest;
/// <summary>
/// Initializes a new instance of the <see cref="AboutViewModel"/> class.
/// </summary>
/// <param name="emailComposeService">
/// The email Compose Service.
/// </param>
/// <param name="applicationManifestService">
/// The application Manifest Service.
/// </param>
/// <param name="marketplaceReviewService">
/// The marketplace review service
/// </param>
/// <param name="shareLinkService">
/// The share Link Service.
/// </param>
public AboutViewModel(
IEmailComposeService emailComposeService,
IApplicationManifestService applicationManifestService,
IMarketplaceReviewService marketplaceReviewService,
IShareLinkService shareLinkService)
{
_emailComposeService = emailComposeService;
_marketplaceReviewService = marketplaceReviewService;
_shareLinkService = shareLinkService;
RateCommand = new RelayCommand(this.Rate);
SendFeedbackCommand = new RelayCommand(this.SendFeedback);
ShareToMailCommand = new RelayCommand(this.ShareToMail);
ShareSocialNetworkCommand = new RelayCommand(this.ShareSocialNetwork);
_applicationManifest = applicationManifestService.GetApplicationManifest();
_appUrl = string.Concat("http://windowsphone.com/s?appid=", _applicationManifest.App.ProductId);
}
/// <summary>
/// Gets the author.
/// </summary>
public string Author
{
get
{
return _applicationManifest.App.Author;
}
}
/// <summary>
/// Gets the version.
/// </summary>
public string Version
{
get
{
return _applicationManifest.App.Version;
}
}
/// <summary>
/// Gets the rate command.
/// </summary>
public ICommand RateCommand { get; private set; }
/// <summary>
/// Gets the send feedback command.
/// </summary>
public ICommand SendFeedbackCommand { get; private set; }
/// <summary>
/// Gets the share social network command.
/// </summary>
public ICommand ShareSocialNetworkCommand { get; private set; }
/// <summary>
/// Gets the share to e-mail command.
/// </summary>
public ICommand ShareToMailCommand { get; private set; }
/// <summary>
/// The rate.
/// </summary>
private void Rate()
{
_marketplaceReviewService.Show();
}
/// <summary>
/// The send feedback.
/// </summary>
private void SendFeedback()
{
const string To = "saramgsilva@gmail.com";
const string Subject = "My Feedback";
var body = string.Format(
"Application {0}\n Version: {1}",
_applicationManifest.App.Title,
_applicationManifest.App.Version);
_emailComposeService.Show(To, Subject, body);
}
/// <summary>
/// The share social network.
/// </summary>
private void ShareSocialNetwork()
{
const string Message = "This application is amazing, should try it! See in";
_shareLinkService.Show(_applicationManifest.App.Title, Message, new Uri(_appUrl, UriKind.Absolute));
}
/// <summary>
/// The share to mail.
/// </summary>
private void ShareToMail()
{
const string Subject = "Nokia Developer Wiki Samples - About page";
var body = string.Concat("This application is amazing, you should try it! See in", _appUrl);
_emailComposeService.Show(Subject, body);
}
}
}
Here we used:
- RelayCommand class (MVVM Light toolkit - source code here)
- Represents "A command whose sole purpose is to relay its functionality to other objects by invoking delegates. The default return value for the CanExecute method is 'true'. This class does not allow you to accept command parameters in the Execute and CanExecute callback methods".
- IEmailComposeService interface (Cimbalino toolkit - source code here)
- Represents an interface for a service capable of sending e-mail messages. The implementation is EmailComposeService
- IMarketplaceReviewService interface (Cimbalino toolkit - source code here)
- Represents an interface for a service capable of showing the marketplace review screen for an application and the implementation for this interface will be MarketplaceReviewService.
- IShareLinkService interface ((Cimbalino toolkit - source code here)
- Represents an interface for a service capable of sharing links over the social networks configured on the device. The implementation is ShareLinkService.
- IApplicationManifest interface (Cimbalino toolkit - source code here)
- Represents an interface for a service capable of reading from the application manifest. The implementation is ApplicationManifestService
Each interface is injected in ViewModel, which are defined in ViewModelLocator. For example, for NavigationService we need to do:
SimpleIoc.Default.Register<INavigationService, NavigationService>();
This means when the Ioc container needs an implementation of INavigationService and will create an object of NavigationService (the idea is the same for the other dependencies).
As we saw in HomeViewModel, each application bar button will be binding to a command and it will be associated to an action. Let's see how it works for Author name:
The TextBlock's Text is binding to a property Author from AboutViewModel and this property will get the name of the author defined in Manifest file. There isn't a direct way to get it, but with IApplicationManifest from Cimbalino toolkit we don't need to worry about it, because this class get it for us without additional development.
The value for the Version is similar to the code for Author.
ViewModelLocator.cs
To help each page connect with its view model we use a ViewModelLocator to manage all view models and their dependencies.
namespace NokiaDev.AboutPageSample.ViewModels
{
using Cimbalino.Phone.Toolkit.Services;
using GalaSoft.MvvmLight.Ioc;
using Microsoft.Practices.ServiceLocation;
/// <summary>
/// The view model locator.
/// </summary>
public class ViewModelLocator
{
/// <summary>
/// Initializes a new instance of the <see cref="ViewModelLocator"/> class.
/// </summary>
public ViewModelLocator()
{
// starts the Ioc container
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
// register all dependecies
if (!SimpleIoc.Default.IsRegistered<INavigationService>())
{
SimpleIoc.Default.Register<INavigationService, NavigationService>();
}
if (!SimpleIoc.Default.IsRegistered<IMarketplaceReviewService>())
{
SimpleIoc.Default.Register<IMarketplaceReviewService, MarketplaceReviewService>();
}
if (!SimpleIoc.Default.IsRegistered<IShareLinkService>())
{
SimpleIoc.Default.Register<IShareLinkService, ShareLinkService>();
}
if (!SimpleIoc.Default.IsRegistered<IApplicationManifestService>())
{
SimpleIoc.Default.Register<IApplicationManifestService, ApplicationManifestService>();
}
if (!SimpleIoc.Default.IsRegistered<IEmailComposeService>())
{
SimpleIoc.Default.Register<IEmailComposeService, EmailComposeService>();
}
// register all view models
SimpleIoc.Default.Register<HomeViewModel>();
SimpleIoc.Default.Register<AboutViewModel>();
}
/// <summary>
/// Gets the home view model.
/// </summary>
public HomeViewModel HomeViewModel
{
get
{
return ServiceLocator.Current.GetInstance<HomeViewModel>();
}
}
/// <summary>
/// Gets the about view model.
/// </summary>
public AboutViewModel AboutViewModel
{
get
{
return ServiceLocator.Current.GetInstance<AboutViewModel>();
}
}
/// <summary>
/// The cleanup.
/// </summary>
public static void Cleanup()
{
// TODO Clear the ViewModels
}
}
}
The constructor of the ViewModelLocator starts the Ioc container ( SimpleIoc) and registers all dependencies and View Models.
This Ioc container manages all dependencies and injects them to each View Model. The ViewModelLocator contains one property for each View Model registered, because it will be used in binding with Page's DataContext.
if (!SimpleIoc.Default.IsRegistered< .... >())
{...}
We add the ViewModelLocator to App.xaml.
App.xaml
The App.xaml and App.xaml.cs is the class created when the application starts.
In XAML, is possible to add global resources dictionaries or even simple object. For our sample we will add the ViewModelLocator object that will be a static field.
<Application
x:Class="NokiaDev.AboutPageSample.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:viewModel="clr-namespace:NokiaDev.AboutPageSample.ViewModels">
<!--Application Resources-->
<Application.Resources>
<viewModel:ViewModelLocator x:Key="Locator" />
</Application.Resources>
<Application.ApplicationLifetimeObjects>
<!--Required object that handles lifetime events for the application-->
<shell:PhoneApplicationService
Launching="ApplicationLaunching" Closing="ApplicationClosing"
Activated="ApplicationActivated" Deactivated="ApplicationDeactivated"/>
</Application.ApplicationLifetimeObjects>
</Application>
Benefits of MVVM
Using MVVM has many benefits:
- The view model implementation is independent of the services implementation like ApplicationManifestService, NavigationService, etc. Each time the view is changed only the XAML code needs to be changed. It is not necessary to change the behaviour just because the view changed (as long as the features are the same!);
- This approach allows us to implement unit test for the view model using fake services;
- Maintenance is much easier
- Separation of concerns and features allows cleaner/better code;
Because each toolkit is used by a lot of people it more likely that any issues will be fixed. It allows rapid and effective development.
Reusing an "About Page"
Almost every application we create will have an About Page, and these will be virtually the same. To simplify our development process, we might reuse this work by:
- Creating item templates for: AboutPage.xaml and for AboutViewModel.cs
- Creating project template for the project, allowing you to choose one of the targets.
Because our project has dependencies from external references (Cimbalino Windows Phone Toolkit , MVVM Light Toolkit (PCL version)) and from the images contained in images folder, the second method (creating the project template) is a better approach. This is the option discussed below.
- Export the template project
- Editing the exported template
- After unzip the result file, we can find some files, *.cs and *.xaml files are common for us, and we recognize these. But there is an important file, with the extension .vstemplate (normally remaned for MyTemplate.vstemplate), which contains the definition for the project when is created. Here is an initial version, with generic definition that will be defined when the project is created.
<VSTemplate Version="3.0.0" xmlns="http://schemas.microsoft.com/developer/vstemplate/2005" Type="Project">
<TemplateData>
<Name>NokiaDev Windows Phone Application</Name>
<Description>A project for creating Windows Phone application with support for MVVM and About Page.</Description>
<ProjectType>CSharp</ProjectType>
<ProjectSubType>
</ProjectSubType>
<SortOrder>1000</SortOrder>
<CreateNewFolder>true</CreateNewFolder>
<DefaultName>NokiaDev Windows Phone Application</DefaultName>
<ProvideDefaultName>true</ProvideDefaultName>
<LocationField>Enabled</LocationField>
<EnableLocationBrowseButton>true</EnableLocationBrowseButton>
<Icon>__TemplateIcon.ico</Icon>
</TemplateData>
<TemplateContent>
<Project TargetFileName="NokiaDev.AboutPageSample.csproj" File="NokiaDev.AboutPageSample.csproj" ReplaceParameters="true">
<ProjectItem ReplaceParameters="true" TargetFileName="App.xaml">App.xaml</ProjectItem>
<ProjectItem ReplaceParameters="true" TargetFileName="App.xaml.cs">App.xaml.cs</ProjectItem>
<ProjectItem ReplaceParameters="false" TargetFileName="ApplicationIcon.png">ApplicationIcon.png</ProjectItem>
<ProjectItem ReplaceParameters="false" TargetFileName="Background.png">Background.png</ProjectItem>
<Folder Name="Images" TargetFolderName="Images">
<ProjectItem ReplaceParameters="false" TargetFileName="appbar.about.png">appbar.about.png</ProjectItem>
<ProjectItem ReplaceParameters="false" TargetFileName="appbar.email.png">appbar.email.png</ProjectItem>
<ProjectItem ReplaceParameters="false" TargetFileName="appbar.rate.png">appbar.rate.png</ProjectItem>
<ProjectItem ReplaceParameters="false" TargetFileName="appbar.reply.email.png">appbar.reply.email.png</ProjectItem>
<ProjectItem ReplaceParameters="false" TargetFileName="appbar.share.png">appbar.share.png</ProjectItem>
<ProjectItem ReplaceParameters="false" TargetFileName="appbar.share.settings.png">appbar.share.settings.png</ProjectItem>
</Folder>
<ProjectItem ReplaceParameters="true" TargetFileName="packages.config">packages.config</ProjectItem>
<Folder Name="Properties" TargetFolderName="Properties">
<ProjectItem ReplaceParameters="true" TargetFileName="AppManifest.xml">AppManifest.xml</ProjectItem>
<ProjectItem ReplaceParameters="true" TargetFileName="AssemblyInfo.cs">AssemblyInfo.cs</ProjectItem>
<ProjectItem ReplaceParameters="true" TargetFileName="WMAppManifest.xml">WMAppManifest.xml</ProjectItem>
</Folder>
<ProjectItem ReplaceParameters="true" TargetFileName="Read-Me.txt">Read-Me.txt</ProjectItem>
<ProjectItem ReplaceParameters="false" TargetFileName="Settings.StyleCop">Settings.StyleCop</ProjectItem>
<ProjectItem ReplaceParameters="false" TargetFileName="SplashScreenImage.jpg">SplashScreenImage.jpg</ProjectItem>
<Folder Name="ViewModels" TargetFolderName="ViewModels">
<ProjectItem ReplaceParameters="true" TargetFileName="AboutViewModel.cs">AboutViewModel.cs</ProjectItem>
<ProjectItem ReplaceParameters="true" TargetFileName="HomeViewModel.cs">HomeViewModel.cs</ProjectItem>
<ProjectItem ReplaceParameters="true" TargetFileName="ViewModelLocator.cs">ViewModelLocator.cs</ProjectItem>
</Folder>
<Folder Name="Views" TargetFolderName="Views">
<ProjectItem ReplaceParameters="true" TargetFileName="AboutPage.xaml">AboutPage.xaml</ProjectItem>
<ProjectItem ReplaceParameters="true" TargetFileName="AboutPage.xaml.cs">AboutPage.xaml.cs</ProjectItem>
<ProjectItem ReplaceParameters="true" TargetFileName="HomePage.xaml">HomePage.xaml</ProjectItem>
<ProjectItem ReplaceParameters="true" TargetFileName="HomePage.xaml.cs">HomePage.xaml.cs</ProjectItem>
</Folder>
</Project>
</TemplateContent>
</VSTemplate> - Tip: We added the nupkg (Cimbalino.Phone.Toolkit.2.1.nupkg, Portable.MvvmLightLibs.4.1.27.1.nupkg, Unofficial.Blend.Interactivity.1.0.0.nupkg and Portable.CommonServiceLocator.1.2.2.nupkg) that will be used for install the NuGet packages used in project. And is need to add theses reference in *.vstemplate file, at the bottom.
<VSTemplate Version="3.0.0" xmlns="http://schemas.microsoft.com/developer/vstemplate/2005" Type="Project">
.....
<WizardExtension>
<Assembly>NuGet.VisualStudio.Interop, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</Assembly>
<FullClassName>NuGet.VisualStudio.TemplateWizard</FullClassName>
</WizardExtension>
<WizardData>
<packages repository="template">
<package id="Cimbalino.Phone.Toolkit" version="2.1" targetFramework="wp71" />
<package id="Portable.CommonServiceLocator" version="1.2.2" targetFramework="wp71" />
<package id="Portable.MvvmLightLibs" version="4.1.27.1" targetFramework="wp71" />
<package id="Unofficial.Blend.Interactivity" version="1.0.0" targetFramework="wp71" />
</packages>
</WizardData>
</VSTemplate>
- After unzip the result file, we can find some files, *.cs and *.xaml files are common for us, and we recognize these. But there is an important file, with the extension .vstemplate (normally remaned for MyTemplate.vstemplate), which contains the definition for the project when is created. Here is an initial version, with generic definition that will be defined when the project is created.
- Add the new template, for install, near all Windows Phone Templates (must be inside the folder with Windows Phone name)
- Install the new template
Here is the result template: NokiaDev - Windows Phone Template
This template is created for Windows Phone SO 7.1 and can be upgraded for Windows Phone SO 8.0. The best approach, but outside the goal for the article, is to create an implementation of IWizard for selecting the correct target when the project is created.
- Item Templates can be found in "C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE\ItemTemplates\"
- Project Template can be found in "C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE\ProjectTemplates\"
References:
- (MSDN) Creating Project and Item Templates
- (MSDN) Templates for Creating Templates
- (MSDN) Packages in Visual Studio Templates
- (MSDN) How to: Use Wizards with Project Templates
Conclusion
In conclusion, an about page makes the user informed about all useful details about the application.This allow to add additional features like rate, feedback and share which increases the quality and can be great for marketing. User opinion is the best feedback we can get for have a great application, for this reason is recommended to have one. To ensure a quick development in repeated task is recommended to reuse code.
Additional references
The following articles are old and to some extent out of date. However the fundamental concepts remain sound:


















Contents
Hamishwillee - Thanks very much!
Hi Sara
Thanks very much for this. I have given it a subedit, primarily for English and Wiki style. If you look at the history I think you will see that by using # and #: I can make lists and "steps" easier to read.
My first suggestion for improvement would be to split out section #Telerik RadControls - Windows Phone Application Template into its own article (and link between them). This makes sense because it will make it easier to find, and later it will make it easier to group with other telerik control articles. Even more important, this is a really fast way of creating an "About" page so I see it as probably one of the "first choices" for PDP members. If you want to make it really interesting you could add a section on "extending" the telerik About control (assuming that is possible).
I am not sure what to then do about the other section #Coding4Fun Toolkit - AboutPrompt. It is a bit confusing because it sounds initially like there is a control in the toolkit called AboutPrompt, but a quick scan of the code make it look more like you're only using Coding4Fun for the UserControl, and creating your own AboutPrompt. This needs to be clarified and then I can give you better advice on how to proceed - if this is just to get the UserControl then I'd want a lot more discussion on why this approach is better than just creating out of XAML as you've done.
The section on "reusing" is excellent - I'm not sure we cover how to create reusable templates anywhere on wiki. This might be a really good "standalone article" in future.
For the first section on your About page, this is a good step-by-step guide, and made even more helpful by your "templatising". The only "issue" I have is that there is a lot of code but not much explanation of it. In particular I think it is worth explaining the bits that separate this from an ordinary About Page - how you went about creating the sharing and feedback features, and why you did it this way. If you split out some of the other sections into their own documents then perhaps it will feel more reasonable to do so.
What do you think? If you agree with the "need" to do this, then do you need help with the split?
Regards
Hamishhamishwillee 04:22, 18 March 2013 (EET)
Saramgsilva - Response
Hamish : My first suggestion for improvement would be to split out section #Telerik RadControls - Windows Phone Application Template into its own article (and link between them). This makes sense because it will make it easier to find, and later it will make it easier to group with other telerik control articles. Even more important, this is a really fast way of creating an "About" page so I see it as probably one of the "first choices" for PDP members. If you want to make it really interesting you could add a section on "extending" the telerik About control (assuming that is possible).
> The template from Telerik needs more development, is like a first and simple version that needs more details. i agree with separate articles, this is very big!
Hamish : I am not sure what to then do about the other section #Coding4Fun Toolkit - AboutPrompt. It is a bit confusing because it sounds initially like there is a control in the toolkit called AboutPrompt, but a quick scan of the code make it look more like you're only using Coding4Fun for the UserControl, and creating your own AboutPrompt. This needs to be clarified and then I can give you better advice on how to proceed - if this is just to get the UserControl then I'd want a lot more discussion on why this approach is better than just creating out of XAML as you've done.
> The AboutPrompt is a popup with a initial data from Manifest file, the contol i added if to keep a similar look like in the sample i created.
Hamish :The section on "reusing" is excellent - I'm not sure we cover how to create reusable templates anywhere on wiki. This might be a really good "standalone article" in future.
> For now keep in this article, in future i would like to create one for reusing code using Item Template, Project Template and Nuget ( i think is interesting, but need to study more advance things)
Hamish : For the first section on your About page, this is a good step-by-step guide, and made even more helpful by your "templatising". The only "issue" I have is that there is a lot of code but not much explanation of it. In particular I think it is worth explaining the bits that separate this from an ordinary About Page - how you went about creating the sharing and feedback features, and why you did it this way. If you split out some of the other sections into their own documents then perhaps it will feel more reasonable to do so.
> yes is true, i need to write a bit mpre, because i am using external libraries and i need to explain why i did this. The article is very big and with that i lost a bit in explanation.
Hamish : What do you think? If you agree with the "need" to do this, then do you need help with the split?
> Thanks for the review, is that i need to listen. i would like to change this but i have some doubts with name for articles.saramgsilva 23:08, 18 March 2013 (EET)
Hamishwillee - Hi Sara
Discussed offline - basically I agree with all the above. New names for articles in SeeAlso.
Let me know when you're ready for next round review. I think these are shaping up really well.
Regards
Hhamishwillee 00:55, 19 March 2013 (EET)
Saramgsilva - Summit for review
Hello Hamishwillee,
I think this version is ready for review. I will waiting for your feedback.
Regards
Sara Silvasaramgsilva 12:19, 20 March 2013 (EET)
Hamishwillee - Subedited, further feedback
Hi Sara
Structurally this is much better, and I think you've made great strides in the discussion. I have subedited to fix some grammatical errors and make it a bit more readable - mostly little things like having the About page image before the Home page image (since that isn't so interesting).
These are the remaining questions/issues:
The conclusions section is all "benefits of MVVM" and not "What this article delivered". I think it may be OK to have the benefits listed, but what I would do is add a section up the top "Architectural overview" (or similar) and include your overview of MVVM and the benefits. Then you can have Pre-requisites just containing the section about the toolkits and how to install them.
Instead of a conclusions I'd have at the bottom a Summary which just states that you've used MVVM to create an about page which supports sharing blah blah, and which can easily be reused in your projects. In the Summary OR the Introduction you might also want to add that "If you just want a basic About Page, see the articles X, Y".
Thanks so much for this. I think it is going to be useful to a lot of people.
Regards
Hamishhamishwillee 05:37, 21 March 2013 (EET)
Saramgsilva - Response
Hi,
I changed from Conclusion to Benefits of MVVM, but it is refering to the sample, because in some points i talk about classes i used from toolkits i used, but i don´t want extend or talk about so much about MVVM, because it should be another article, that should talk about architecture.
About this: "resources dictionaries or even simple object"
Here i am adding an object of the type ViewModelLocator
<Application.Resources>
but i can add something like it:
<Application.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries> <ResourceDictionary Source="Resources/StandardStyles.xaml" /> <ResourceDictionary Source="Resources/BaseStyles.xaml" /> </ResourceDictionary.MergedDictionaries> <viewModel:ViewModelLocator x:Key="Locator" /> </ResourceDictionary> </Application.Resources>I am adding resources dictionaries and and object. Are you thinking i wasn´t clear?
About summary, i can add one, normally do.saramgsilva 13:52, 21 March 2013 (EET)
Hamishwillee - Minor subedit
Hi Sara,
I did a minor fix to the "benefits" section - yes this is a better name. You can add a summary if you like - not strictly necessary. I do think some words pointing to the telerik and other solutions for "simplest approach" might be worth adding (yes, I know we link in the SeeAlso, but words indicating "for a quick and dirty solution" in introduction would help.
With respect to "In XAML, is possible to add global resources dictionaries or even simple object. For our sample we will add the ViewModelLocator object that will be a static field.". I think what you are saying is that in this case a static field is "a simple object" - correct?
Looks about done to me!
Regards
Hhamishwillee 01:23, 22 March 2013 (EET)