Sunday, November 21, 2010

Chrysalis – Tombstoning support (Part II - Implementation Details)

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.

   1: void IApplicationService.StartService(ApplicationServiceContext context)
   2: {
   3:     // Set this as the current ServiceManager via the static property
   4:  
   5:     ChrysalisService.Current = this;
   6:  
   7:     // Attach to the PhoneApplicationService lifetime events
   8:  
   9:     PhoneApplicationService phoneApplicationService = PhoneApplicationService.Current;
  10:  
  11:     phoneApplicationService.Activated += new EventHandler<ActivatedEventArgs>(PhoneApplicationService_Activated);
  12:     phoneApplicationService.Deactivated += new EventHandler<DeactivatedEventArgs>(PhoneApplicationService_Deactivated);
  13:     phoneApplicationService.Closing += new EventHandler<ClosingEventArgs>(PhoneApplicationService_Closing);
  14:  
  15:     // Attach to the page navigation events
  16:     // NB: We set off a DispatcherTimer since we need to wait for the RootVisual property to be set before we can access this
  17:  
  18:     ExecuteViaDispatcherTimer(() =>
  19:         {
  20:             if (Application.Current.RootVisual != null)
  21:                 PhoneApplicationFrame_RootVisualLoaded((PhoneApplicationFrame)Application.Current.RootVisual);
  22:         });
  23: }


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.



   1: private void PhoneApplicationFrame_RootVisualLoaded(PhoneApplicationFrame frame)
   2: {
   3:     // Attach to the navigation events
   4:  
   5:     frame.Navigating += new NavigatingCancelEventHandler(NavigationService_Navigating);
   6:     frame.Navigated += new NavigatedEventHandler(NavigationService_Navigated);
   7:  
   8:     // Set the current page
   9:  
  10:     CurrentPage = frame.Content as PhoneApplicationPage;
  11:  
  12:     ...
  13: }

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.



   1: public interface IPhoneLifetimeAware
   2: {
   3:     void Activated();
   4:     void Closed();
   5:     void Deactivated();
   6:     void Launched();
   7: }



   1: public interface IPhoneNavigationAware
   2: {
   3:     void NavigatingFrom(NavigatingCancelEventArgs e);
   4:     void NavigatedTo(NavigationEventArgs e);
   5: }

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.



   1: public interface IHasSessionState
   2: {
   3:     void Initialize(object state);
   4:     object SaveState();
   5: }

 

The SaveState() method is called by ChrysalisService whenever the application is Deactivated or when navigation occurs away from the respective page. From this method the ViewModel can return some state that will be automatically persisted during tombstoning.

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.


Summary


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.

Friday, September 24, 2010

Chrysalis – Tombstoning support (Part I - Introduction)

As I discussed in my previous post, when you are writing Silverlight (or XNA) based Windows Phone 7 applications, one of the considerations you must make is regarding supporting the “tombstoning” of your application. At any point during its execution your application may receive notification that you must save any state and exit, to possibly (but not always) be restarted at a later point. This however is you application’s view – to the user they must believe that you application was waiting patiently in the background, unaware of the tearing down and restarting that is actually occurring.

If you are following the Model-View-ViewModel presentation pattern then the best placed entity in the system to know about what state to persist when tombstoning is the ViewModel. You have to firstly ensure that the application subscribes correctly to the PhoneApplicationService.Deactivated and PhoneApplicationService.Activated events. These must pass the requests onto the ViewModel which must store its state in the correct locations. Upon reactivation the ViewModel must know that it has some stored state, retrieve it and then restore the UI to that before the deactivation.

Transparently handling these steps is one of the key features of the Chrysalis framework.

How to use Chrysalis for Tombstoning?

