Sunday, May 20, 2012

Cocoon Navigation – Passing Arguments Between Pages

Over the last couple of posts I have introduced the navigation framework that is included as part of the freely available Cocoon framework for developing Metro-style Windows 8 applications. I have previously shown how to annotate pages with the PageExport and ViewModelExport attributes, and to navigate to these using the INavigationManager.

Passing Arguments to ViewModels

Whilst navigating between pages is a common pattern for modern applications, often you wish to pass some state during page navigation. As an example, imagine a photo browsing application. The “BrowsePhotos” page may show a number of images, which when clicked on navigates to a “ViewPhoto” page. In this case there needs to be some way to pass the image to display as an argument to the “ViewPhoto” page.

This is made simple in the Cocoon navigation framework by a second overload of the INavigationManager.NavigateTo(…) method that takes both a page name and an argument to pass between the pages.

public interface INavigationManager
{
    ...
 
    void NavigateTo(string pageName);
    void NavigateTo(string pageName, object arguments);
}

The ‘arguments’ parameter can be of any type, however there are a number of restrictions that should be observed in practice,
  • The type should be able to be serialized via a DataContractSerializer

  • The type should not rely on a reference to any particular object (for example if the value is from a shared cache it may be better to pass the key rather than the actual object to ensure that multiple versions are not created)

In our photo application example we are caching the image details, so pass the photoID from the “BrowsePhotos” view model,

[ViewModelExport("BrowsePhotos")]
public class BrowsePhotosViewModel
{
    // *** Fields ***
 
    private readonly INavigationManager navigationManager;
 
    // *** Constructors ***
 
    [ImportingConstructor]
    public BrowsePhotosViewModel(INavigationManager navigationManager)
    {
        this.navigationManager = navigationManager;
    }
 
    // *** Command Methods ***
 
    public void ViewPhoto(Photo photo)
    {
        navigationManager.NavigateTo("ViewPhoto", photo.PhotoId);
    }
}

Activating Destination Pages

The destination view model is able to accept parameters by implementing the IActivatable<TArguments, TState> interface where the type of the argument is designated by TArguments. The TState generic type will be discussed in a later blog post and if not required can be set as ‘string’.

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

After creating the new view model the Cocoon framework will call the Activate(…) method passing in the argument passed from the call to INavigationManager.NavigatedTo(…). This method will only be called once and prior to display of the view.

In our example photo browsing application the “ViewPhoto” view model will therefore be implemented as (Note that the unused SaveState() method simply returns ‘null’),

[ViewModelExport("ViewPhoto")]
public class ViewPhotoViewModel : IActivatable<string, string>
{
    ...
 
    // *** IActivatable Methods ***
 
    public void Activate(string arguments, string state)
    {
        this.Photo = GetPhoto(arguments);
    }
 
    public string SaveState()
    {
        return null;
    }
 
    // *** Private Methods ***
 
    private Photo GetPhoto(string photoId)
    {
        ...
    }
}

Summary


I have describe above how the Cocoon framework makes passing arguments between pages simple to implement. Over the next posts I will discuss some of the added value when using the Cocoon navigation framework, including how to make your application seem “always alive”.

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).

No comments: