On October 9th 2010, I did a presentation at the Silicon Valley Code Camp on the Application Lifecycle for Windows Phone 7. This last week was KA-ray-zeee busy at work and I didn’t want to just post the slides and code I had at code camp. Better to wait and really do a good job, so here it is.
Introduction
First, I would like to acknowledge the outstanding decks and examples that the Microsoft Windows Phone 7 Evangelism Team has been and continues to publish. Team members I’ve been working with are Yochay Kiriaty and Jaime Rodriguez.
I created the provided deck from several decks published by the Evangelism Team. I edited and added content for the session I did.
For the three example applications, I studied the Evangelism Team’s material, samples on the web, added many hours of learning and ported Ocean to the Windows Phone 7.
This was a lot of fun, in-fact more pure fun than I’ve had in a while. Don’t get me wrong, I love what I do everyday and the opportunities I’ve been blessed with at Microsoft. Maybe because the phone is new, I didn’t really know much about it, but was able to understand it and get productive quickly. Additionally, the Visual Studio 2010 tooling worked great.
No other way to say it, “developing on Windows Phone 7 is a lot of fun.” Very much looking forward to getting my own device.
I’m encouraged that Microsoft has a commitment to the XAML language and that I was able to leverage my huge investment in WPF with Silverlight 3-4, and now the Windows Phone 7. The ability to transfer my investment across platforms and devices is a fantastic benefit to developers on Microsoft’s stacks.
Let me now turn our attention to what is in the box (the download).
Presentation Slide Deck
The deck is in the solution folder and explains each topic clearly. The application lifecycle concepts are repeated several times in different ways so the reader can grasp tombstonning.
The code snippets in the deck come from TravelReporting
project and the OceanFramework.Phone
project.
ApplicationLifeCycle Project
The purpose of this application is to provide a nice clear log of the application’s constructors, methods and events as they execute. It is critical to your success that you learn the phone’s application lifecycle. This program can help with that.
Crack the App.xaml open and look at the CustomHyperlinkButtonStyle
. I use this to make a Hyperlink control look and act like a Button. I do this so that I can navigate from XAML and not have to wire up a command or click event handler. You’ll see this style used in all three applications where appropriate.
Notice how clean my debug output window is. That’s because I’ve turned off the other messages. To turn off the other messages, right click the debug output window while debugging. Then unselect messages on the context menu that you do not want to see. Below, I just want to see my phone messages, so I’ve left Program Output selected.
Logger
Creating the log messages is very simple, just call Logger.Log();
You can also pass an optional notes string.
void Application_Launching(Object sender, LaunchingEventArgs e) {
Logger.Log();
}
The magic is in the below Log
method. By creating a StackTrace
object, I can extract the calling type and method from the appropriate stack frame. This type of logging is much better than having to craft each individual log message. I’ve used this class in each of the projects.
namespace ApplicationLifeCycle.Infrastructure {
public class Logger {
public static void Log(String notes = "") {
StackTrace stackTrace = new StackTrace();
String typeName = stackTrace.GetFrame(1).GetMethod().DeclaringType.Name;
String methodName = stackTrace.GetFrame(1).GetMethod().Name;
if(!String.IsNullOrEmpty(notes)) {
notes = String.Concat(" - ", notes);
}
Debug.WriteLine(String.Format("WP7: {0} - {1}{2}", typeName, methodName, notes));
}
private Logger() {
}
}
}
LaunchersAndChoosers Project
This project demonstrates 3 launchers and 3 choosers. It also provides a lot of logging so that you can see what goes on and when. Spend some time, using the application. Then predict the sequence of events before executing them, you’ll have the application lifecycle down quickly.
Take a look at the MainPage.xaml and MainPage.xaml.cs. By using the CustomHyperlinkButtonStyle
, I was able to run code-free in the code-behind.
TravelReporting Project
This application allows a user to enter a travel report from their phone. The travel report has two pages of required data. The user can’t proceed to the second page unless the first page is valid.
For validation, I’m using the declarative (attribute based) validation offered by the Ocean framework. The validation APIs allow for multiple rule-sets. This enabled me to have a set of rules for the first page’s fields and a set of rules to validate the entire object on page two.
IDataErrorInfo
is not supported in this release of Silverlight for Windows Phone 7. I have included the interface so that you can have it in place if and when it is supported. In this simple application, I’m not bothering the user with messages until they press the Next or Save buttons. When Next or Saved is pressed, the TravelReport
object is validated against the appropriate rules.
To see the validation attributes in action, have a look at the TravelReport.cs file. You’ll also see several rules added in code.
When the travel report is saved, it is added to the history file.
The History page is accessed from the main page’s menu. The history presents a list of travel reports and allows viewing the report in detail.
The history file simulates accessing the cloud for historical data. When the application starts, two travel reports are added to the history file to give you something to look at.
Extras
TombstoneSupportPhoneApplicationPage (OceanFramework.Phone)
This is the base class for all my pages. It adds automatic tombstone activating and deactivating support so that I don’t have to repeat this code on each page.
One challenge developers have is this business of focus not changing when the user presses the back, start, application button or menu. The problem is, control data bindings do not update their source until lost focus occurs. Since lost focus does not happen when the user does one of these actions, the user could lose that field’s data that was entered but not committed to the source. Remember, when a user presses the start button, the application will be tombstoned and if the field’s data was not committed to the model or view model before those objects get persisted, then the data that was entered is lost.
Not to worry. The below method handles this quirk for you. Take note of the below TODO. My current application only has TextBoxes that need this help. Your applications may need additional tests for other controls.
This method also records the name of the currently focused control so that when the application comes back from tombstonning, the focus field can be restored.
protected override void OnNavigatingFrom(System.Windows.Navigation.NavigatingCancelEventArgs e) {
base.OnNavigatingFrom(e);
if (State.ContainsKey(FOCUSED_ELEMENT)) {
State.Remove(FOCUSED_ELEMENT);
}
var focusedElement = FocusManager.GetFocusedElement() as Control;
if (focusedElement != null) {
if (!String.IsNullOrEmpty(focusedElement.Name)) {
State.Add(FOCUSED_ELEMENT, focusedElement.Name);
}
BindingExpression be = null;
if (focusedElement is TextBox) {
be = focusedElement.GetBindingExpression(TextBox.TextProperty);
}
if (be != null) {
be.UpdateSource();
}
}
}
IsolatedStorageFacade (OceanFramework.Phone)
This facade class provides a simple interface for interacting with the IsolatedStorageFile
and IsolatedStorageSettings
. You’ll want to modify this to meet your specific needs.
I made all the methods static
for ease of use. If I was using an IOC container, I would provide an interface and inject an implementation. This would also make testing easier since the implementation could be swapped out.
TombstoneFacade (OceanFramework.Phone)
This facade class provides a simple interface for interacting with the PhoneApplicationService
temporary storage state bag. You’ll want to modify this to meet your specific needs.
I made all the methods static
for ease of use. If I was using an IOC container, I would provide an interface and inject an implementation. This would also make testing easier since the implementation could be swapped out.
Globalization
I met with my great friend Laurent Bugnion of MVVM-Light fame this week and spent time taking about Windows Phone 7. I asked him about globalization of the phone apps. He explained his solution for using .resx files and I’m sharing it with you.
The Localizer
class is a front end that we can instantiate in XAML, then controls can data bind directly to the properties in the .resx file. This wrapper is required because the .resx class can’t be instantiated in XAML, even if it is marked public
. This may be a bug, I’ll check up on this.
public class Localizer {
Strings _strings;
public Strings Strings {
get { return _strings; }
}
public Localizer() {
_strings = new Strings();
}
}
This XAML is from App.xaml.
<infrastructure:Localizer x:Key="LocalizedStrings" />
The below TextBlock
displays a globalized string
for the application title. All string
s in the TravelReports
application are resources.
<TextBlock Style="{StaticResource PhoneTextNormalStyle}"
Text="{Binding Source={StaticResource LocalizedStrings},
Path=Strings.Application_Title, Mode=OneTime}" />
Download
The download is on my sky drive here.
Remember after downloading a .zip file, you’ll want to right click on the file and “Unblock” the file. This is the mark-of-the-web that Visual Studio 2010 respects.
Have a great day.
Just a grain of sand on the worlds beaches.
Filed under:
C#,
CodeProject,
Ocean,
Presentations,
Silverlight,
Visual Studio 2010,
Windows Phone 7