Supplied with yesterdays drop of the Chrysalis framework is a sample calculator application. Whilst not particularly useful, it is intended to show how Chrysalis simplifies tombstoning. At its heart is the CalculatorViewModel.

   1: public class CalculatorViewModel : ViewModelBase
   2: {
   3:     // *** Fields ***
   4:     
   5:     private int numberX = 10;
   6:     private int numberY = 5;
   7:     
   8:     // *** Properties ***
   9:     
  10:     public int NumberX
  11:     {
  12:         get
  13:         {
  14:             return numberX;
  15:         }
  16:         set
  17:         {
  18:             numberX = value;
  19:             OnPropertyChanged("NumberX");
  20:             OnPropertyChanged("Total");
  21:         }
  22:     }
  23:     
  24:     public int NumberY
  25:     {
  26:         get
  27:         {
  28:             return numberY;
  29:         }
  30:         set
  31:         {
  32:             numberY = value;
  33:             OnPropertyChanged("NumberY");
  34:             OnPropertyChanged("Total");
  35:         }
  36:     }
  37:     
  38:     public int Total
  39:     {
  40:         get
  41:         {
  42:             return NumberX + NumberY;
  43:         }
  44:     }
  45: }

This derives from Chrysalis.ViewModelBase base class and includes three properties. The properties ‘NumberX’ and ‘NumberY’ are editable and both bound to TextBoxes in the associated UI (CalculatorView.xaml). The ‘Total’ property simply returns the sum of the two other values and is bound to a read-only TextBox in the UI. Property changed notifications are raised by calling OnPropertyChanged(…) on the base class.


At this stage everything will look familiar to the Silverlight or WPF developer, and the application will run as expected,


Calculator


The problem occurs if we now deactivate and reactivate the application. In the emulator provided with the developer tools you can do this by clicking the “Start” button to return to the start page, then clicking “Back” to return to your application. This will result in all values being reset to their initial values as we are not persisting any state. Remember though that the user should believe that the application has been sitting patiently in the background, and expects all the values to be consistent with that.


To solve this problem Chrysalis.ViewModelBase provides a couple of virtual methods that you can override.



protected virtual object SaveState() {...}
protected virtual void RestoreState(object state) {...}

The SaveState() method is called when your application is being deactivated and can return some state to be persisted. The RestoreState(…) method is called when your application is being activated and returns the state so that you can restore the property values, and hence the UI.


Also, to enable the Chrysalis support we need to add a couple of lines to the App.xaml. Firstly an ‘xmlns’ definition at the top of the file to reference the Chrysalis.Services namespace, and the <csv:ChrysalisService/> item in the ApplicationLifettimeObjects section. Appart from those changes (shown in the code below) ,the rest of the App.xaml file can be left as is.



   1: <Application 
   2:     ...
   3:     xmlns:csv="clr-namespace:Chrysalis.Services;assembly=Chrysalis">
   4:  
   5:     <Application.ApplicationLifetimeObjects>
   6:         ...
   7:         <csv:ChrysalisService/>
   8:     </Application.ApplicationLifetimeObjects>
   9:  
  10: </Application>

For our calculator sample we do this with a class ‘CalculatorViewModelState’. Note: This class must be declared with public scope. Since this will be serialized transparently by the phone for the duration of deactivation, we need it to be public otherwise we will receive a SecurityException when the phone tries to deserialize it.



   1: // *** Overriden Base Methods ***
   2:  
   3: protected override object SaveState()
   4: {
   5:     return new CalculatorViewModelState()
   6:     {
   7:         NumberX = numberX,
   8:         NumberY = numberY
   9:     };
  10: }
  11:  
  12: protected override void RestoreState(object state)
  13: {
  14:     CalculatorViewModelState vmState = (CalculatorViewModelState)state;
  15:  
  16:     if (vmState != null)
  17:     {
  18:         NumberX = vmState.NumberX;
  19:         NumberY = vmState.NumberY;
  20:     }
  21: }
  22:  
  23: // *** Sub-classes ***
  24:  
  25: public class CalculatorViewModelState
  26: {
  27:     public int NumberX { get; set; }
  28:     public int NumberY { get; set; }
  29: }

We simply set the properties and return the state within the SaveState() method, and restore the values in the RestoreState(…) method. If you now try to tombstone the application, the state will be persisted on exit, and on returning the UI will look and perform identically to how it did prior to deactivation.


Success!


Navigation and Storing State


You may notice that in the sample application we have a button that takes us to a second page of the application – CalculatorInformationPage.xaml. We should also be able to restore any application state if we navigate to this page, tombstone, return to the application, and navigate back to the calculator page.


No need to worry though, since the Chrysalis framework ensures that this occurs transparently without having to write any further code. This works by calling SaveState()/RestoreTo(..) when a user navigates away from and back to the page, and handling the persistence of the state as required.


