Monday, April 30, 2012

Navigation in Cocoon – MVVM for Metro-style apps

Over the next series of posts I’m going to introduce a new subsystem within the Cocoon framework for Metro-style applications written in managed languages.
Modern rich client applications often consist of a number of interconnected pages or views. For example consider the Windows 8 “Store”. This has a home page that acts as a hub the links to a number of category pages, which in turn link to the individual application detail pages. The user navigates forward through the application flow by clicking images, buttons or links. They can also navigate backwards by using a back button that is placed in the top left hand corner of each page. In addition there are ‘special pages’ such as search, or even the settings panes available from the settings charm.

There are a number of challenges for developers who wish to correctly implement such a navigation structure.

Navigation in Cocoon

Although not limited to this, the Cocoon framework is designed to work great with the Model-View-ViewModel (MVVM) pattern that has become common when designing XAML based applications. One problem when using this pattern is that you need some way of associating a view with a view-model. Often this is done by navigating directly to a page, and using a “ViewModelLocator” to identify and wire up the respective view-model.

In Cocoon a slightly different approach is used. Here, rather than navigating directly to a view, you navigate to a named page. Although the behaviour is extensible, by default Cocoon will use MEF (the built in composition framework included in .Net) to locate both the view and view-model associated with this page name, create and initialise instances of these and wire them together.

You can export any XAML view (for example the pages created by any of the Visual Studio templates) by adding the ‘PageExport’ attribute to the code-behind file,

[PageExport("BrowsePhotos")]
public sealed partial class BrowsePhotosPage : MyPhotoApp.Common.LayoutAwarePage
{
    public BrowsePhotosPage()
    {
        this.InitializeComponent();
    }
}

And similarly you can export the view-model using the ‘ViewModelExport’ attribute,


[ViewModelExport("BrowsePhotos")]
public class BrowsePhotosViewModel
{
    ...
}

The Navigation Manager

In order to navigate between pages, Cocoon includes a navigation manager that can be accessed by importing the INavigationManager interface through MEF (simplified by the fact that all views and view models in Cocoon are themselves are composed by MEF).


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

The most interesting methods are the two overloads of ‘NavigateTo(…)’ that both take the page name to navigate to. The navigation manager will also keep track of the current navigation stack so that you can easily use the ‘CanGoBack’ property and ‘GoBack()’ method to traverse backwards through the previously visited pages.

For example we could add methods to our BrowsePhotos view model as such,


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

Summary


I have shown above how the Cocoon navigation framework allows you to easily construct a page based navigation structure for applications based upon the MVVM pattern. I have of course glossed over how you navigate to the first page of your application. I will discuss this further next time.

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

Sunday, April 22, 2012

Using MEF in Metro-style applications

Update 23 Aug 2012:

Since I originally wrote this post the standard .Net framework MEF implementation is no longer accessible from Windows 8 Windows Store applications. Instead MEF support is released out-of-band on NuGet as a specific "MEF for web and Windows Store apps" package. Once you have added this to your Windows 8 projects there is a slightly different programming model. For more information see the Microsoft.Compostion documentation.

In brief, you can set up composition with,

var configuration = new ContainerConfiguration()
        .WithAssembly(typeof(App).GetTypeInfo().Assembly);
var compositionHost = configuration.CreateContainer();
compositionHost.SatisfyImports(this);

Original post follows,  

In a slight change from talking about the Cocoon framework, today I’m going to discuss how you may use MEF (the Managed Extensibility Framework) in Windows 8 Metro-style applications. Hopefully the reason for this deviation will become clear in my next post.

What Is MEF?

I’m not going to explain MEF in detail as this has been discussed many times before and is described on MSDN. Succinctly, taken directly from the MEF CodePlex page,
The Managed Extensibility Framework (MEF) is a composition layer for .NET that improves the flexibility, maintainability and testability of large applications. MEF can be used for third-party plugin extensibility, or it can bring the benefits of a loosely-coupled plugin-like architecture to regular applications.
For Windows 8 Metro-style app developers it is the loosely-coupled architecture that is of most interest (since third-party extensibility will not be applicable to application packages delivered through the Windows Store). This allows the individual components of your application to be designed, written and tested separately. The instantiation, lifetimes and connections between components is then managed by MEF at runtime.

Using MEF in Windows 8 Metro-Style Applications

The good news is that MEF is included in the .Net base class libraries as part of the Metro-style application profile so is included in-the-box for all such applications. Unfortunately if you look at the documentation you will see references to ‘Assembly.GetExecutingAssembly()’ that is not available in the Metro-profile,

// Does not work in Metro-style applications
 
var catalog = new AssemblyCatalog(System.Reflection.Assembly.GetExecutingAssembly());

All is not lost however, as you can access the main application assembly using,

// This does work in Metro-style applications!
 
var catalog = new AssemblyCatalog(typeof(App).GetTypeInfo().Assembly);

Note that since GetTypeInfo() is an extension method on 'Type' you will have to add "using System.Reflection;" to the top of your source file. You can also reference other assemblies simply by picking a type contained in that assembly and replacing ‘App’ in the above snippet.

Therefore a more complete snippet that would find and compose all imports in the current class is,


var catalog = new AssemblyCatalog(typeof(App).GetTypeInfo().Assembly);
var compositionService = catalog.CreateCompositionService();
compositionService.SatisfyImportsOnce(this);


Summary

Hopefully this post will help anybody trying to integrate MEF with their Windows 8 Metro-style app development. Ultimately there is an ‘ApplicationCatalog’ that should allow you to generate a catalog from all assemblies within the app package however there is a known bug in the Consumer Preview bits.

Sunday, April 15, 2012

Using the Cocoon Data Framework

