In my last post I introduced the tombstoning features of the Chrysalis Windows Phone 7 application framework. To summarise, this allowed developers using the Model-View-ViewModel presentation pattern to easily ensure that their ViewModels could maintain their state during tombstoning. In this post I will provide an overview of how Chrysalis implements this feature. As usual, all the source code is available on the Chrysalis CodePlex site under the “Source Code” tab.
The Chrysalis Service
One of the first steps when using the Chrysalis framework is to register the ChrysalisService in the App.xaml file’s ApplicationLifetimeObjects section (see my last post for details). This takes advantage of Silverlight’s application extension services (see MSDN) which allow you to register services that run at start-up of the application. The advantage of this approach is that once registered, the rest of the application can take advantage of the features of ChrysalisService without having to use any custom base classes of pages, View Models, etc.
The bulk of the initialization of the ChrysalisService happens within the StartService method, which Siliverlight calls during application start-up.
Firstly we store a static reference to our service so that we can find it at any other point within the application execution. After this we get the current PhoneApplicationService (added by default to all Silverlight Windows Phone 7 applications). Since Silverlight will initialize all application services in the order we have specified in the App.xaml file, this will already have been initialized. We then attach to the Activated, Deactivated and Closing events. Note that we do not need to attach to the Launching event since we can identify this if our service has been initialized without the Activated event.
The next step is to attach to navigation events to and from pages within the application. Normally you would do this by using the NavigationService class accessible from the current page, but since at this point of application execution no page is present (and hence the application’s RootVisual property is null) we have no way to access this. The ChrysalisService class overcomes this problem by queuing a request using a DispatcherTimer with a delay of 0ms. Although this sounds like it should execute immediately, the contract for the DispatcherTimer merely states that it should call the callback at least the specified time after starting. In fact this is queued up when the dispatcher next becomes free, conveniently after the RootVisual has been initialized.
We can then use the RootVisual (which we know for Windows Phone 7 Silverlight applications will be a PhoneApplicationFrame) to attach to the Navigating and Navigated events. We also store a reference to the current page for future use, which is also updated on any successful navigation events.
Notifying the ViewModel of application events
Now the ChrysalisService is able to identify all the application events of interest, we need a way to pass this to the current ViewModel. This is done via the two interfaces, IPhoneLifetimeAware and IPhoneNavigationAware.
Since we are tracking the current page at any point of time, we can identify the ViewModel associated with it by using the DataContext of that page. If the returned object implements either of the above interfaces then we can call the relevant methods in response to application events.
Storing application page state
We have not yet addressed the main use of this feature, for storing state relevant to the ViewModel during tombstoning. This is done via a third interface that the ViewModel can implement (as is done by the provided ViewModelBase class), IHasSessionState.
Similarly, the Initialize(…) method is called by ChrysalisService whenever the application is Activated or when navigation occurs to the respective page. The ViewModel can then reinstate any state required to recreate the page prior to tombstoning.
I have now described how the Chrysalis application framework allows developers to easily manage any state relating to individual ViewModels (and therefore to individual pages of an application). In my next post I will describe how Chrysalis allows applications to store application state that may span several pages, and how this can easily be persisted between tombstoning and application restarts as is required.