Summary


As you will have seen, the Chrysalis framework allows Silverlight developers using the MVVM pattern to simplify the persistence of state during tombstoning on their applications. By simply overriding two methods, the ViewModel itself can specify what state to persist, and the framework handles all the plumbing required to store and retrieve this.


In my next posts I will be discussing how this all works under the covers and when you should be returning state vs when you should be using isolated storage. After that, I will be releasing and describing the next feature currently being added to Chrysalis related to choosers.


Update 17/10/2010: With the latest version RestoreState(…) should check for a null state & MainViewModel is refactored to CalculatorViewModel.

Introducing Chrysalis

In this post I am going to introduce the new Chrysalis framework available now from CodePlex at http://chrysalis.codeplex.com. Chrysalis is in an open source framework designed to simplify the development of Silverlight based Windows Phone 7 applications. Whilst it is primarily focused on Model-View-ViewModel (MVVM) related presentation patterns, it can be applied to other designs.

Many times it has been commented that if you are a Silverlight developer (and to some extent a WPF developer), then you now have the skills to write Windows Phone 7 applications. And this is almost true – with the introduction of Windows Phone 7 you can now write Silverlight applications that run on the phone as native apps (with XNA the other option for more graphically rich apps). But at the same time there are a number of new concepts that you will need to consider to write high quality software that runs within the constraints of a mobile device.

Tombstoning

The first consideration that everyone who works with Windows Phone 7 (both in Silverlight and XNA) should be aware of is the interestingly named “tombstoning”. The MSDN documentation has an excellent section on the “Execution Model Overview for Windows Phone” so I will not go into this in detail. In summary, you have to be aware that your application may be exited automatically at any point during its execution (for example when a phone call comes in) – not pushed to the background, but killed outright. At some later point you application may be reactivated, and it is you job as a developer to ensure that all application state is restored. The end user should believe that the app was sat there in the background all the time, even though you know that it was killed and restarted.

The Windows Phone 7 framework will warn you that you application is being deactivated with the PhoneApplicationService.Deactivated event. This is your opportunity to save any state required, either to one of a couple of state bags, or to isolated storage. When the application is restarted then you will receive the PhoneApplicationService.Activated event, and you can restore the UI to its former state.

In reality there is a lot to think about. Firstly you have to ensure that if you are using MVVM then your ViewModels receive the activation and deactivation events. This is complicated by the fact that the PhoneApplicationService.Activated event is often fired before your ViewModel is even created. In addition there is a lot of control state that may need to be maintained – currently focused control, position of scroll bars, etc.

Chrysalis aims to greatly simplify this process.

Choosers

In Windows Phone 7 there are a number of points at which you may need to interact with the built in phone UI, for example to take a photo with the camera, or to retrieve contact information. This is done using “Choosers” (MSDN article).

When you show a chooser we once again experience tombstoning. For the duration of the user interacting with the phone UI, our application is exited, to be restarted later when the interaction has completed. Not only do we now need to restore any state within the application, we must remember that we were calling into a chooser and what we were intending to do with the result – for example if we have multiple sets of contact information on the screen, which were we updating?

Chrysalis aims to allow you to specify a callback within your ViewModel that will receive the result from the chooser. Combined with the tombstoning support, your application should be barely aware that the application was killed and restarted. Instead the chooser will look like any other method call and callback.

Access to Hardware

Although the programming model for Windows Phone 7 is entirely managed code, there are two “flavours” of application – Silverlight and XNA. In several cases features exist within XNA, but not within Silverlight. Whilst these can be accessed by simply adding the XNA assembly references, the APIs sometimes require a different mindset.

Chrysalis aims to provide wrappers where required to make connecting to the hardware available through the XNA framework as simple as using any of the native Silverlight controls.

Summary

To conclude, the Chrysalis framework is now available at http://chrysalis.codeplex.com. While this is only a first release I encourage you to take a look at the basis provided and keep an eye on this blog as I will describe the usage and implementation of new features as they are introduced.

And please provide feedback on existing or new features, either through this blog, or on CodePlex.

Sunday, April 15, 2007

How small can you go? - Part III