Over the last series of posts I have discussed the Cocoon data framework. This aims to simplify the retrieval and display of data sets within Windows 8 Metro style applications. In particular it assists with pulling data from remote systems via typical page-based web APIs and displaying them as continuous lists.
The posts so far have covered,

The Cocoon Sample Application

Included with the Cocoon source code (available from Codeplex) is a sample application that demonstrates there principles. This application is a simple Flickr viewer that displays the current list of “interesting” photos according to the Flickr API. Note that to compile this application you will need to register for a Flickr API key here and place this in the ‘FLICKR_API_KEY’ constant within the ‘Data/FlickrApi.cs’ file.
In this application the FlickrApi class provides basic access to the Flickr API with a single method GetInterestingPhotos() [Note: This is for demonstration purposes only and is not designed to demonstrate good practice for creating a web API client]

namespace Cocoon.Sample.Data
{
    public partial class FlickrApi
    {
        // *** IMPORTANT : YOU MUST ENTER YOUR API KEY BELOW! ***
        public const string FLICKR_API_KEY = "ENTER YOUR FLICKR API KEY HERE";
 
        public async Task<FlickrPhotoPage> GetInterestingPhotos(int page, int perPage)
        {
            ...
        }
    }
}

You will notice that this retrieves data in a paged manner, passing in the page to return as an argument and returning a FlickrPhotoPage as a result. Note also that since this is an asynchronous method call the result is returned as a Task. In the UI however we have a single scrollable list of photos, so we will use the Cocoon data framework to link these together.

Creating a New DataListSource

It is recommended that when you are using the Cocoon data framework you expose the IDataListSource implementations though a data source singleton class. Since data list sources can perform some caching of the data this allows several pages of your application to use the same underlying source. In the sample application this it the FlickrDataSource class.

namespace Cocoon.Sample.Data
{
    public class FlickrDataSource
    {
        // *** Fields ***
 
        private FlickrApi flickrApi = new FlickrApi();
        private IList<FlickrPhoto> interestingPhotos;
 
        // *** Methods ***
 
        public IList<FlickrPhoto> GetInterestingPhotos()
        {
            // Create a single instance of the interesting photos list
            // This can then be shared between multiple view models
 
            if (interestingPhotos == null)
            {
                InterestingPhotosDataListSource dataListSource = new InterestingPhotosDataListSource(flickrApi);
                interestingPhotos = (IList<FlickrPhoto>)new VirtualizingDataList<FlickrPhoto>(dataListSource);
            }
 
            return interestingPhotos;
        }
    }
}

Here we simply create an instance of our FlickrApi class along with a lazily generated InterestingPhotosDataListSource object. Whilst you can expose this to your rest of your application as is, here we also create a VirtualizingDataList<FlickrPhoto> passing the data list source into the constructor. Since this implements IList<FlickrPhoto> we can data bind to this in our UI.
The most interesting part of this is the InterestingPhotosDataListSource class – this is the class that you will need to write for each of the lists of data you wish to expose through the Cocoon data framework. As we have already discussed the Flickr API exposes the interesting photos feed as a series of pages, therefore we will derive from PagedDataListSource<FlickrPhoto>.
The three methods that we need to implement are FetchCountAsync, FetchPageSizeAsync and FetchPageAsync. Often however, as in this case, you will find that the number of items and page size are returned as part of the API call for returning the first page. Hence we only need to write an implementation of FetchPageAsync and use this to write the other two methods.


namespace Cocoon.Sample.Data
{
    public class InterestingPhotosDataListSource : PagedDataListSource<FlickrPhoto>
    {
        // *** Fields ***
 
        private FlickrApi flickrApi;
 
        // *** Constructors ***
 
        public InterestingPhotosDataListSource(FlickrApi flickrApi)
        {
            this.flickrApi = flickrApi;
        }
 
        // *** Overriden Base Methods ***
 
        protected override Task<DataListPageResult<FlickrPhoto>> FetchCountAsync()
        {
            return FetchPageAsync(1);
        }
 
        protected override Task<DataListPageResult<FlickrPhoto>> FetchPageSizeAsync()
        {
            return FetchPageAsync(1);
        }
 
        protected async override Task<DataListPageResult<FlickrPhoto>> FetchPageAsync(int pageNumber)
        {
            FlickrPhotoPage flickrPage = await flickrApi.GetInterestingPhotos(pageNumber, 20);
            return new DataListPageResult<FlickrPhoto>(flickrPage.Total, flickrPage.PerPage, flickrPage.Page, flickrPage.Photos);
        }
    }
}


In the FetchPageAsync(…) method we directly call the FlickrAPI.GetInterestingPhotos method (using the new C# async support). The result is then returned as a DataListPageResut<T> with the total number of items, the number of items per page, the page number returned, and a list of the items within that page.

Data Binding to the Data List

Since in this sample application we are using the MVVM pattern the user interface is split into two parts, the ‘InterestingPhotosPage.xaml’ and the ‘InterestingPhotosViewModel.cs’. In the view model we simple call FlickrDataSource.GetInterestingPhotos method that we wrote earlier and expose this IList<FlickrPhoto> as a property of the view model.

this.InterestingPhotos = flickrDataSource.GetInterestingPhotos();


And in the XAML we bind to this property as you would any other collection,


<CollectionViewSource
            x:Name="itemsViewSource"
            Source="{Binding InterestingPhotos}"/>

Summary

I hope that I have shown above a brief insight into the power of the Cocoon data framework. We started by writing a simple “data list source” implementation describing how to access data from a paged web UI. The framework then allows you to easily expose this as a list that can be data bound to a UI, with support for virtualization and ISupportPlaceholder for free.