Design a Simple Windows Phone 7 app

Design a simple Windows Phone 7 app

Learn how to build a typical List/Detail application for Windows Phone 7.

The article presents simple customer list editor making use of various data editors - all built with the help of MobileLight Toolkit from Resco.

Introduction

Windows Phone 7 (WP7) programming combines several technologies:

  • .NET (WP7 uses a subset of the full .NET class library)
  • C# (Other languages not available yet)
  • Silverlight for WP7. (A simplification of the desktop SVL, which is in turn a simplification of WPF.)

Mastering these technologies for a programmer coming from (say) Windows Mobile programming is a real problem.

This article shows how to build typical List/Detail application for Windows Phone 7 using MobileLight Toolkit from Resco.

Prerequisites

The target audience is a C# .NET programmer with a reading knowledge of Silverlight. At the very minimum, the reader should understand basic Silverlight controls and layout.

You need to have installed Windows Phone Developer Tools. (Requires Vista or W7, 2 GB RAM, DirectX 10+)

The installation includes

  • Visual Studio 2010 Express for WP,
  • The emulator (real phone device is not needed).

Further, you should install Resco MobileLight Toolkit from http://www.resco.net/developer/mobilelighttoolkit.

The Toolkit contains a set of useful controls that simplify Windows Phone 7 programming. Attached SampleApplication provides a template that can be used to build a broad range of typical business-class applications without delving into advanced Silverlight topics.

Although SampleApplication operates with more difficult concepts - binding, styling and templating - all of this can be understood from the comments.

Application Preview

Resco_wp7_1.png

The above screenshots demonstrate the application functionality:

  • Main screen displays customer list.
  • Selected customer is displayed differently, as it shows buttons offering call, e-mail and edit actions.
  • At the bottom there is [+] button for creation of a new customer.
  • Customer form contains various editors of customer properties and buttons for save/delete.

Special editors - combo box and datetime picker are shown in the screenshots below.

Resco_wp7_2.png

The rest of this document describes the source code for this application. We recommend that you install Resco MobileLight Toolkit and open the SampleApplication project.

Application description

The app serves as an editor of a customer list.

It displays list of all customers and lets you add/delete/edit individual customers.

The code consists of:

  • Data:
    • Customer.cs contains class Customer and related classes.
    • Customer is a simple data class with a set of public properties. It implements INotifyPropertyChanged interface so that the UI controls can react to data changes.
    • Class Customers provides single application-wide customer list. It is also responsible for the data loading and storing.
    • Customers.xml is a sample customer list in xml format used for the app initialization.
  • Images
  • Three classes - App, MainPage, DetailsPage, i.e. a pretty standard structure of a WP7 application (1 application object + 2 pages).
    • Note also that each class is actually represented by 2 files - one for GUI (xaml file) and one for the respective code (xaml.cs file).

App class

The code for App.xaml, App.xaml.cs was generated by Visual Studio. The only thing added is the line

 Customers.Save();