In part one of this series of posts ("How small can you go?" 22 Jan 2007) I described how you could design a Windows Presentation Foundation (WPF) control that altered the visibility of specific areas of a UI when then containing window was resized. Compare this to the behaviour of the Office 2007 ribbon, which will hide itself to show more of the edited document when the window is below a certain size. In part II ("How small can you go? - Part II" 15 Feb 2007) I detailed an alternative approach that allowed a trigger to be used when any bindable property (e.g. the width of a window) was below a certain size. In this post I will complete the implementation.


To summarise part II, we implemented an IValueConverter that would return a boolean value indicating whether a specified binding was less than a certain value. This could be used as follows,



<... .Resources>
<cvt:LessThanConverter x:Key="LessThanConverter"/>
</... .Resources>

<DataTrigger Value="True" Binding="{Binding RelativeSource={RelativeSource Self}, Path=ActualWidth, Converter={StaticResource lessThanConverter}, ConverterParameter=200}">
...
</DataTrigger>


While this allowed defining a trigger for when the width was below a specific threshhold, we would have to define the trigger again for the height of the window. What we really need is some way to combine two bindings with a 'logical OR' operation.


Introducing the IMultiValueConverter...


An IMultiValueConverter is similar in principle to an IValueConverter, whereas the latter allows the conversion of a single value into another form (in our case, a double into a bool indicating whether the value is below a threshold), the former will take several values, and combine them into a single output value that is then used as a trigger. We therefore need an IMultiValueConverter that will take a number of booleans and output a single boolean that represents a 'logical OR' of all the input values. We can then use the following XAML,



<... .Resources>
<cvt:LessThanConverter x:Key="lessThanConverter"/>
<cvt:MultiValueOrConverter x:Key="multiValueOrConverter"/>
</... .Resources>

...

<DataTrigger Value="True">
<DataTrigger.Binding>
<MultiBinding Converter="{StaticResource multiValueOrConverter}">
<Binding RelativeSource="{RelativeSource Self}" Path="ActualWidth" Converter="{StaticResource lessThanConverter}" ConverterParameter="200"/>
<Binding RelativeSource="{RelativeSource Self}" Path="ActualHeight" Converter="{StaticResource lessThanConverter}" ConverterParameter="200"/>
</MultiBinding>
</DataTrigger.Binding>
...
</DataTrigger>



This snippet declares two objects, our LessThanConverter from before, and a new MultiValueOrConverter. Following this we have a DataTrigger who's binding is a MultiBinding that takes two bindings that will return true if the width or height is less than 200. By default the MultiBinding will only trigger if all the child bindings are true (a 'logical AND'). We change this behaviour to a 'logical OR' by specifying our multi-value converter. The trigger will now fire if either the element width OR height are less than 200.


The actual code for the multi-value converter is similar in principle to that of a single-value converter. We take an array of input values that we will assume are all boolean values. We then perform a foreach loop over them and if any are true, we return true, otherwise false. Therefore the resulting code is,



using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Data;
using System.Globalization;

namespace SizingApplication2
{
public class MultiValueOrConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
foreach (bool value in values)
{
if (value == true)
return true;
}

return false;
}

public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}

}
}



If we combine this with the XAML snippet above and include a suitable setter to hide the desired parts of the UI, we now have all the behaviour we require. Advantages of this approach include not requiring any extra elements, and being able to adapt the value converters to any situation where the UI changes based upon a certain value (for example, to display a warning message when a slider is moved above a certain value, or even change its colour as a warning).


The full code for this post and an example usage is available here.

Sunday, March 04, 2007

It's all in the Blend

Recently I've been experimenting with the new software tool Expression Blend. For those of you who do not know, Expression Blend is Microsoft's design tool for XAML and WPF applications and is available as I write in Beta 2 form. It provides a visual design workspace where you can lay out all the elements that make up a UI, and adjust their properties as required.

I have been making extensive use of it to style all the elements in my ribbon UI framework that I am currently developing. For someone who has previously edited the XAML directly it provides a much quicker environment for laying out the UI, with instant feedback on all changes. It also simplifies the introduction of triggers (changes on IsMouseOver, IsPressed, etc.) and animation. As an example, shown below is the application menu button for the ribbon UI. Of course since this is WPF this is all vector based, and smoothly scales up (NB: This screen grab is from an actual live UI - rollover animations, opens a menu when clicked, etc...).


