Tuesday, May 29, 2012

Cocoon Navigation – Making Your App “Always Alive”

Over the last few posts I have discussed the navigation framework that is included as part of the freely available Cocoon framework for developing Metro-style Windows 8 applications in .Net languages. I have shown how to annotate pages to be discovered by the framework and how to pass arguments between pages.

In this post I will discuss one of the benefits of using the Cocoon framework to manage your application’s navigation.

Making Your Application “Always Alive”

One of the challenges when writing Windows 8 Metro-style applications is to manage the application lifecycle. So that Windows is able to ensure a great experience for users running on battery powered devices, Metro style apps are suspended as the user moves to other applications. Furthermore, your application may be terminated to free more memory if this is required. However for the end user great Metro-style applications will give the impression that they are “always alive” in the background. It is up to you, the developer, to ensure that this illusion is maintained. For more background Microsoft’s Windows 8 Application Developer blog has a great post on this topic.

One aspect of making your application feel “always alive” is to ensure that if it is terminated and later relaunched then the user is taken to exactly the same point that they were previously viewing. To do this you must persist the navigation stack, currently viewed page and any page state then subsequently restore this.

Persisting Navigation With the Cocoon Framework

The great news is that if you are using the Cocoon navigation framework then this is all handled automatically for you. All you have to do is enable this by setting the INavigationManager.NavigationStorageType property. Typically you would set this by overrinding the SetupNavigationManager() method in your application bootstrapper (see this post for more information on the bootstrapper),

public class AppBootstrapper : CocoonBootstrapper
{
    // *** Overriden base methods ***
 
    protected override void SetupNavigationManager()
    {
        NavigationManager.NavigationStorageType = NavigationStorageType.Local;
    }
}

There are currently three possible NavigationStorageType values,

  • None – Your navigation state will not be persisted and your application will always launch to your home page.

  • Local – Your navigation state will be persisted to the current machine only.

  • Roaming – Your navigation state will be persisted between all devices that the user logs into using their Microsoft Account.

That’s all you need to do, Cocoon will handle everything else – persisting the navigation stack, restoring to the correct page, storing the arguments passed to each page.

Preserving Page State

In some cases you may want to go a step further and store some page state. Imagine for example you are half way through writing a comment in a social networking app, then change app to do something else. When you return you should expect that you can continue from where you left off. Other things you may want to preserve are selected search filters, selected items, position in a view, etc.

Preserving page state can be done by the view model implementing the IActivatable<TArguments, TState> interface that I discussed last time for passing arguments to pages. The TState generic type can be set to the data type you would like to persist (TArguments can be set to ‘string’ if it is not required).

public interface IActivatable<TArguments, TState>
{
    // *** Methods ***
 
    void Activate(TArguments arguments, TState state);
    TState SaveState();
}

On first navigation to the page the Activate(…) method will be called passing the default value of TState (‘null’ for string or reference types). When Cocoon determines that it should preserve page state then it will call the SaveState() method and your implementation should return the current state. If the application is later terminated and relaunched then a new instance of the view model is created and activated by calling the Activate(…) method with the preserved state.

For example, if as part of a hypothetical photo browsing app we allow the user to comment on a photo we could implement the view model as,

[ViewModelExport("ViewPhoto")]
public class ViewPhotoViewModel : IActivatable<string, ViewPhotoState>
{
    // *** Properties ***
 
    public string Comment
    {
        get { ... }
        set { ... }
    }
 
    ...
 
    // *** IActivatable Methods ***
 
    public void Activate(string arguments, ViewPhotoState state)
    {
        this.Photo = GetPhoto(arguments);
        
        if (state != null)
        {
            ViewPhotoState viewState = (ViewPhotoState)state;
            this.Comment = viewState.Comment;
        }
    }
 
    public ViewPhotoState SaveState()
    {
        return new ViewPhotoState() { Comment = this.Comment };
    }
 
    // *** Sub-classes ***
 
    [DataContract]
    private class ViewPhotoState
    {
        [DataMember]
        public string Comment;
    }
}

Note that we store the state as a custom ‘ViewPhotoState’ object that is decorated to allow serialization by the DataContractSerializer.

Summary


I have shown above how we can easily make our applications feel “always alive” by using the Cocoon navigation framework.

As usual the code is freely available for download from the Cocoon CodePlex site (to get the latest version go to the “Source Code” tab, select the first change set and use the “Download” link).
Post a Comment