in Application_Deactivated/Application_Closing handlers. (In other words we tell the class Customers that it's time to close)

That's it. Well, you may ask how the app actually starts. This is done behind the scenes in the file WMAppManifest.xml. This file is organized by Microsoft Visual Studio and contains a few standard things (background, app title) and the start page - MainPage in our case.

MainPage class

Apart from some initialization/termination stuff, it's here where the programming of WP7 apps starts.

MainPage.xaml defines the UI - the header, bottom bar (with [New] button) and the most important part - the AdvancedList control.
MainPage.xaml.cs contains:

  • Standard constructor generated by Microsoft Visual Studio. (InitializeComponent() is a command to read xaml file at runtime.)
  • OnNavigatedTo handler. WP7 apps consist of pages and this handler is called by the framework when the page becomes active.
    In our case we do a single thing - set up the DataContext, which is a single instance of the Customers class. DataContext is then inherited by the page controls. In this case it is the list that uses inherited DataContext to show Customers.Items collection.
  • The rest of the file contains event handlers. The handlers that initiate email or phone call are straightforward (see the code), while the navigation is described elsewhere.

How the navigation works

WP7 apps have pretty standard structure as they always consist of these components:

  • Application object takes cares about the app life cycle - launching/termination, activation/deactivation.
  • Pages which are basically forms. (Objects derived from PhoneApplicationPage class.)
  • Navigation between the pages.

The navigation concept is simple:

  • System navigates to the first page. (Defined in WMAppManifest.xml)
  • The application can navigate to another page using NavigationService.Navigate() calls.
  • The user presses the back key or start button. (To return to previous page or to exit the application.)

Every page (PhoneApplicationPage derived class) has two navigation related callbacks:

  • OnNavigatedTo - called when the page is activated.
  • OnNavigatedFrom - called when the page is deactivated.

The very last thing to mention is the parameters used in these methods.  In this respect two things are important:

  • We navigate to xaml files. As long as we talk about the xaml files within our application, the file names used are simply full paths with respect to the project folder.

Hence we could navigate to say "/SubFolder/MyFile.xaml"

  • We need to pass some parameters. Microsoft decided to take over Uri technology used by web browsers.

Uri has usually the form <xaml_path>[?<query>], where

query:=  key1=value1&key2=value2&...                  //  or key1=value1;key2=value2;...

In our case the navigation conversation looks like this:

MainPage issues the commands:

Navigate(  "/DetailsPage.xaml?selectedItem=12" )           //  Open the item #12
Navigate( "/DetailsPage.xaml?newItem=true" )              // Create new item\
DetailsPage reacts in OnNavigatedTo():

System passes the query is passed through the page property NavigationContext. Its member QueryString contains key/value dictionary of the parameters passed. (This saves you from parsing rather complex query format.)

In our case we simply analyze single key/value pair, which is either [selectedItem,12] or [newItem,true].

How the AdvancedList works

Most of the list programming is done in the Xaml file. Here is the code scheme:

// MainPage.xaml
<r:AdvancedList x:Name="MainListBox" ItemsSource="{Binding Items}" ...    NormalTemplate="normal" SelectedTemplate="selected">
<r:AdvancedList.DataTemplates>
<DataTemplate x:Name="normal"> ... </DataTemplate>
<DataTemplate x:Name="selected"> ... </DataTemplate>
</r:AdvancedList.DataTemplates>
</r:AdvancedList>
// MainPage.xaml.cs
public partial class MainPage : PhoneApplicationPage {
protected override void OnNavigatedTo(NavigationEventArgs e) {
//...
if (DataContext == null)
DataContext = Customers.Instance;
}
private void btnCall_Click(object sender, RoutedEventArgs e) {
//...
var customer = Customers.Instance.Items[MainListBox.SelectedIndex];
}
}

Let's analyze the code:

  • The name property of the AdvancedList Xml element defines the instance
    AdvancedList MainListBox ;
    This object is then used in btnCall_Click handler to get selected customer.
  • The DataContext is set in the .cs file to Customers.Instance.
    If you now realize that ItemsSource for AdvancedList is bound to the DataContext property Items, it becomes clear that the list displays Customers.Items.
    Moreover, it is an ObservableCollection, i.e. the binding will be "live". What it means is that if the rest of the application adds/deletes/changes customers, the list will react automatically.
    (Note that there are other possibilities to supply ListBox items, but the described one represents the mainstream use.)
  • The last question is how the list items are displayed. This is defined by the DataTemplate and will be discussed later. For the time being note that there are two templates - one for selected and another one for the unselected item.

DataTemplate

The template is used to display list items, which (in our case) means Customer objects.

Here is the template for unselected item:

<DataTemplate  x:Name="normal">
<Grid>
// Define grid 2x2
<Grid.RowDefinitions>  <RowDefinition/>  <RowDefinition/>  </Grid.RowDefinitions>
<Grid.ColumnDefinitions>  <ColumnDefinition/>  <ColumnDefinition/>  </Grid.ColumnDefinitions>// First grid row shows the value Customer.Name
<TextBlock Grid.ColumnSpan="2" Text="{Binding Name}"
Style="{StaticResource PhoneTextExtraLargeStyle}"/>// 2nd row displays Customer properties EMailAddress1 and Telephone1
<TextBlock Grid.Row="1" Grid.Column="0" Text="{Binding EMailAddress1}"
Style="{StaticResource PhoneTextSubtleStyle}"/>
<TextBlock Grid.Row="1" Grid.Column="1" Text="{Binding Telephone1}"
Style="{StaticResource PhoneTextSubtleStyle}"/>
</Grid>
</DataTemplate>

Note also that we do not specify text properties (font, height etc.) directly, but rely instead on predefined WP7 styles. The advantage is that the application will behave consistently with the phone theme selected by the user.

The template for selected item looks similarly - it displays the same items as above and adds 3 buttons - [call], [email] and [edit]. These buttons are processed in the .cs file by handlers such as btnCall_Click.

If you looked into the AdvancedList source code, you would find that the treatment of dynamic templates is the primary added functionality of this class. In other words, AdvancedList adds TemplateSelector - a feature present in WPF, but omitted in Silverlight.

How to implement dynamic template

SampleApplication relies on AdvancedList feature that allows using different templates for selected/unselected items. The former one contains buttons, while the latter shows only Customer properties.

The logical question is if we could do it by using a single dynamic template that would show/hide buttons depending on the selection. In other words we need a way to bind button visibility to the IsSelected property.

Unfortunately Silverlight (unlike WPF) can't bind to ListBoxItem. (IsSelected is a property of ListBoxItem!)

However, AdvancedList has a solution:

Customer object has suitable property that by chance uses the same name - IsSelected. If you set AdvancedList ItemIsSelectedPath property to "IsSelected", then the list selection will be bound to Customer.IsSelected property.

Now we can make the dynamic template:

<r:AdvancedList ItemsSource="{Binding  Items}"  ...  ItemIsSelectedPath="IsSelected">

<r:AdvancedList.Resources>
<r:BooleanToVisibilityConverter x:Key="MyConverter"/>
</r:AdvancedList.Resources>
...
<DataTemplate>
<Button ... Visibility="{Binding IsSelected, Converter={StaticResource MyConverter}}"/>
...
</DataTemplate>
</r:AdvancedList>

The binding relies on a converter. This is because there is a type conversion between IsSelected and Visibility properties.

Remark:

You can similarly bind ListBoxItem.IsEnabled property to suitable Customer property.

How DetailView works

DetailsPage serves as a viewer/editor of a Customer object.

We already know that this form is launched through navigation. If you look into OnNavigatedTo() code, you will see that its purpose is to set the DataContext to suitable Customer object (m_customer).

There's not much else what the .cs file takes care of - it just performs the final action, i.e. saves or discards the changes.

Most of the work is done in the Xaml file, but even that one is conceptually simple:

  • It's just definitions of individual controls that are properly bound to the DataContext (i.e. Customer object) properties.
  • On top of that we have also the title and the ApplicationBar with two buttons - [Save] and [Delete].

The most important part of the code is the DetailView element containing a list of various DetailViewItems.

Number of items is unlimited; the DetailView will scroll if necessary.

Typical item definition looks as follows:

<r:DetailItemTextBox  Label="Name" DataMember="Name" />

As you probably guessed, it is a (labeled) text box with that edits the property Customer.Name.

The text box takes the whole screen width with the label displayed right above it. (This all can be overridden.)

There's just one more complex item - the combo box:

<r:DetailItemComboBox  Label="Company Size" DataMember="Size"
ItemsSource="{Binding Source={StaticResource CustomerSizesKey}}"
ValueMemberPath="Id"  DisplayMemberPath="Label"/>

The first two attributes (Label, DataMember) are standard, i.e. combo box edits the property

 int  Customer.Size;

Remaining attributes define the content of the list shown when the combo box is opened:

  • ItemsSource supplies the item list. In this case it is the CustomerSizes object defined through static resources, i.e. a list of CustomerSize objects. Look to the xaml code for the implementation details.
  • DisplayMemberPath attribute tells the list to display the item property CustomerSize.Label.
  • ValueMemberPath attribute tells the list to return the item property CustomerSize.Id.
  • DetailItemComboBox binds the returned value to the Customer.Size property.

As you'll become familiar with WP7 programming, you will discover other ways how to set up the DetailView.

See for example DetailView.xaml comments that discuss other ways how to setup the combo box. 

Note also that you are not limited to placing DetailViewItem's into the DetailView.

You can use any other control as well - just take care about proper binding.

What happens to data

Customers.xml contains the default data that is used when the app is launched for the first time.

Once you edit the data, it gets saved into WP7 isolated storage. Unfortunately, it means the data cannot be used by any other application.

If you - as a programmer - want to see raw saved data, do the trick described in the source code of the Customers.Instance() method.

The format of the saved data relies on the old good XmlSerializer. It covers most common scenarios, although one could expect problems with more complex types as Silverlight does not support custom serializing (ISerializable interface, Serializable attribute).

As an alternative you could use DataContractSerializer (DCS) that is natively used by Silverlight messaging.

Although DCS is newer, it is not clearly superior to XmlSerializer. (DCS is slightly faster, but produces larger payload.)

Our recommendation is to start with XmlSerializer and switch to DCS only if the former does not support all data formats.

As of now, the only meaningful way of data sharing on WP7 presents the web services. However, this topic goes well beyond the purpose of the current document and won't be discussed here.

What's Next

Resco is a company with a long tradition of mobile programming covering both end-user applications and developer tools. The Toolkit - as it is published now - is just the first version. In the near future existing controls will be enhanced and new ones added. We also plan to publish a series of tutorials that should help to jump-start Windows Phone 7 programming.

Any feedback is welcome - either here or directly at Resco forums.


Similar Articles