In its current incarnation (beta 2) there are some issues I have had. First of all I have been unable currently to get the whole of my ribbon UI in the designer. To be fair, I haven't really tried fixing this, and it is a large composition of custom controls in a WPF rendered chrome window. It also takes a bit of learning to get used to the way it places elements by default. Of course I never read the help when I started using it which could of helped, and once you understand the basic ideas it is very easy to build up the control structure desired.

My favorite features apart from the ease at which the UI can be styled... One item I'll definitely add here is the gradient eyedropper tool. This is similar to the standard eyedropper, which can pick up individual pixel colours from the screen. However, when the gradient eyedropper tool is dragged across a region of the screen it will automatically pick up entire gradient fills. Great for designing smooth user interfaces. Also I like the simplicity by which you can apply property changes and animation upon events.

Let me know below if anybody else has any experiences of Expression Blend...



Update: After a request for the XAML code I have attached the basic code below (copy and paste into XamlPad to see it). The actual Expression Blend generated XAML is significantly more complex (and much less readable!), and includes all the roll-over behaviour etc.. This is the main reason I chose a designer over hand crafting the XAML. Hopefully the attached code will give you an idea how to approach such designs.

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:sys="clr-namespace:System;assembly=mscorlib" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >
<Page.Resources>
<Style TargetType="{x:Type Button}" x:Key="RibbonApplicationMenuButton">
<Setter Property="Width" Value="37"/>
<Setter Property="Height" Value="37"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>

<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid>
<Border BorderThickness="0,0,0,0" CornerRadius="100000,100000,100000,100000" Opacity="1" Margin="0,0,-1,-1" x:Name="ShadowBorder" Background="#39000000"/>
<Border x:Name="OuterBorder" BorderBrush="#FF6E7D95" BorderThickness="1,1,1,1" CornerRadius="100000,100000,100000,100000">
<Border ClipToBounds="False" x:Name="InnerBorder" Width="Auto" Height="Auto" BorderBrush="#FFDDE2EC" BorderThickness="1,1,1,1" CornerRadius="10000,10000,10000,10000">
<Border.Background>
<LinearGradientBrush EndPoint="0.505,0.489" StartPoint="0.512,-0.004">
<GradientStop Color="#FFF3F5F8" Offset="0"/>
<GradientStop Color="#FFC0CADB" Offset="1"/>
</LinearGradientBrush>
</Border.Background>
<Grid Width="Auto" Height="Auto">
<Path RenderTransformOrigin="0.499999990968993,0.0833333333333333" Stretch="Fill" Margin="0,15,0,0" x:Name="path" Width="Auto" Data="F1 M16.5,15.5 C22.163836,15.5 27.559435,15.738094 32.466614,16.168823 L32.5,16.5 C32.5,25.336555 25.336555,32.5 16.5,32.5 7.663444,32.5 0.5,25.336555 0.5000006,16.5 L0.53338605,16.168823 C5.4405661,15.738094 10.836165,15.5 16.5,15.5 z">
<Path.Fill>
<RadialGradientBrush MappingMode="RelativeToBoundingBox" GradientOrigin="0.5,0.5">
<RadialGradientBrush.RelativeTransform>
<TransformGroup>
<ScaleTransform CenterX="0.5" CenterY="0.5" ScaleX="1.077" ScaleY="1.748"/>
<SkewTransform AngleX="0" AngleY="0" CenterX="0.5" CenterY="0.5"/>
<RotateTransform Angle="0" CenterX="0.5" CenterY="0.5"/>
<TranslateTransform X="-0.002" Y="-0.025"/>
</TransformGroup>
</RadialGradientBrush.RelativeTransform>
<GradientStop Color="#FFFFFFFF" Offset="0.375"/>
<GradientStop Color="#FF93A5C2" Offset="1"/>
<GradientStop Color="#FFF2F4F7" Offset="0.529"/>
</RadialGradientBrush>
</Path.Fill>
</Path>
<ContentPresenter HorizontalAlignment="Center" Margin="0,0,0,0" VerticalAlignment="Center" Width="Auto" Height="Auto"/>
</Grid>
</Border>
</Border>
</Grid>

</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Page.Resources>

<Button Style="{StaticResource RibbonApplicationMenuButton}"/>
</Page>