Browse by Tags

All Tags » MEF   (RSS)

I created a quick video to help you get started with using Jounce. The video starts with a blank slate, steps through installation of Jounce and the creation of a sample view model for a simple contact record that includes validation.

You can access the video directly at http://vimeo.com/jeremylikness/jounce-getting-started, or view it below:

Jounce: Getting Started from Jeremy Likness on Vimeo.

Jeremy Likness

I'm pleased to announce the official release of Jounce 2.0 for Silverlight 5. There are quite a number of new features available that I'll review in this post. Most significantly, of course, the code base has been updated specifically to target Silverlight 5. A number of bug fixes, feature requests, and Silverlight 5 features have been added. The DLL for Jounce is still just under 100 KB for release so it remains nimble and lightweight.

There are two ways you can install the latest. Zip over to Jounce at CodePlex to download the binaries and/or the full source. Or, jump into NuGet and install the Jounce package. The package is set up to wire in a default application. To get this functionality, follow these simple steps:

  1. Create a new Silverlight application. I recommend the basic "Silverlight Application" template as I haven't tested with any others, and it doesn't matter if you host it in a web site and/or choose to use WCF RIA services.
  2. Delete the App.xaml and MainPage.xaml files. Trust me on this one.
  3. Jump into the package manager console and type Install-Package Jounce.
  4. Hold down CTRL and press F5 and you should see a welcome message. That's it. You are ready to write your Jounce application.

What's New

The code base is now CLS compliant.

The application service used to wire Jounce now exposes some configuration properties. You can use this to have Jounce ignore unhandled exceptions (by default, it will intercept these and publish them as a message instead) and also to set the debug level. These used to be parsed from the parameters from the object tag but obviously this did not make sense for OOB applications.

When dynamically loading XAP files (i.e. extension or plugin modules) you can specify a callback that Jounce will call to report progress. This allows you to have more control over the extension points and display a progress message to the end user for example.

The processing of the XAP file URL was updated to allow query strings. This is a common method to dynamically serve up XAP files and/or to manage updates for OOB applications. Jounce used to choke on this but the code was updated to gracefully handle this when you specify the URL to the XAP to download.

You no longer have to derive your view model from the BaseViewModel class. The only requirement for the framework to work is for you to implement the IViewModel interface. This will help developers who wanted to provide their own base class services and found it difficult due to the face you cannot derive from more than one base class (hey, I managed to sneak in a basic interview question).

You can specify an option using metadata to automatically call Deactivate on your view model when the corresponding view is unloaded (i.e. if the Unloaded event fires). This allows you to perform clean up automatically when the view goes out of scope.

You can now map a view to a view model in three ways. You can export a ViewModelRoute, you can fluently bind them using a new interface, and you can specify the view model in XAML. The new MapToViewModel custom markup extension allows you to specify the view model name, whether you want a shared or non-shared copy, and whether the Deactivate method should be called when the view is unloaded. This makes it possible to use templates that bind to new instances of view models.

There is additional support for the OOB windows. You can append parameters to the navigation payload or use some fluent extension methods to specify the title and size of a view and have it loaded into a separate window instead of a region. You can also raise events with a title to set the title of the HTML page (in browser) or OOB application (out of browser). To further support OOB, there are additional attributes you can query on the base view model to determine if the application is running out of browser and whether or not it is installed on the user machine.

There is a new class available called CustomType that allows you to construct a dynamic type that is bindable to view models. For example, you might parse a JSON object and use this type to build up the object. It features methods to add new properties and fetch them and will also act as a dictionary with an indexer. It uses an underlying helper class that takes advantage of Silverlight 5's ICustomTypeProvider. You can use the source as a template to build your own custom types (or derive from it instead).

I will update documentation and examples as I can moving forward. My book, Designing Silverlight Business Applications, has many examples of building applications using Jounce including WCF RIA. Thanks everyone for their patience and support of this project!

Jeremy Likness

I've been building enterprise applications for more than a decade now, and have specialized in Silverlight line of business applications for the past several years. The term "enterprise" seems to inspire images of complex, large, difficult-to-maintain software systems but a well-written system doesn't have to suffer from the extra complexity. One question I receive over and over again is what a good resource is to learn best practices for building Silverlight applications that target line of business. The market is just now starting to come out with books and tutorials that address these topics but for the longest time you had to scour to find most of your information in blog posts or tweets. I decided to take on two projects to fill two very specific gaps and I'm excited to share the details with you in this blog post.

The first project reaches past Silverlight and addresses a framework I believe was game-changing when introduced with .NET 4.0: the Managed Extensibility Framework (MEF). I partnered with Addison-Wesley to produce a LiveLessons video series and ended with over 4 hours covering the fundamentals of MEF.

I learned about the Managed Extensibility Framework (MEF) when it was in early preview. The first project that I used it for that went to production was the 2010 Winter Olympics in Vancouver. It helped our team build out reporting modules quickly and easily. It did not take long for me to discover how powerful it was for Silverlight applications. I have since used it in projects ranging from SharePoint WebPart integration to the slate application our company developed for Rooms to Go.

One of the more popular posts on my blog was the 10 reasons to use the Managed Extensibility Framework article I wrote in April of 2010. MEF is also the foundation for the MVVM framework I wrote and released as the open source project Jounce. While I've found it to be a powerful framework that is bundled as part of the runtime (it's not a third-party add-on, but shipped with everything else when you installed .NET and Silverlight) there has been one nagging problem: lack of documentation.

I can't tell you how many times I've been asked where I learned about the framework (through blog posts) or where I found best practices (trial, error, and talking to others who used the framework) and what the best book about MEF is to buy (I don't know). So when Addison-Wesley (Pearson) approached me about a video tutorial as part of their LiveLessons Series to cover fundamentals of the framework, I was ecstatic.


For several months I spent a few hours after work and over the weekends building sample projects, recording screen casts, and putting together a curriculum that I felt would provide developes with everything they need to know to be proficient with using MEF. I wanted to be sure you learned when to use it and when not to use it. My goal was to share all of the problems I've faced building enterprise software that MEF was able to solve, and package the recipes I've used to solve common problems.

The end result is the Fundamentals of the Managed Extensibility Framework. Feel free to click on the link and take a peek at the product, but I also want to be sure you know about the free sample that covers Lesson 7 about Silverlight. It is an excerpt from the full lesson but will give you insights into how the screen casts and lessons work to decide if it's presented in a way suited to your learning style. I am very excited about what I was able to cover. Click here to watch the free sample.

The program starts by guiding you through a reference application that uses most of the features of MEF, including discovery, lifetime management, extensibility, and metadata. I then go into the details of imports and exports, parts, catalogs, and containers. I focus specifically on discovery, extensibility using a plug-in model, and provide samples for understanding how MEF manages the lifetime of objects. I cover collections, recomposition, composition batches, and debugging then focus on both flavors of metadata (weakly and strongly typed). I have a full lesson dedicated to the specific uses of MEF in Silverlight, and conclude with a set of recipes that demonstrate common problems I've solved in real world projects using MEF.

You can also watch the course as part of your Safari books online subscription.

I hope this helps fill a much-needed gap in documentation and tutorials about the Managed Extensibility Framework. For those of you who do invest in the tutorial, I would greatly appreciate you sharing your honest comments and feedback using the comments at the end of this post. That will help me learn how to make it better and more importantly help others decide what value they may gain from the tutorial . Watch the 20-minute sampler here and take a look at the full package here. Access the tutorial through Safari Books online at this link.

Jeremy Likness

One exciting new feature of Silverlight 5 is the ability to create custom markup extensions. Markup extensions are a part of XAML. Whenever you see a notation that starts and ends with a brace, you are viewing a markup extension. Markup extensions exist to pass information to properties in the XAML that the XAML parser can use when generating the object graph.

A commonly used example of markup extensions is the data-binding syntax. In the following XAML snippet, the data-binding uses a markup extension to specify that a binding is being defined.

<TextBlock Text="{Binding Path=Name,Mode=TwoWay}"/>

The brace begins the extension, followed by the name of the class that will handle the extension, followed by any parameters you wish to pass. You can do that same thing in code behind by creating a Binding object directly and setting it's properties.

So how are markup extensions useful? They provide a hook to perform functionality that would be impossible or overly complicated using traditional approaches such as attached properties or behaviors. One popular use of markup extensions is to provide access to static classes that otherwise are not available in XAML. A common reason to do that would be to access a service locator - for example, to generate your view model.

To illustrate how to create your own, I decided to use the Managed Extensibility Framework as an example. It is often challenging to insert classes that are managed by MEF into XAML because they require a step known as "composition" to wire dependencies. With a custom markup extension, however, that limitation goes away because the extension can perform the composition call!

Because MEF does not work the same way in the designer as it does in the runtime, I also wanted to provide a fallback mechanism for design-time views. The markup extension will take a component type (a fully qualified type name) and an optional design type. In the designer, if the design type is specified, it creates an instance and returns it. If not, it creates an instance of the component and returns it. During runtime, when not in the designer tool, the extension takes the additional step of calling MEF to compose the dependencies on the target component.

While the following example view model could be created in XAML, the properties would never get set because they are imported from somewhere else:

public class MainViewModel
{        
    [Import("Name")]
    public string Name { get; set; }

    [Import("Email")]
    public string Email { get; set; }
        
}

The values are exported in another class (just for the sake of this example):

public class Exports
{
    [Export("Name")]
    public string Name
    {
        get { return "Jeremy Likness"; }
    }

    [Export("Email")]
    public string Email
    {
        get { return "jeremy@jeremylikness.com"; }
    }
}

The design-time view model returns some sample data:

public class DesignViewModel
    {
        public string Name { get { return "Joe Designer"; } }
        public string Email { get { return "joe@acme.123"; } }
    }

Now for the custom markup extension. It should inherit from MarkupExtension and the name should end with Extension (similar to the way dependency property definitions end with the word Property). There is just one method to implement and you can provide your own properties. Here is the MEF composition extension:

public class MefComposerExtension : MarkupExtension 
{
    public string Component { get; set; }
    public string Designer { get; set; }

    public override object ProvideValue(IServiceProvider serviceProvider)
    {            
        if (Component == null)
        {
            throw new Exception("Component required.");
        }
            
        if (DesignerProperties.IsInDesignTool)
        {
            return Activator.CreateInstance(Type.GetType(string.IsNullOrEmpty(Designer) ? Component : Designer));
        }

        var instance = Activator.CreateInstance(Type.GetType(Component));
        CompositionInitializer.SatisfyImports(instance);
        return instance;
    }
}

Notice that the first check is whether it is in the design tool. If so, it will return an instance of either the design parameter or the component. If not in the design tool, it will create an instance of the component, and then use MEF to satisfy the imports. To use the custom markup extension, you simply add a reference to the namespace and then reference the name of the extension inside braces. Here is the XAML for the namespace:

<UserControl ... xmlns:local="clr-namespace:TypeConverter" .../>
And here is the XAML for the main page that uses the markup extension to set the data context:
<Grid x:Name="LayoutRoot" Background="White" 
        DataContext="{local:MefComposer Component='TypeConverter.MainViewModel',Designer='TypeConverter.DesignViewModel'}">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="Auto"/>            
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto"/>
        <ColumnDefinition Width="Auto"/>
    </Grid.ColumnDefinitions>
    <TextBlock Grid.Row="0" Grid.Column="0" Text="Name: "/>
    <TextBlock Grid.Row="1" Grid.Column="0" Text="Email: "/>
    <TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding Name}"/>
    <TextBlock Grid.Row="1" Grid.Column="1" Text="{Binding Email}"/>        
</Grid>

As you can see, it is fairly straightforward - simply the namespace and the name of the extension, wherever the returned value should be inserted. This works fine in the preview version of Blend. You can see the grid's datacontext property correctly resolve the design view model:

And the design-time data in on the design surface:

Of course, the most important step is to run this and see it in action. Sure enough, at runtime it will not only create the view model instance, but compose the parts through MEF and find the imported properties:

Obviously this feature is extremely powerful. While it has existed for some time in WPF, it is now available for Silverlight developers and promises to create many new possibilities when integrated in code moving forward.

Grab the source code for this project here.

Jeremy Likness

Jounce is the result of building composite Silverlight enterprise applications for a variety of verticals since Silverlight 3.0 and finding the common problems that needed to be solved. I found many frameworks to be too heavy for the task and always wondered why more did not tap into the native advantages that the Managed Extensibility Framework brings. So, I began porting my framework around as a core engine for projects and finally decided to make it available to provide guidance for building these types of applications using the MVVM pattern and MEF.

You can see concepts about Jounce echoed in many of my posts, but the easiest way to summarize the post-release topics is to follow the jounce tag on this blog. While bits and pieces have been posted over time, probably the first comprehensive peek at what Jounce would look like happened as the result of my 2010 CodeStock presentation. I posted an application called XFit to demo a live modular application that was more than just a button and a text file. Over time that has been refined and advanced through input from the community as well as fellow developers who are using Jounce in their own projects.

I'd like to give special thanks to Page Brooks for giving Jounce a logo, adding tests, testing the heck out of it and also giving us a wonderful project template (available on the downloads page).

Anyway I hope this guidance finds you well, and provides a nice, lightweight set of examples and patterns for building Silverlight applications with the MVVM pattern and MEF. Go ahead and grab the source, read the docs, and join the discussions at the Jounce CodePlex site. Thanks!

Jeremy Likness

Even if you don't use Jounce, this post will help you better understand how to create non-shared views and view models with the Managed Extensibility Framework (MEF). The architecture I prefer in Silverlight is to keep a shared view and view model where possible. If only one instance of the view is visible at a time, the view model can be manipulated to provide the correct bindings and information when different data is selected for that view. Keeping a single view avoids issues with waiting for multiple views in garbage collection or keeping track of multiple views that might not unhook from the visual tree correctly.

There are several cases where this is not plausible. In a master/detail scenario with dockable views, you may end up with multiple "detail" views on the screen. Each view requires a separate copy and possibly a separate view model as well.

Lazy Shared Views and View Models

In MEF, the Lazy<T,TMetadata> syntax is used to import multiple implementations of a contract and associated metadata. The pattern allows you to inspect the metadata before creating the object instances, so you have full control over what is happening. Jounce uses this feature to bind views and view models by inspecting the metadata and using that to examine "routes" created by the user (a route simply asserts that view "X" requires view model "Y").

The view model import looks like this:

[ImportMany(AllowRecomposition = true)]
public Lazy<IViewModel, IExportAsViewModelMetadata>[] ViewModels { get; set; }

The array can be queried with LINQ. In Jounce, the view model metadata simply provides a user-defined tag for the view model so it can be referenced without knowing the type (this is useful, for example, when the view model must be referenced before the XAP that contains it has been loaded). Here is the metadata contract:

public interface IExportAsViewModelMetadata
{
    string ViewModelType { get; }
}

Here is a simple query to get the associated information for the view model. What's important to note is that part of this information is a Lazy<T> property for the view model. When the value property is accessed, the view model is created, but any subsequent references will use the same copy, or a "shared" view model:

var vmInfo = (from vm in ViewModels
                where vm.Metadata.ViewModelType.Equals(viewModelType)
                select vm).FirstOrDefault();

Using the Export Factory

To get a fresh copy, instead of using the lifetime management attributes that MEF provides, I chose to go with the ExportFactory. Unlike a Lazy import, the export factory does not provide a copy of the target object. Instead, it provides the means of creating a new copy. In other words, you are provided with an actual factory to generate new copies. The convention for this is very similar to the lazy version:

[ImportMany(AllowRecomposition = true)]
public List<ExportFactory<IViewModel, IExportAsViewModelMetadata>> ViewModelFactory { get; set; }

Notice that again metadata exists, so you can inspect the factory to make sure it is the right factory before asking it to generate a new object. Now it is a simple matter to query for the right view model and then ask the export factory to generate a new copy:

public IViewModel GetNonSharedViewModel(string viewModelType)
{
    return (from factory in ViewModelFactory
            where factory.Metadata.ViewModelType.Equals(viewModelType)
            select factory.CreateExport().Value).FirstOrDefault();
}

The Ties that Bind

Now you are able to generate a view and a view model on the fly. Jounce adds helper methods to view models to help synchronize with the view. For example, InitializeViewModel is called the first time the view model is bound to the view, and ActivateView is called when a view is loaded that is bound to the view model. There is also a binding for the visual state manager so that the view model can transition states without being aware of the view.

In order to bind property, Jounce provides a simple mechanism for generating a new copy of a view that allows you to pass in the data context:

UserControl GetNonSharedView(string viewTag, object dataContext);

If you have simple views, this can take a model or other class that is not a view model and will still bind it to the data context for you. However, if the bound object is a Jounce view model, the binding will add some additional calls and hooks to ensure that visual states and other bindings are updated as needed. This is what the view creation method looks like:

public UserControl GetNonSharedView(string viewTag, object dataContext)
{
    var view = (from factory in ViewFactory
                where factory.Metadata.ExportedViewType.Equals(viewTag)
                select factory.CreateExport().Value).FirstOrDefault();

    if (view == null)
    {
        return null;
    }

    _BindViewModel(view, dataContext);
                
    var baseViewModel = dataContext as BaseViewModel;
    if (baseViewModel != null)
    {
        baseViewModel.RegisterVisualState(viewTag,
                (state, transitions) => JounceHelper.ExecuteOnUI(
                  () => VisualStateManager.GoToState(view, state, transitions)));
        baseViewModel.RegisteredViews.Add(viewTag);
        baseViewModel.Initialize();
        RoutedEventHandler loaded = null;
        loaded = (o, e) =>
                        {
                            ((UserControl) o).Loaded -= loaded;
                            baseViewModel.Activate(viewTag, new Dictionary<string, object>());
                        };
        view.Loaded += loaded;
    }
    return view;
}

Notice the use of the variable to allow unbinding the lambda expression after the first loaded event is fired (the load event is triggered every time the control is placed in the visual tree, but the bindings only need to be updated once).

DataTemplate Selectors

The final step for Jounce was to create a special value converter for spinning views. This is similar to the concept I wrote about in Data Template Selector using the Managed Extensibility Framework. Only in this case, the converter will do one of two things: if passed a Jounce view model, it will automatically find the view the view model is associated with, generate a new copy of the view, and bind it, or if passed a parameter, it will create a view with the tag provided in the parameter.

The Jounce quickstart (available by grabbing the latest Jounce source download) contains an example of this. The target model is a contact class:

public class Contact
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Address { get; set; }
    public string City { get; set; }
    public string State { get; set; }
}

The view model for the model simply passes through to the underlying properties. In a full implementation, it would save the orignal model for roll back and have other options such as commands to manipulate the data:

[ExportAsViewModel("ContactVM")]
public partial class ContactViewModel : BaseViewModel
{
    public ContactViewModel()
    {
        if (DesignerProperties.IsInDesignTool)
        {
            SetDesignerData();
        }
    }

    public Contact SourceContact { get; set; }
        
    public string FirstName
    {
        get { return SourceContact.FirstName; }
        set
        {
            SourceContact.FirstName = value;
            RaisePropertyChanged(()=>FirstName);
        }
    }

    public string LastName
    {
        get { return SourceContact.LastName; }
        set
        {
            SourceContact.LastName = value;
            RaisePropertyChanged(()=>LastName);
        }
    }

    public string Address
    {
        get { return SourceContact.Address; }
        set
        {
            SourceContact.Address = value;
            RaisePropertyChanged(()=>Address);
        }
    }

    public string City
    {
        get { return SourceContact.City; }
        set
        {
            SourceContact.City = value;
            RaisePropertyChanged(()=>City);
        }
    }

    public string State
    {
        get { return SourceContact.State; }
        set
        {
            SourceContact.State = value;
            RaisePropertyChanged(()=>State);
        }
    }
}

The view simply shows the last name, first name in bold and then the address on the second line:

<Grid x:Name="LayoutRoot" Background="White" d:DataContext="{d:DesignInstance vm:ContactViewModel, IsDesignTimeCreatable=True}">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="Auto"/>
    </Grid.RowDefinitions>
    <StackPanel Orientation="Horizontal" Margin="5">
        <TextBlock FontWeight="Bold" Text="{Binding LastName}"/>
        <TextBlock FontWeight="Bold" Text=", "/>
        <TextBlock FontWeight="Bold" Text="{Binding FirstName}"/>
    </StackPanel>
    <StackPanel Orientation="Horizontal" Grid.Row="1" Margin="5">
        <TextBlock Text="{Binding Address}"/>
        <TextBlock Text=" "/>
        <TextBlock Text="{Binding City}"/>
        <TextBlock Text=", "/>
        <TextBlock Text="{Binding State}"/>
    </StackPanel>
</Grid>

Here is the view with sample data in the designer:

The view itself is exported in the code-behind, as well as a binding mapping it to the corresponding view model:

[ExportAsView("ContactView")]
public partial class ContactView
{
    public ContactView()
    {
        InitializeComponent();
    }

    [Export]
    public ViewModelRoute Binding
    {
        get { return ViewModelRoute.Create("ContactVM", "ContactView"); }
    }
}

The main view model starts out by providing a list of contacts (this one generates sample data for the sake of the demo):

[ExportAsViewModel("MainVM")]
public class MainViewModel : BaseViewModel
{
    private readonly List<Contact> _sampleData = new List<Contact>
                                            {
                                                new Contact
                                                    {
                                                        FirstName = "Jeremy",
                                                        LastName = "Likness",
                                                        Address = "1212 Hollywood Blvd",
                                                        City = "Hollywood",
                                                        State = "California"
                                                    },
                                                new Contact
                                                    {
                                                        FirstName = "John",
                                                        LastName = "Doe",
                                                        Address = "12 Driving Parkway",
                                                        City = "St. Petersburg",
                                                        State = "Florida"
                                                    },
                                                new Contact
                                                    {
                                                        FirstName = "Jane",
                                                        LastName = "Doe",
                                                        Address = "1414 Disk Drive",
                                                        City = "Lead",
                                                        State = "South Dakota"
                                                    },
                                                new Contact
                                                    {
                                                        FirstName = "Sam",
                                                        LastName = "Iam",
                                                        Address = "12 Many Terrace",
                                                        City = "Figment",
                                                        State = "Imagination"
                                                    },

                                            };

    public MainViewModel()
    {
        Contacts = new ObservableCollection<Contact>(_sampleData);
    }

    public ObservableCollection<Contact> Contacts { get; private set; }
}

The problem is that our view requires a view model (it might handle edits or deletes in the future, so the model itself isn't enough). No problem! First, create a set of extension methods: one to pass the contact into a view model, and another to handle a list of contacts that will return a list of contact view models:

public static ContactViewModel ToViewModel(this Contact contact, IViewModelRouter router)
{
    var vm = router.GetNonSharedViewModel("ContactVM") as ContactViewModel;

    if (vm == null)
    {
        throw new Exception("Couldn't create view model for contact.");
    }

    vm.SourceContact = contact;
    return vm;
}

public static IEnumerable<ContactViewModel> ToViewModels(this IEnumerable<Contact> contacts, IViewModelRouter router)
{
    return contacts.Select(contact => contact.ToViewModel(router)).ToList();
}

Notice the router is used to get a non-shared copy of the view model, then the contact is passed in. The list function simply applies the conversion to the entire list. Of course, the view model tag can be specified as a constant to avoid the "magic string" and make it easier to refactor down the road.

The main view model can now be tweaked to expose a list of view models:

public IEnumerable<ContactViewModel> ViewModels
{
    get { return Contacts.ToViewModels(Router); }
}

It's a very simple conversion using the helper extension methods. To ensure the enumerable is re-loaded anytime the underlying collection changes, simply add this after the observable collection is created:

Contacts.CollectionChanged += (o, e) => RaisePropertyChanged(() => ViewModels);

Next the XAML is updated to use the special converter:

<ListBox ItemsSource="{Binding ViewModels}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <ContentControl Content="{Binding Converter={StaticResource ViewConverter}}"/>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

In this example, the binding is a list of contact view models. The special converter will inspect the binding, figure out the view model and find the corresponding view (the contact view we showed earlier), then create a new copy of the view and bind the view model. This could also have been done directly with the contact model if a view model wasn't being used. More importantly, if the list is type IViewModel it can contain different types of view models, and the converter will automatically find the appropriate view - this is a "View Model First" approach to binding but serves as a data template selector.

When the application is run, the non-shared views and view models spin up and bind as expected:

The full source code for Jounce and the example shown here is available from the Jounce CodePlex site.

Jeremy Likness

The Jounce framework specifically relies on the Managed Extensibility Framework to help solve MVVM concerns. I recently presented an introduction to MEF and explained what I believe are the four core problems it solves:

  1. Discovery — it's good to decouple, but at some point you need to provide an implementation, and MEF does a great job of discovering implementations, wiring their dependencies, and providing them to you
  2. Lifetime management — instead of mangling classes to follow the singleton pattern, MEF provides you with a way to manage the lifetime of those classes through attributes. You can define whether or not an instance is shared or generated both where you define the class and when you require it, giving you plenty of flexibility over how the class is managed without having to change it
  3. Extensibility — this often throws people off because they believe it is just for plug-ins. The fact is MEF has a very easy, built-in means for dynamically loading XAP files and integrating them into your main application, making modularity and extensibility easy to implement
  4. Metadata — Jounce uses this extensively: the ability to tag an implementation with additional data and filter that data to route implementations and only create them on demand when needed. This is how Jounce manages views, view models, and regions

The one drawback to using MEF is troubleshooting. Sometimes the composition step — when MEF scans all of the requirements and contracts in a project and maps in the implementations that satisfy them — can fail and it's not immediately clear why. MEF uses stable composition, so if any part of a hierarchy fails to import the correct references, the entire composition step will fail. This is intentional so you don't get unexpected behavior when you are asking for a dependency and it can't be provided.

Fortunately, MEF provides plenty of hooks to debug what is going on when composition occurs. Jounce uses a special debug container that can actually be used independently of Jounce for your MEF projects. It is in a class called MEFDebugger and you can browse the source at CodePlex here.

The class constructor takes in a container and a logging mechanism. The logger is what messages are written to. The default logger supplied by Jounce simply emits debug statements, but it can be replaced by any implementation of your own and wired into any third-party logger available for Silverlight. The container is the main MEF container. Jounce configures this container when the application is started and passes it into the MEF debugging container. The debug container is closed — there are no additional methods or properties — so you simply maintain a reference to keep it alive for the duration of the application.

The first thing the debugger does is hook into an ExportsChanged event. This fires any time a new XAP file is loaded or the catalog is modified in any way that results in a change of exports. This is when recomposition comes into play and typically happens the first time the container is composed and subsequently whenever a dynamic XAP file is loaded.

Whenever the exports change, the debugger simply walks through the added parts, the removed parts, and the contract changes and emits those. It also examines the metadata in the exports and writes those out as well. Using the ToString override on your classes helps provide more friendly/readable information when the values of attributes or exports themselves are written out.

The call to debug the catalog simply walks through all import and export definitions and does the same thing. The end result is that you receive a stream of debug information explaining exactly what catalogs are included, what parts are found, the imports, exports, and metadata found in the parts, and any new information when recomposition occurs.

The easiest way to see this in action is to run the quick start. Set the DynamicXAPCalculatorTestPage.aspx page in the web project as the start page to launch this example. Jounce will parse the init params for the debug level to use in the logger. Add this init parameter to ensure you receive verbose debug information:

<param name="initParams" value="Jounce.LogLevel=Verbose" />

When you run the application in the debugger, you'll see very explicit container information sent to the debug window. For example, here is the part that represents the view shell. Notice it requires an import for the event aggregator, and exports a user control and a binding. You can also see the associated metadata, which in this case is the flag marking this as IsShell=true.

2/25/2011 6:44:47 AM Verbose Jounce.Core.MefDebugger :: MEF: Found part: DynamicXapCalculator.Views.Shell
2/25/2011 6:44:47 AM Verbose Jounce.Core.MefDebugger ::    With import: DynamicXapCalculator.Views.Shell.EventAggregator (ContractName="Jounce.Core.Event.IEventAggregator")
2/25/2011 6:44:47 AM Verbose Jounce.Core.MefDebugger ::    With export: DynamicXapCalculator.Views.Shell (ContractName="System.Windows.Controls.UserControl")
2/25/2011 6:44:47 AM Verbose Jounce.Core.MefDebugger ::       With key: ExportedViewType = Shell
2/25/2011 6:44:47 AM Verbose Jounce.Core.MefDebugger ::       With key: IsShell = True
2/25/2011 6:44:47 AM Verbose Jounce.Core.MefDebugger ::       With key: Category = 
2/25/2011 6:44:47 AM Verbose Jounce.Core.MefDebugger ::       With key: MenuName = 
2/25/2011 6:44:47 AM Verbose Jounce.Core.MefDebugger ::       With key: ToolTip = 
2/25/2011 6:44:47 AM Verbose Jounce.Core.MefDebugger ::       With key: ExportTypeIdentity = System.Windows.Controls.UserControl
2/25/2011 6:44:47 AM Verbose Jounce.Core.MefDebugger ::    With export: DynamicXapCalculator.Views.Shell.Binding (ContractName="Jounce.Core.ViewModel.ViewModelRoute")
2/25/2011 6:44:47 AM Verbose Jounce.Core.MefDebugger ::       With key: ExportTypeIdentity = Jounce.Core.ViewModel.ViewModelRoute

The calculator provides some basic functions for addition and subtraction. Multiplication and division are loaded in a dynamic XAP file. Click the link to load the advanced functions, and watch the debug window. You'll notice that additional exports are added to the container:

2/25/2011 6:48:16 AM Verbose Jounce.Core.MefDebugger :: Added Export: DyanmicXapCalculatorAdvanced.AdvancedFunctions.AddCommand (ContractName="System.Tuple(System.String,System.Windows.Input.ICommand)")
2/25/2011 6:48:16 AM Verbose Jounce.Core.MefDebugger ::       With key: ExportTypeIdentity = System.Tuple(System.String,System.Windows.Input.ICommand)

You'll also find that the contract for the commands that drive the calculator has changed (because it now has additional exports to use):

2/25/2011 6:48:16 AM Verbose Jounce.Core.MefDebugger :: Changed contracts:
2/25/2011 6:48:16 AM Verbose Jounce.Core.MefDebugger ::  ==>System.Tuple(System.String,System.Windows.Input.ICommand)
2/25/2011 6:48:16 AM Verbose Jounce.Core.MefDebugger ::  ==>System.ComponentModel.Composition.Contracts.ExportFactory

As you can see, a lot of detailed information is provided that most of the time will help you track down exactly where the imports, exports, and metadata that make up parts is coming from. By examining what is generated and what your code is expecting, you can quickly track down where composition errors may be coming from. With your own logger implementation you can easily route these messages to the server, a text file, or even store them in isolated storage for later inspection.

Jeremy Likness

Sometimes it makes sense to have multiple types of views contained within a list or region. In WPF, a data template selector can help determine which template is used based on the data template, allowing a container to mix different types. It's not so straightforward with Silverlight because the DataTemplateSelector class does not exist.

There have been some excellent articles on the web with simple workarounds for this, but they often involve some sort of dictionary or hard-coded selection process. What I wanted to do was provide an example that does several things:

  • Allows you to add new templates easily simply by tagging them with attributes,
  • Is design-time friendly, and
  • Handles dependencies in the templated views, if needed

The target situation is a hypothetical social media feed that aggregates data from different types but shows them in a single list. This example mocks the data but should be sufficient to show how it could be done. Consider this screenshot which shows three different styles of presenting data in the list:

Data Template Selector in Silverlight

So, let's get started. The way I decided to handle the selector would be to use views as my "data templates" (this is similar to how Calburn.Micro does it) and tag the views with the type they handle.

I created three simple types:

Social Media Types

To wire a sample in the designer, I created a design-time model that is not built in release mode. Here is the example for a tweet:

namespace MEFDataTemplate.SampleData
{
#if DEBUG
    public class DesignTimeTweet : Tweet 
    {
        public DesignTimeTweet()
        {
            AvatarUri = new Uri("/MEFDataTemplate;component/Images/twitterprofile.png", UriKind.Relative);
            Message = "This is a tweet inside the designer.";
            Posted = DateTime.Now;
            Username = "@jeremylikness";
        }
    }
#endif
}

Now we can build out template for a tweet. I created a folder called Templates and added a user control called TweetTemplate.xaml. The XAML organizes a sample tweet like this:

    <Grid x:Name="LayoutRoot" HorizontalAlignment="Stretch" Background="White" d:DataContext="{d:DesignInstance design:DesignTimeTweet,IsDesignTimeCreatable=True}">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>            
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <StackPanel Orientation="Horizontal" Margin="5">
            <Image Margin="2" Source="/MEFDataTemplate;component/Images/twitter.png"/>
            <TextBlock VerticalAlignment="Center" Margin="2" Text="{Binding Username}"/>
        </StackPanel>
        <Image Margin="2" VerticalAlignment="Top" Source="{Binding AvatarUri}" Stretch="None" Grid.Row="1"/>
        <TextBlock Margin="5" Text="{Binding Posted,StringFormat='MM-dd-yyyy h:mm:ss'}" FontWeight="Bold" HorizontalAlignment="Right" Grid.Column="1"/>
        <TextBlock Margin="5" TextWrapping="Wrap" Text="{Binding Message}" Grid.Row="1" Grid.Column="1"/>
    </Grid>

Inside the designer, it looks like this:

Data Template inside the Designer

Now we need to tag it. If you are familiar with MEF, you know it is not straightforward to create an ExportFactory with metadata, as there is no easy way to reach the metadata and create the corresponding factory (this is what is needed to create new views for each item, rather than having a single copy). Even the Lazy feature won't work for us because the lazy value is lazy loaded, but then retains the same value. So what can we do?

We'll get to the tricky part in a second, but for now we'll export our view twice. First, we'll make a special export that allows us to tag the view with the type of entity it can handle. The metadata looks like this:

namespace MEFDataTemplate.Templates
{
    public interface IExportAsTemplateForTypeMetadata
    {
        Type TargetType { get; }        
    }
}

And the export attribute itself is implemented like this:

namespace MEFDataTemplate.Templates
{
    [MetadataAttribute]
    [AttributeUsage(AttributeTargets.Class)]
    public class ExportAsTemplateForTypeAttribute : ExportAttribute, IExportAsTemplateForTypeMetadata 
    {
        public ExportAsTemplateForTypeAttribute(Type targetType) : base(typeof(UserControl))
        {
            TargetType = targetType;            
        }

        public Type TargetType { get; set; }       
    }
}

Now, we can tag our template and let MEF know it handles Tweet objects:

namespace MEFDataTemplate.Templates
{
    [ExportAsTemplateForType(typeof(Tweet))]
    [Export]
    public partial class TweetTemplate
    {
        public TweetTemplate()
        {
            InitializeComponent();
        }
    }
}

Notice that I export the control twice. The first time is to tag the target type it can handle, and the second time is to give me an export I can work with to create the views inside the templates.

We repeat the process for the photos and blogs. Next, I need a container to help me generate new views. Remember, I can't grab both metadata and export factories, so I'll "cheat" by making a host for the export factory:

namespace MEFDataTemplate.Templates
{
    public class TemplateFactory<T>
    {
        [Import]
        public ExportFactory<T> Factory { get; set; }

        public T Instance
        {
            get
            {
                return Factory.CreateExport().Value;
            }
        }
    }
}

Essentially, when I type this class and create an instance, I can reference the Instance property and it will go to the export factory to give me a new instance. We could simplify this and just restrict T to new(), and that would work fine, but doing this also allows the type to have dependencies. If you wanted to import a logger, event aggregator, or other dependency, this mechanism supports it - and you'll be surprised at how good the performance actually is.

Now we've got some work to do. I'm going to use a value converter that takes the data type and returns the data template. We'll also bind the data to the data template. Here's what it looks like, and I'll explain what's going on below:

namespace MEFDataTemplate.Converters
{
    public class DataTemplateSelector : IValueConverter 
    {
        private const string INSTANCE = "Instance";
        const string LAYOUT_ROOT = "LayoutRoot";                                      
            
        public DataTemplateSelector()
        {
            if (!DesignerProperties.IsInDesignTool)
            {
                CompositionInitializer.SatisfyImports(this);
            }
        }

        [ImportMany]
        public Lazy<UserControl, IExportAsTemplateForTypeMetadata>[] Templates { get; set; }

        private readonly Dictionary<Type,object> _factories = new Dictionary<Type, object>();

        private readonly Dictionary<Type,Func<UserControl>> _templateFactory = new Dictionary<Type,Func<UserControl>>();

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (DesignerProperties.IsInDesignTool)
            {
                return new TextBlock {Text = "Design time row."};
            }

            FrameworkElement view = new Grid();

            if (value != null)
            {                
                if (_templateFactory.ContainsKey(value.GetType()))
                {
                    view = _templateFactory[value.GetType()]();                   
                }
                else 
                {
                        var viewType = (from t in Templates
                                        where t.Metadata.TargetType.Equals(value.GetType())
                                        select t.Value.GetType()).FirstOrDefault();
                        if (viewType != null)
                        {
                            var factory = Activator.CreateInstance(typeof(TemplateFactory<>).MakeGenericType(new[] { viewType }));
                            CompositionInitializer.SatisfyImports(factory);
                            _factories.Add(value.GetType(), factory);
                            Func<UserControl> resolver = ()=>
                                factory.GetType().GetProperty(INSTANCE).GetGetMethod().Invoke(factory, null) as UserControl;
                            _templateFactory.Add(
                                value.GetType(), resolver);
                            view = _templateFactory[value.GetType()]();
                        }
                }

                if (view != null)
                {
                    RoutedEventHandler handler = null;
                    handler = (o, e) =>
                                  {
                                      view.Loaded -= handler;
                                      ((Grid) view.FindName(LAYOUT_ROOT)).DataContext = value;
                                  };
                    view.Loaded += handler;
                }
            }

            return view;
        }       

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}

So the first thing we do is compose imports if we aren't in the designer. This will pull in all tagged views and the metadata that describes the types that they support.

Notice I have two dictionaries. One dictionary maps the target type to the TemplateFactory<T> for the view that supports the target type. Because we're dealing with generics, I only need one copy per type, so with 1,000 records I still only make three factory objects (one per type). Second, because we'll use reflection to grab the Instance property (since we can't close the generic directly) I don't want to reflect every single row. Next, I store a function that handles the result of the reflection.

When the value comes in, if we're in the designer, we just return a simple bit of text. Otherwise, we set up an empty Grid to return if our data template selection fails. You could throw an exception instead of to make this more robust. If I've already processed the type, I simply look up the function and call it to get a new view.

For the first time I find a type, we get to have some fun. First, I find the view that is intended for the target type by inspecting the metadata. This only has to be done once to get the type for the view. Next, I create an instance of the template factory. This works from the inside out for this statement:

var factory = Activator.CreateInstance(typeof(TemplateFactory<>).MakeGenericType(new[] { viewType }));

The typeof statement gets up what's called an "open generic" or a generic type that hasn't been scoped to a target type yet. In order to close the generic, we call the MakeGenericType method and pass it the type we want to close it with - in this case, the type of the template we found by inspecting meta data. We create an instance, and now we have our MEF factory for generating the view.

Because we can't close the type, we need to use reflection to find the property that grabs the instance for us:

 Func<UserControl> resolver = ()=>
                                factory.GetType().GetProperty(INSTANCE).GetGetMethod().Invoke(factory, null) as UserControl;

This uses reflection to get the property, gets the "getter" method, then invokes it for the factory object we just created and casts it as a UserControl. If you want to support other exports, you can cast this down to a base FrameworkElement if you like.

If you're really concerned with performance, you can cache the result of the GetGetMethod as an Action (storing the full function here will still call the reflection, whereas storing the result of the get will store a pointer to the actual getter without reflection - make sense?) then you could call that cached method, but I didn't see enough issues with performance to go to that level.

Finally, we wire up the DataContext. Here, we have to be careful. If we wire the Loaded event to a method, we'll lose the context of where we're at and not be able to hook the item to the data context. However, if we assign a lambda expression, we're really creating a reference from this converter to the view - which means it will never be released from memory.

So instead, we create a reference to the handler, then pass a lambda expression. The lambda expression is able to reference the item to wire to the data context, and also reference itself to unhook from the Loaded event. The result is that the control will hook to the item and then lose the event handler. This assumes the templates have a LayoutRoot, if you prefer you can connect to the user control directly.

The view model exposes a generic list of objects:

public ObservableCollection<object> SocialFeed { get; private set; }

And wires in 1,000 items randomly chosen between tweets, photos, and blog entries. You can tweak the size to test larger or smaller lists for performance. Using our selector is simple - we declare it and then use it to bind the object to a ContentControl.

    <UserControl.Resources>
        <Converters:DataTemplateSelector x:Key="Selector"/>
    </UserControl.Resources>
    <Grid x:Name="LayoutRoot" Background="White">        
        <Grid.DataContext>
            <ViewModel:MainViewModel/>
        </Grid.DataContext>
        <ListBox ItemsSource="{Binding SocialFeed}" HorizontalAlignment="Center" Width="800" VerticalAlignment="Top">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <ContentControl Width="750" HorizontalAlignment="Center" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch"
                                    Content="{Binding Converter={StaticResource Selector}}"/>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </Grid>

When you run, you see we get a nice virtualizing list box with selected data templates and the performance on my machine is fast.

From here, you can do several things. If your items implement a common interface, you might provide a default template that handles anything and then export specific templates as you implement more detailed types. Obviously you can get rid of the instance factory and the composition initialization if your views will have no dependencies. Once this is wired in place, adding a new "data template" is as easy as design it, tag it, and run it.

To quote Forrest Gump, "That's all I got to say about that." Grab the source here.

Jeremy Likness

One common request I get is how Jounce can work with the Navigation Framework.

My first reply is always, "Why do you want to use that?" As you can see in previous posts, the Jounce navigation works perfectly fine with region management to manage your needs. If you want the user to be able to "deep link" to a page, you can easily process the query string and parse it into the InitParams for the application and deal with them there.

For the sake of illustration, however, I wanted to show one way Jounce can work with an existing navigation framework. In fact, to make it easy to follow along, the quick start example works mainly from the "Navigaton Application" template provided with Silverlight.

As a quick side note, I am very much aware of the INavigationContentLoader interface. This may be the way to go and in the future I might write an adapter for Jounce, but I just don't see a compelling need to have URL-friendly links as I typically write applications that act like applications in Silverlight, not ones that try to mimic the web by having URLs.

The example here is available with the latest Jounce Source code (it's not part of an official release as of this writing so you can download it using the "Latest Version - Download" link in the upper right).

To start with, I simply created a new Silverlight navigation application.

Without overriding the default behavior, the navigation framework creates a new instance of the views you navigate to. To get around this model which I believe is wasteful and has undesired side effects, I changed the mapping for the various views to pass to one control that manages the navigation for me:

<uriMapper:UriMapper>
<uriMapper:UriMapping Uri="" MappedUri="/Views/JounceNavigation.xaml"/>
    <uriMapper:UriMapping Uri="/ShowText/{text}" MappedUri="/Views/JounceNavigation.xaml?view=TextView&text={text}"/>
    <uriMapper:UriMapping Uri="/{pageName}" MappedUri="/Views/JounceNavigation.xaml?view={pageName}"/>                        
</uriMapper:UriMapper>

Notice how I can translate the path to a view parameter, and that I am also introducing a mapping for "ShowText" that we'll use to show how you can grab parameters.

The JounceNavigation control will get a new copy every time, but by using MEF it will guarantee we always access the same container. To do this, I created NavigationContainer and it contains a single content control with a region so the region is only exported once:

<ContentControl 
                    HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
                    HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch"
                    Regions:ExportAsRegion.RegionName="MainContainer"/>

In the code-behind, I simply export it:

namespace SilverlightNavigation.Views
{
    [Export]
    public partial class NavigationContainer
    {
        public NavigationContainer()
        {
            InitializeComponent();
        }
    }
}

Now we can use this single container in the JounceNavigation control. What we want to do is attach it when we navigate to the control, and detach it when we navigate away (a control can only have one parent, so if we don't detach it, we'll get an error when the next view is created if the previous view hasn't been garbage-collected yet).

The navigation control also does a few more things to integrate with the navigation framework. It will remember the last view so it can deactivate the view when navigating away. It will default to the "Home" view but basically takes any view passed in (based on the uri mappings we defined earlier) and raises the Jounce navigation event. Provided the view targets the region in our static container, it will appear there. Normally I'd do all of this in a view model but wanted to show it in code-behind for the sake of brevity (and to show how Jounce plays nice with standard controls as well).

public partial class JounceNavigation
{
    [Import]
    public IEventAggregator EventAggregator { get; set; }

    [Import]
    public NavigationContainer NavContainer { get; set; }

    private static string _lastView = string.Empty;
                
    public JounceNavigation()
    {
        InitializeComponent();
        CompositionInitializer.SatisfyImports(this);
        LayoutRoot.Children.Add(NavContainer);
        if (!string.IsNullOrEmpty(_lastView)) return;
        EventAggregator.Publish("Home".AsViewNavigationArgs());
        _lastView = "Home";
    }

    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        if (NavigationContext.QueryString.ContainsKey("view"))
        {
            var newView = NavigationContext.QueryString["view"];
            _lastView = newView;
            EventAggregator.Publish(_lastView.AsViewNavigationArgs()); 
            EventAggregator.Publish(NavigationContext);
        }
    }

    protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
    {
        if (!string.IsNullOrEmpty(_lastView))
        {
            EventAggregator.Publish(new ViewNavigationArgs(_lastView) {Deactivate = true});
        }
        LayoutRoot.Children.Remove(NavContainer);
    }

}

Notice that we publish two events. The first is the view navigation to wire in the target view. The second is a NavigationContext event. The navigation context contains all of the query string information. Any view that needs to pull values from the query string can simply listen for this event. Because the view navigation is called first, the view will be in focus and ready when it receives the context message to parse any parameters.

To demonstrate this, let's look at the TextView control. When you pass text in the url, it will simply display it. The XAML looks like this:

<Grid x:Name="LayoutRoot" Background="White">
    <TextBlock x:Name="TextArea"/>
</Grid>

The code-behind looks like this:

[ExportAsView("TextView")]
[ExportViewToRegion("TextView", "MainContainer")]
public partial class TextView : IEventSink<NavigationContext>, IPartImportsSatisfiedNotification
{
    [Import]
    public IEventAggregator EventAggregator { get; set; }

    public TextView()
    {
        InitializeComponent();                        
    }

    public void HandleEvent(NavigationContext publishedEvent)
    {
        if (publishedEvent.QueryString.ContainsKey("text"))
        {
            TextArea.Text = publishedEvent.QueryString["text"];
        }
    }

    public void OnImportsSatisfied()
    {
        EventAggregator.SubscribeOnDispatcher(this);
    }
}

Pretty simple - it exports as a view name, targets the main container region, and then registers as the event sink for NavigationContext messages. In this case we only have one listener. In more complex scenarios with multiple view models listening, the view model would simply inspect the "view" parameter to make sure it matches the target view (it could easily find this in a generic way by asking the view model router) and ignore the message if it does not.

To convert the "Home" and the "About" page took only two steps.

First, I changed them from Page controls to UserControl controls. I simply had to change the tag in XAML and remove the base class tag in the code-behind and the conversion was complete. Second, I tagged them as views and exported them to the main region:

namespace SilverlightNavigation.Views
{
    [ExportAsView("About")]
    [ExportViewToRegion("About", "MainContainer")]
    public partial class About 
    {
        public About()
        {
            InitializeComponent();
        }       
    }
}

That's it - now I have a fully functional Jounce application that uses the navigation framework and handles URL parameters. You can click on the "text" tab to see the sample text and then change the URL to confirm it parses the additional text you create.

Jeremy Likness

Navigation is always an interesting topic and something I often see people struggle with in Silverlight applications. I am not a fan of navigation methods that force you to change the way your views behave, which is why I am not a fan of the navigation framework that is built into Silverlight (you suddenly have to use pages instead of user controls and understand frames and interact with special classes). Jounce takes a less intrusive approach that decouples how navigation works from how navigation is requested.

In the core Jounce framework you'll notice there are two classes, a ViewNavigationArgs and a ViewNavigatedArgs that derives from the first class. If you take a look at the code:

public class ViewNavigationArgs : EventArgs
{
    public ViewNavigationArgs(Type viewType)
    {
        ViewType = viewType.FullName;
    }

    public ViewNavigationArgs(string viewType)
    {
        ViewType = viewType;
    }

    public bool Deactivate { get; set; }

    public string ViewType { get; private set; }

    public override string ToString()
    {
        return string.Format(Resources.ViewNavigationArgs_ToString_ViewNavigation,
                                Deactivate
                                    ? Resources.ViewNavigationArgs_ToString_Deactivate
                                    : Resources.ViewNavigationArgs_ToString_Activate, ViewType);
    }
}

You can see there is not much to the class except a "view type" which is simply what we tagged our view with (the string that we discussed in the last post) along with a flag to indicate whether we are deactivating the view. To start the navigation cycle for Jounce, all you have to do is simply publish a ViewNavigationArgs message. Pretty simple, no?

Of course, I know you might not want your navigation to work the same way I like mine, so Jounce doesn't make any assumptions about how navigation will take place, it only provides the framework for notifying you about the event.

There are several reasons why I chose to include the view tag for the navigation event. First, it is consistent with the same tag you use to bind views to view models so it gives a common "name" to a view you would like to see, without having to understand how the view is implemented. Second, it abstracts the type and implementation of the view. For a view model to "navigate" it simply publishes an event with a tag, and doesn't have to reference user controls or pages or any other navigation construct - in fact, you can build a completely new view with a completely different style, tag it the same, and have the navigation work.

Another reason why this is effective is because many applications have dynamically loaded modules. When the XAP file is loaded dynamically, the calling assembly does not have access to the type in the dynamically loaded assembly (until after it is loaded). I never felt that navigation should have to be aware of whether it is triggering a module load or not, which is why I built the ViewXapRoute class.

The view XAP route simply informs Jounce that a view with a particular tag can be found in a different XAP file. The class looks like this:

public class ViewXapRoute
{
    private ViewXapRoute()
    {
    }
        
    public static ViewXapRoute Create(string viewName, string viewXap)
    {
        return new ViewXapRoute {ViewName = viewName, ViewXap = viewXap};
    }

    public string ViewName { get; private set; }

    public string ViewXap { get; private set; }

    public override string ToString()
    {
        return string.Format(Resources.ViewXapRoute_ToString_View_Route_View, ViewName, ViewXap);
    }
}

The RegionManagement solution has an example of how this dynamic navigation works. If you take a look at RequestSquare.xaml.cs, you can see that a route is exposed for the view tagged "Dynamic" indicating it can be found in the XAP file called "RegionManagementDynamic.xap". The code looks like this:

[Export]
public ViewXapRoute DynamicRoute
{
    get
    {
        return ViewXapRoute.Create("Dynamic", "RegionManagementDynamic.xap");
    }
}

With this hint, Jounce can easily navigate now even if it means loading the XAP. Now take a look at two events. Both load a view, but one loads a view that is in another XAP file. Can you tell which one?

private void Button_Click(object sender, System.Windows.RoutedEventArgs e)
{
    EventAggregator.Publish(new ViewNavigationArgs(Square.SQUARE));
}

private void ButtonDynamic_Click(object sender, System.Windows.RoutedEventArgs e)
{
    EventAggregator.Publish(new ViewNavigationArgs("Dynamic"));
}

The only difference is that one uses a magic string which could just as easily have been a constant instead (I wanted to demonstrate different ways). Notice that the request for the view is exactly the same in either case, which is what we want: the module requesting the view shouldn't have to know if it is dynamic or not. Somewhere else we provide the hint that the view exists in a different XAP file, and Jounce takes care of reading that hint and loading the XAP file.

We covered a little about what happens when the navigation is fired in the last blog post (the view model and view are wired and certain methods are called on the view model). Now let's take a full look at the event handler for the ViewNavigationArgs event that is in the ViewRouter class:

public void HandleEvent(ViewNavigationArgs e)
{
    if (e.Deactivate)
    {
        ViewModelRouter.DeactivateView(e.ViewType);
        EventAggregator.Publish(new ViewNavigatedArgs(e.ViewType){Deactivate = true});
        return;
    }

    var viewLocation = (from location in ViewLocations
                        where location.ViewName.Equals(e.ViewType, StringComparison.InvariantCultureIgnoreCase)
                        select location).FirstOrDefault();

    if (viewLocation != null)
    {
        DeploymentService.RequestXap(viewLocation.ViewXap,
                                        exception =>
                                            {
                                                if (exception != null)
                                                {
                                                    throw exception;
                                                }
                                                _ActivateView(e.ViewType);
                                            });
    }
    else
    {
        // just activate the view directly
        _ActivateView(e.ViewType);
    }
}

Notice that if the event is a deactivation, the view model is informed by calling the Deactivate method. This allows the view model to save state, release references, or do anything else that might need to be done when the view is being swapped out.

When the event is an activation, Jounce looks for a location hint. If it exists and the dynamic XAP file has not yet been loaded, it is loaded and the activation delayed until the dynamic XAP file is ready. Otherwise, it calls activation directly.

Also notice that at the end of Jounce's cycle of dealing with the event, it raises the ViewNavigatedArgs to indicate it has done the preliminary wiring of view models and XAP loading. This is something important to understand with Jounce navigation: the navigation is fired before Jounce does anything, and the navigated is fired afterwards, so if you are tapping into navigation and want to know that the view models have been activated, this is the event to listen for.

Again, Jounce is about being lightweight and guiding, not imposing. Because not everyone uses regions, the core Jounce framework does not include regions. Region management is packaged as a separate assembly that is optional. I'll talk about region management more in my next post, but it's important to know it is non-intrusive. If the region management assembly is included, the region manager will hook into the navigated event and use that event to move views into target regions.

Of course, we've now fired events, wired view models and even informed our view models that something has happened, but you are probably wondering, "Where is the navigation? So far I haven't seen a view actually do something."

Again, this is where Jounce gives you flexibility but I've included an example in the quick starts to help out. The SimpleNavigation project shows one way navigation can be handled.

In this sample project, several views are tagged with additional information. Jounce provides extra attributes for views that you can use to parse and categorize these. In our example, we're assuming that a view available from the top level navigation menu will have a category called "Navigation." We also want to provide a simple menu name for the view, as well as a description. One such view, a red square, is tagged like this:

[ExportAsView("RedSquare",Category="Navigation",MenuName = "Square",ToolTip = "Click to view a red square.")]
public partial class RedSquare
{
    public RedSquare()
    {
        InitializeComponent();
    }
}

Notice that these attributes are optional. The main navigation view, that should not also be an option itself, is simply tagged with a name:

[ExportAsView("Navigation")]
public partial class Navigation
{
    public Navigation()
    {
        InitializeComponent();
    }
}

The navigation view model pulls in the metadata for the views:

[ImportMany(AllowRecomposition = true)]
public Lazy<UserControl, IExportAsViewMetadata>[] Views { get; set; }

It then processes the views to create an observable collection with the tag for the view, the text that should display on the navigation button, and a tool tip for the button - note we are only looking for the navigation category:

foreach(var v in from viewInfo in Views where viewInfo.Metadata.Category.Equals("Navigation")
                    select Tuple.Create((ICommand)NavigateCommand,
                    viewInfo.Metadata.ExportedViewType, 
                    viewInfo.Metadata.MenuName, 
                    viewInfo.Metadata.ToolTip))
{
    _buttonInfo.Add(v);
}

Our navigation command does two things. It is only allowed if the command is for something other than the current view (we keep track of the current view in the CurrentView property). It also simply raises the view navigation event with the appropriate tag when fired. Also, notice the extension method that makes it easy to turn a string into a ViewNavigationArgs class. Here is the command:

NavigateCommand = new ActionCommand<string>(
view =>
    {
        CurrentView = view;
        EventAggregator.Publish(view.AsViewNavigationArgs());
    },
view => !string.IsNullOrEmpty(view) && !view.Equals(CurrentView));

And here is the XAML that binds the command:

<Button Margin="5" Command="{Binding Item1}" 
   CommandParameter="{Binding Item2}" Content="{Binding Item3}"
   ToolTipService.ToolTip="{Binding Item4}"/>

So basically the metadata for the views is used to generate a collection with information, and buttons are bound to those views that show the user-friendly name, provide a tool tip, and when fired, raise the view navigation event.

The shell for the project as a ContentControl that is bound to a property called CurrentView:

<ContentControl Grid.Row="1" Content="{Binding CurrentView}"/>

The view model listens for navigation events. When they happen, it uses the view model router to grab the view and bind it to the control. Because the view model router has to inspect all views in order to bind them to view models, it provides an indexer to make it easy to locate a view (without understanding the underlying details or implementation of the view). You simply pass the view tag and if the view has been found already, it will be returned. Take a look here - this is probably what you've been waiting for. It's an event that listens for navigation, and when a navigation event is raised, grabs the view so it appears in the content control:

public void HandleEvent(ViewNavigationArgs publishedEvent)
{
    if (!publishedEvent.ViewType.Equals("Navigation"))
    {
        CurrentView = Router[publishedEvent.ViewType];
    }
}

That's it - the button click raises the event, the view model listens for the event, cross-references the view and pushes it into a content control.

Of course, if that seemed like a lot of work, I agree, it was. This is on purpose: Jounce does not want to impose a navigation framework, so we are responsible for listening for publishing and receiving navigation events and doing something with them.

What's nice about this model is that navigation doesn't have to be a page. It can be an item, a sub-module, or even a tiny little control buried in the footer of the page. It is truly agnostic of your hierarchy, so it makes it easy to build composite applications because anywhere you need something to appear, you just raise an event with its tag.

If you want to make it even easier, forget about listening to the events and wiring in the views. We don't really want to deal with the views at all. We're developers, and we're focused on the code. So how do we take care of that, and let the views take care of themselves? We'll need to use a pattern introduced by Prism called "region management."

When I go into detail about region management in the next post, you'll start to see an emerging pattern with Jounce: tagging and binding. To get a view model bound to a view, we tag the view and view model, then give Jounce a hint to bind them. When we have a view in a different XAP file, we tag the view, then we export a binding that maps the view to the XAP. Region management is the same way. Instead of listening to navigation and manually grabbing views and setting them, region management lets us tag an area of the page and call it a region, then tag a view and let Jounce know the view belongs in that region.

We'll learn more about that next time ... but in the meantime, you can pull down the simple navigation project to explore these concepts further.

Jeremy Likness

In this second installment about the Jounce framework, I'll share how to get started with Jounce and wire your first view bound to a view model.

The Jounce project is available online at http://Jounce.Codeplex.com.

Jounce injects itself as a service to the application. In my opinion, using IApplicationService is the right way to handle start up and shut down in a Silverlight application. It is also an opportunity to wire in configuration because a context is passed that contains the initialization parameters, as well as hook into events such as unhandled exceptions.

When you create a new application, you can blow away all of the junk you see in the App.xaml.cs code behind. Instead, you go into the XAML and insert the Jounce Application Service in a special section for application services:

<Application xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
             xmlns:Services="clr-namespace:Jounce.Framework.Services;assembly=Jounce.Framework" 
             x:Class="Jounce.App"
             >
    <Application.ApplicationLifetimeObjects>
        <Services:ApplicationService/>
    </Application.ApplicationLifetimeObjects>
</Application>

That's all Jounce needs to register and plug into the Silverlight application lifecycle. When the appplication first starts, it will call this method:

public void StartService(ApplicationServiceContext context)
{
    var logLevel = LogSeverity.Warning;

    if (context.ApplicationInitParams.ContainsKey(Constants.INIT_PARAM_LOGLEVEL))
    {
        logLevel =
            (LogSeverity)
            Enum.Parse(typeof (LogSeverity), context.ApplicationInitParams[Constants.INIT_PARAM_LOGLEVEL], true);
    }

    _mainCatalog = new AggregateCatalog(new DeploymentCatalog()); // empty one adds current deployment (xap)

    var container = new CompositionContainer(_mainCatalog);

    CompositionHost.Initialize(container);
    CompositionInitializer.SatisfyImports(this);

    if (Logger == null)
    {
        ILogger defaultLogger = new DefaultLogger(logLevel);
        container.ComposeExportedValue(defaultLogger);
    }

    DeploymentService.Catalog = _mainCatalog;
    _mefDebugger = new MefDebugger(container, Logger);
}

Here, Jounce is doing several things. It sets a default level for logging, but also checks the initialization parameters and overrides the level to whatever is set. This allows you to control the logging level by adding the parameter to the Silverlight object host. In this example, Jounce is being configured to log verbosely:

<object data="data:application/x-silverlight-2," type="application/x-silverlight-2" width="100%" height="100%">
 <param name="source" value="ClientBin/Jounce.xap"/>
 <param name="onError" value="onSilverlightError" />
    <param name="initParams" value="Jounce.LogLevel=Verbose" />
 <param name="background" value="white" />
 <param name="minRuntimeVersion" value="4.0.50826.0" />
 <param name="autoUpgrade" value="true" />
 <a href="http://go.microsoft.com/fwlink/?LinkID=149156&v=4.0.50826.0" style="text-decoration:none">
   <img src="http://go.microsoft.com/fwlink/?LinkId=161376" alt="Get Microsoft Silverlight" style="border-style:none"/>
 </a>
</object><iframe id="_sl_historyFrame" style="visibility:hidden;height:0px;width:0px;border:0px"></iframe>

Jounce wires in a default aggregate catalog to manage various deployment catalogs (this is what allows for dynamic XAP loading). There are two key things that also happen. First, Jounce declares an import for the logger contract that looks like this:

[Import(AllowDefault = true, AllowRecomposition = true)]
public ILogger Logger { get; set; }

The "allow default" tells MEF that null is fine and don't complain if nothing is exported for the contract. If you decide to implement your own logger and export it, it will be imported here and Jounce will use your custom logger. However, if you don't provide one, that's fine - Jounce can check the property for a null value and supply it's own default logger that simply writes to the debugger. This is exported to the container so future requests for a logger will pull in the default logger supplied by Jounce.

The MefDebugger is also important because it wraps the MEF container with some debug code that spits out lots of diagnostic information to help you troubleshoot what's going on with the Managed Extensibility Framework. If you debug the default application shipped with Jounce, you'll see plenty of activity in the debug window.

0/19/2010 6:44:29 AM Verbose Jounce.Core.MefDebugger :: MEF: Found part: Jounce.ViewModels.WelcomeViewModel
10/19/2010 6:44:29 AM Verbose Jounce.Core.MefDebugger ::    With import: Jounce.Core.ViewModel.BaseViewModel.EventAggregator (ContractName="Jounce.Core.Event.IEventAggregator")
10/19/2010 6:44:29 AM Verbose Jounce.Core.MefDebugger ::    With import: Jounce.Core.ViewModel.BaseViewModel.Router (ContractName="Jounce.Core.ViewModel.IViewModelRouter")
10/19/2010 6:44:29 AM Verbose Jounce.Core.MefDebugger ::    With import: Jounce.Core.ViewModel.BaseViewModel.Logger (ContractName="Jounce.Core.Application.ILogger")
10/19/2010 6:44:29 AM Verbose Jounce.Core.MefDebugger ::    With export: Jounce.ViewModels.WelcomeViewModel (ContractName="Jounce.Core.ViewModel.IViewModel")
10/19/2010 6:44:29 AM Verbose Jounce.Core.MefDebugger ::       With key: ViewModelType = Welcome
10/19/2010 6:44:29 AM Verbose Jounce.Core.MefDebugger ::       With key: ExportTypeIdentity = Jounce.Core.ViewModel.IViewModel
10/19/2010 6:44:29 AM Verbose Jounce.Core.MefDebugger ::    With export: Jounce.ViewModels.WelcomeViewModel (ContractName="Jounce.Core.ViewModel.IViewModel")
10/19/2010 6:44:29 AM Verbose Jounce.Core.MefDebugger ::       With key: ViewModelType = Welcome
10/19/2010 6:44:29 AM Verbose Jounce.Core.MefDebugger ::       With key: ExportTypeIdentity = Jounce.Core.ViewModel.IViewModel

This is just one example of a "part" found and the resulting imports and exports. This is very valuable to track down why imports or exports might not be behaving the way you expect. Take a look at the source for the MefDebugger. It spins through all parts in the container, but then hooks into an event so that any time the container is rewired (such as when a dynamic XAP file is loaded) it will dump the changes for you as well.

The next important lifecycle event is the Starting method, called after the initialization but before the visual tree is completely wired. Take a look here:

public void Starting()
{
    Application.Current.UnhandledException += Current_UnhandledException;

    var viewInfo = (from v in Views where v.Metadata.IsShell select v).FirstOrDefault();

    if (viewInfo == null)
    {
        var grid = new Grid();
        var tb = new TextBlock
                        {
                            Text = Resources.ApplicationService_Starting_Jounce_Error_No_view
                        };
        grid.Children.Add(tb);
        Application.Current.RootVisual = grid;
        Logger.Log(LogSeverity.Critical, GetType().FullName,  Resources.ApplicationService_Starting_Jounce_Error_No_view);
        return;
    }

    Application.Current.RootVisual = viewInfo.Value;
    Logger.LogFormat(LogSeverity.Information, GetType().FullName,
                        Resources.ApplicationService_Starting_ShellResolved, MethodBase.GetCurrentMethod().Name,
                        viewInfo.Value.GetType().FullName);
    Logger.Log(LogSeverity.Information, GetType().FullName, MethodBase.GetCurrentMethod().Name);            

    EventAggregator.Publish(viewInfo.Metadata.ExportedViewType.AsViewNavigationArgs());
}

Jounce hooks into the unhandled exceptions and provides a method that basically raises a custom message. This is done using the Event Aggregator (more on that later) but makes it easy to subscribe to exceptions and even handle them in your code.

When you tag a view in Jounce, you can mark a view as the shell. This should only be done with one view. Jounce looks for that view and sets it to the root visual, or creates an error message and displays that instead.
The view metadata is imported to the application service like this:

[ImportMany(AllowRecomposition = true)]
public Lazy<UserControl, IExportAsViewMetadata>[] Views { get; set; }

Jounce then logs some messages and raises a navigation event. We'll cover navigation in Jounce later - the important thing to know is that this navigation event is what informs Jounce that it should go out and find any related view models and bind them to the view.

How did we get the view to appear as the shell?

[ExportAsView("Welcome",IsShell = true)]
public partial class Welcome
{
    public Welcome()
    {
        InitializeComponent();            
    }
}

Jounce gives you plenty of flexibility to tag your views and view models. The only rule is that each tag should be unique. Here, we're just using a "magic string" but in most applications (and you'll see the examples in the quick starts) constants can be defined instead. In this case, the view is tagged with the tag "Welcome" and set as the shell. That's all it takes to make that view the first view that appears.

Of course, the whole point of the framework is MVVM. In the Jounce default example, we create a simple view model that handles a welcome message but also kicks off an animation when loaded. The view model looks like this:

[ExportAsViewModel("Welcome")]
public class WelcomeViewModel : BaseViewModel 
{
    public WelcomeViewModel()
    {
        Title = "Welcome to Jounce!";            
    }

    private string _title;

    public string Title
    {
        get { return _title; }
        set
        {
            _title = value;
            RaisePropertyChanged(()=>Title);
        }
    }

    public override void _Activate(string viewName)
    {            
        GoToVisualState("WelcomeState",true);
    }
}

This view model is also tagged like the view. It can have a different tag than the view, because Jounce allows for the same view model to be bound to multiple views. What's important here is that it is tagged.

The base view model offers several services, including methods you can override when the view model is created for the very first time (_Initialize), anytime the view it is bound to becomes activate (_Activate) and anytime the view is deactivated (_Deactivate).

When the navigation event for a view is raised, Jounce intercepts this call and binds the view model and calls the appropriate methods.

Take a look at the view router. It is an event sink for the view navigation event - this allows it to receive any global messages sent for navigation:

public class ViewRouter : IPartImportsSatisfiedNotification, IEventSink<ViewNavigationArgs>

The view router in turn calls the ActivateView method on the ViewModelRouter. The method looks like this:

public bool ActivateView(string viewName)
{
    Logger.LogFormat(LogSeverity.Verbose, GetType().FullName, Resources.ViewModelRouter_ActivateView,
                        MethodBase.GetCurrentMethod().Name,
                        viewName);

    if (HasView(viewName))
    {
        var view = ViewQuery(viewName);

        var viewModelInfo = GetViewModelInfoForView(viewName);

        if (viewModelInfo != null)
        {
            var firstTime = !viewModelInfo.IsValueCreated;

            var viewModel = viewModelInfo.Value;

            if (firstTime)
            {
                viewModel.GoToVisualState =
                    (state, transitions) =>
                    JounceHelper.ExecuteOnUI(() => VisualStateManager.GoToState(view, state,
                                                                                transitions));
                _BindViewModel(view, viewModel);
                viewModel.Initialize();
            }
            viewModel.Activate(viewName);
        }

        return true;
    }
    return false;
}

As you can see, a view model is found to match the view and is bound (the view model router will look for LayoutRoot and bind the view model there ... if it can't find it, it will bind it to the parent control's DataContext). You can also see that Jounce binds an action called GoToVisualState that executes on the UI thread. This allows the view model to fire a visual state transition without referencing the view. In our example, the _Activate method is overridden to call:

public override void _Activate(string viewName)
{            
    GoToVisualState("WelcomeState",true);
}

This triggers a visual state transition and animations the "Welcome to Jounce" message.

There is one final piece missing. We never specified how to know that the welcome view model belongs with the welcome view. In Jounce, I decided against a traditional locator pattern to provide more flexibility. Instead, a binding is exported that maps a view model to a view. What's nice about this approach is that the binding can be consolidated in a class that holds all bindings for the application, or localized to the view so it is clear what view model the view is binding to. You could also write your own interface, such as a fluent or convention-based interface, and export bindings to the container to achieve the same result.

In the Welcome view, we mark the binding by exporting the tag for the view model and the tag for the view here:

[Export]
public ViewModelRoute Binding
{
    get
    {
        return ViewModelRoute.Create("Welcome", "Welcome");
    }
}

That's all there is to it! From your perspective, you had to:

  1. Add the Jounce Application service to the App.xaml
  2. Build your view model and tag it
  3. Build your view and tag it, then mark it as the shell
  4. Export a binding for the view model and the view

Jounce took care of all the rest.

The Jounce project is available online at http://Jounce.Codeplex.com.

Jeremy Likness

Over the next few weeks I will be publishing a series of posts explaining the open source Jounce project that I just released. Jounce provides guidance for building modular Silverlight applications using the Managed Extensibility Framework (MEF) and Model-View-ViewModel (MVVM).

Origins

I have been building enterprise Silverlight applications since late in the version 2.0 cycle. Many of these applications require extensibility: making it easy to add new screens or modules. The applications often require modularity as well, specifically to allow for dynamic loading of assemblies to reduce the initial memory footprint and impact on the client browser.

In addition, after trying Model-View-Controller (MVC) and experimenting with MVVM, I quickly found MVVM to be the right tool for my job. My background of developing mission critical applications for over a decade had already imposed the discipline of creating decoupled solutions that are easy to unit test and build in parallel to scale across large development teams. After exploring homegrown factory methods, Unity, and other patterns, I found that MEF really addressed most of my Silverlight needs out of the box.

The end result is that I've been using a common set of patterns across multiple applications. Developers know and understand the value of tools and macros. We're wasting our customers' time if and when we build something from scratch that has already been addressed, and this is why I constantly found myself sharing base classes, interfaces, and other core structures across various projects. I kept this basic framework factored separately to seed new projects and added to it as I encountered new challenges.

This framework is what I recently packaged as Jounce. It is similar to many MVVM frameworks because it provides messaging services and notify property changed handlers. It is different beacuse it does not attempt to abstract the underlying inversion of control - make no mistake: Jounce has a direct, explicit dependency on the Managed Extensibility Framework.

Why Should I Use Jounce?

I've been wanting to share Jounce for quite awhile but resisted because the last thing we need is "yet another framework." I was asked that exact question when I decided that all of my blog posts and examples just don't make as much sense without the context of the underlying framework they derive from.

The answer to the question is a simple one. "Don't."

I'm not trying to compete with the many other mature frameworks that are there. I like all of them. So why Jounce? I released Jounce less as a framework to package and solve all problems, and more as guidance for how I've found MEF can help solve MVVM problems in the Silverlight domain. It's a very specific niche, and I'm not trying to cover both Silverlight and WPF and the Windows Phone 7, nor abstract the notion of dependency injection containers. This is a very specific set of principles that I've used to successfully resolve challenges in a specific space.

The idea here is that you can pull down the source for a framework that is extremely lightweight - less than 1,000 lines of code. That's something you can dig into and look at inside and out. The license for Jounce allows you to use it right out of the box if you like, but my guess is that most people have far more specific needs for their framework than any package can provide "out of the box." For this reason, you are welcome to customize and modify Jounce or use the pieces that make sense for your project and toss the rest out.

Jounce is far more lightweight than Prism is and addresses fewer concerns. The Jounce implementation of the region management pattern takes only a few lines of code and isn't quite as powerful as Prism is ... but I've seldom needed that extra power. Jounce does not have automatic convention-based data-binding that Calburn and Caliburn.Micro provide, but again, I've found I prefer to use explicit data binding and design-time view models with a focus designer-developer workflow.

I've tried to note where a portion of Jounce was derived from another framework, both to give due credit and also to give you a place to explore further.

Some of the guiding principles behind Jounce:

How do I Get Started?

The full source code for Jounce is available at Codeplex. You can pull it down, compile, and get started. The framework has a web project with a simple view and view model. There are several quick starts that demonstrate navigation, regions, dynamic XAP loading, and more ... and I plan on adding others for the 1.0 release.

The power of Jounce I believe comes from the experience of using it. None of the quick starts took very long for me to create with no or minimal troubleshooting to make a feature work. That in my mind is the ideal goal of a framework: to be lightweight and easy to use, and easy to troubleshoot when things go sour. I believe Jounce exhibits all of this.

So in conclusion, Jounce is not the "next hot framework" that I'm begging you to download and use. I don't intend to come out with super cool feature-packed releases ... but if I find a better way to solve a problem or a new idea that pops up often, I will look at including that in the future.

In the next posts I'll start drilling into the details of how Jounce works. Much of this will be familiar to long time readers of my blog, with the difference that the ideas are encapsulated in a full reference framework rather than parceled into small "sample project" chunks.

Your feedback and suggestions are more than welcome!

Jeremy Likness

After having worked on several major projects that integrated the Managed Extensibility Framework, I thought it might be beneficial to share a retrospective on how it was used what value it provided. These are all ways MEF helped my team build modular Silverlight applications.

Unlike my earlier post that covered 10 Reasons to use the Managed Extensibility Framework, this is more of an inventory of actual, specific use cases it has been implemented in real world projects, sometimes referred to as "the wild."

Inversion of Control/Dependency Injection

This was perhaps the easiest decision to make. None of these applications had any requirements for more advanced inversion of control or dependency injection than what MEF offers out of the box. Because we were using it for other reasons, and because it is now native to the framework, it was the logical choice to solve this problem. In most cases, it was as simple as defining the interface, importing it where needed and exporting it where satisfied. Other, more specific cases are described below.

Configuration

Configuration was very important and is easy to facilitate with MEF. I included this as a sub-item under IoC because it really is a side effect of inversion of control. By defining a configuration interface, all code could then reference that interface and testing could mock the values. The main application service implemented the configuration and used a combination of compile-time constants as well as parameterized values to load these. Any consumer, application-wide, then simply needed to import the interface to have access to these variables, even from dynamically loaded modules that had no concrete references to any of the assemblies that configuration lived in.

Logging

Logging is another indirect benefit of the IoC pattern that just happened to be implemented with MEF. We created an interface for logging that was satisfied by a logger and maintained the discipline of avoiding "Debug.WriteLine" and instead writing to the log file with severity, source, and additional information. This separation of concerns allowed us to use a simple logging mechanism in the beginning (it could simply write to the debug window) but gave us the flexibility to add service calls, store logs to isolated storage, or otherwise manage the logging transaction easily from one place without changing any of the rest of the application.

Region Management

Prism 4.0 has an excellent region management framework, so I want to be clear that I have nothing against it and am not about reinventing the wheel. For this project, we only had a few specific types of regions defined, so it was more lightweight to use a more specific version.

Essentially, region management consisted of a few pieces. There was an interface for a region adapter that is scoped to a type of container (Grid, or ContentControl, etc). To implement a new region adapter was as simple as inheriting the interface, adding metadata to describe the target container it would support in a MEF export, and then writing the specific events which including registering (pointing a view to a region), activating (making the view appear in the region) and deactivating (making it go away). Some of this involved manipulation of content or child elements but much of it was driven by the Visual State Manager.

An attached property defined a container as a region, and metadata on a view defined what region that view targeted. The region manager aggregated all of these parts and coordinated between them. If I needed a view activated, the region manager would use the chain of responsibility pattern to find the region adapter that owned the view, then ask it to bring it to focus.

[RegionManagerExport(typeof(ContentControl))]
public class ContentRegion : RegionBase<ContentControl>

Read MEF instead of PRISM Part 2 for a detailed explanation of building custom region management, and see Advanced Silverlight Applications using MEF for an example framework.

Service Integration

A common pattern in line of business applications is to have different types of models or business domain objects that can have some common operations performed against them, such as CRUD (create, read, update, delete). For this reason, I was able to create an abstract IServiceFor<T> style interface and define some common functions. Implementations of the contract would export themselves explicitly, and a service router handled mapping the entities to the service handler for the entity.

What this meant is that I could build a view model for an entity and simply request a service from the service router for the entity type and perform all of my generic operations without worrying about how the service was implemented. I could easily stub the service while developing until the endpoints were actually created. Some services actually interacted with isolated storage while others carried messages over the wire: these were all abstracted from the view model and brought together with MEF.

[Import]
public IServiceLocator Locator { get; set; }

var service = Locator.GetServiceFor<T>();

Messaging

Messaging is a very important aspect of any system. For example, consider having a filter view model with filter data that can be applied to other view models. How do these other view models keep track of when the filter changes, or access the filter data?

In this project, we handled messaging in two ways.

View Composition

Something like a filter, even when globally applied, can be considered a part of the view model that use it. It does not make sense by itself, but when it is composed as part of another view model, it has context and use. MEF was extremely helpful with this pattern because any view model that needs access to another could simply import it:

[Import]
public OtherViewModel Other { get; set; }

Of course, that still doesn't allow us to know when it changed, unless we subscribe to the property changed event. That may make sense in some circumstances, but often there are messages so important that many different parts must listen to them. For this purpose, we used the EventAggregator pattern.

Event Aggregator

The event aggregator I used was based on this post, which describes an event aggregator based on Reactive Extensions (Rx). I factored it to work with Silverlight and it worked like a charm.

One common pattern was messages that caused the application to change. For example, a new filter or a new selection item. I created a special class for carrying these messages. It held the type, the payload, and an enumeration. If I wanted to publish a selection event, for example, I could create this class and place the item selected, it's type, and the enumeration for "select" and publish that.

Any "listener" can then filter like this:

var query = from evt in EventAggregator.GetEvent<MyEntityEvent>()
   where evt.Type.Equals(typeof(MyWatchedEntity)) && 
         evt.Action.Equals(Actions.Select)
   select evt.Cast<MyWatchedEntity>(); 

query.Subscribe(myEntity=>{//do something});

Dynamic XAP Routing

Dynamic XAP loading is important in Silverlight applications because it is downloaded from the web and resides on the user's machine. There are two major concerns: the first is the load time for the application, and the second is the memory footprint and impact to the user's machine. Dynamic XAP loading helps by breaking the applicatin into modules. A module is loaded only when requested. Therefore, the initial application loads faster with a smaller memory footprint and grows gradually as modules are exploited.

The challenge some frameworks have is how and when to trigger the module load. I've become fond of a concept I call "dynamic XAP routing." The concept is simple: I tag views with names, either a friendly name or the full namespace. In my core or "infrastructure" project, I have a set of global constants. While the current module may not know about a view, the constants can represent the view. Another set of constants describes the XAP files that are available.

With these two pieces of information, I can then dynamically route via a deployment service that uses deployment catalogs to load modules. A route contains a pointer to a view and the XAP file the view lives in, and is exported by whatever module may need to load that view. When the view is requested, the view manager first checks to see if a route exists. If it does, it asks the deployment service to dynamically load the XAP and defers raising the navigation event until the dependent XAP file is loaded. This makes it easy to abstract navigation from the modules, because any area in the application simply requests the view, and the framework takes care of either navigating to the view, or loading the XAP file and then navigating.

View Model Routing

A common concern with using MVVM is how to bind the view model to the view. In the frameworks I use, there is not a one-to-one mapping because some view models might service multiple views. The view model never really knows about the view(s) it is attached to, but the views depend on the view model (consider it the "binding contract" for the view). Views are exported by type or tag with a target region, and view models are also exported with a view model tag.

Next, I have a simple route object that contains two tags: a view tag, and a view model tag. Whether the view exports this tag, or a separate "routing" class does, these exports are then all managed by a centralized router. The router is able to pull views, and because everything is lazy-loaded, determine if the view needs the view model bound. Conversely, the view model can also be created for the first time or referenced.

The result is that the view and view model binding is completely decoupled - it is described elsewhere in the application. What it also means is that the routing system knows when a view is being shown for the first time, so it can call methods on the view model both the first time it is created, and each time a view is active. This allows my view models to respond to housekeeping that may be required before binding to the view again, without having a dependency on the visual tree.

[ExportAsViewModel(typeof (DialogViewModel))]
public class DialogViewModel : BaseViewModel

...

[ExportAsView(typeof(MyDialog),Regions.DialogRegion)]
public partial class MyDialog
{        
    public MyDialog()
    {
        InitializeComponent();            
    }     
  
    [Export]
    public ViewModelRoute DialogBinding
    {
        get
        {
            return ViewModelRoute.Create<DialogViewModel, MyDialog>();
        }
    }
}

Take a look at View Model binding with MEF and Yet another MVVM Locator pattern for more on this.

Decoupling Views

There are many cases when you may need to map to a type of view but don't know what the view will be before hand. For example, consider a navigation framework that depends on view types (see the next section). When the view is in a dynamic XAP file that isn't loaded, there is no way to directly reference the time. MEF was very useful in "late-binding" types, that is to say, I could import a property for a type using a tag ("MainView" or "DashboardView") and then export the tag when the view was defined somewhere else. This allowed the idea of interacting with a view to be completely decoupled from the actual view type.

Navigation

MEF provided a very flexible navigation framework. I wanted something composable, such that a "navigation event" wasn't limited to a "page" in the application, but rather a view - and views often are nested inside of other views.

The navigation works in conjunction with the view model router to synchronize changes with the view model. In the framework I developed, the MEF-enabled event aggregator simply raises a view navigation event which encapsulates the type of a view and a flag for activation or deactivation. The router, which has imported all views and view models, finds the view, talks to the region manager to swap it out, and if it is active will also call the appropriate method on the view model.

Navigation became incredibly simple because the concept of a dialog or page or even wizard step is reduced to a simple navigation event. The idea of "pop-up" is an implementation detail abstracted from the event itself, and a view model simply raises the request for a view for navigation to happen and doesn't have to worry about view models, regions, or any other nuances of the navigation itself.

Authorization

Authentication and authorization are required for most line of business applications. Typically the user has properties such as roles and credentials that are checked for access and authorization to various areas of the appplication. MEF makes it easy to carry these credentials because the user construct can be exported as either a concrete object or contract, and then imported and queried by any area of the application that requires access to the credentials and user properties.

Commands

Certain commands can be tightly coupled to the user interface, and others might exist in modules not yet referenced. For example, a "home" command or an "expand" command requires a navigation event that is aware of the target for the navigation.

Late-binding Commands

MEF helped handle this scenario by allowing commands to be exported and imported. In some cases, the view model would import the command based on a pre-defined tag (such as a "home" tag) even if the "home" view is in a different module. The module, when loaded, would export the appropriate command and it then becomes avaiable for binding from the view model even though the command was "late-bound" meaning it did not become available until the child module was loaded.

[Import(Contracts.COMMAND_GOHOME, AllowDefault = true)]
public DelegateCommand<object> HomeCommand { get; set; }
...
[Export(Contracts.COMMAND_GOHOME)]
public DelegateCommand<object> HomeCommandExport
{
    get
    {
        return
            new DelegateCommand<object>(
                obj => EventAggregator.Publish(typeof (HomeView).AsViewNavigationArgs()));
    }
}

Global Commands

Some commands are global by nature and instead of creating dozens of local copies per view, make sense to be accessed as a single, global construct. Global commands be exported and then imported wherever they are needed so a global copy is used, rather than creating multiple local instances. Again, as with the "home" example, view models can expose a "home" command before having knowledge of the assembly/module that contains the command, and MEF simply imports the command when it becomes available.

Read Sharing Commands with MEF for more.

Chain of Responsibility

The chain of responsibility pattern is a powerful way to handle common messages that are processed differently based on the message signature. I used MEF to provide a "handler" mechanism that defined a standard contract that would consume certain message types. Each handler would export the contract along with metadata described what messages the handler could process. A central "router" would then import the handlers, listen to the message, and pass the message to the appropriate handlers until one indicated it had successfully processed the message. This, coupled with global commands, provides a very powerful level of extensibility to the application.

For example, consider a "print" command that is globally exposed throughout the applicaton but bound to the data element being printed. Multiple handlers are registered to the print interface that know how to process different types of data objects. When the handler that manages the target object is called, it formats the data in a printer-friendly format and sends the output to the printer. Handling a new type of data is as simple as building a new handler and then exporting the print contract.

Factories with Dependency Resolution

Many classes have multiple layers of dependencies. Consider a composable view where a list of items is presented, and each item is exposed via a bound view model that has dependencies to the event aggregator, service bus, and other contracts that are imported using MEF. MEF makes this scenario simple and straightforward to handle via the ExportFactory keyword. When spinning through a list of data objects, a view model can be created on the fly using the export factory that features full dependency resolution, from handlers to global commands. The data is attached and then the view model bound to the child view with all dependencies resolved via MEF.

Design-Time Friendly Views

Design-time friendly views are extremely important when working with the design team in parallel. MEF made it very easy to build a design-friendly framework because the runtime view models would be bound via the MEF constructs while the design-time view models are bound directly in views using the d:Design and d:DesignInstance attributes. By isolating MEF-specific initialization code using the IPartImportsSatisfied contract, the views and view models remained designer-friendly and would not execute any code reserved for the run time version of the application.

See Design-time Friendly View Models with MEF for more.

Validation Engine

Validation engines typically expose different validation rules that result in rule violations. MEF made it simple and easy to build an engine that was both flexible and extensible. Each validation rule is exported using the contract for the rule. The engine would import all rules, and then provide access via a fluent interface. Read fluent validation with MEF and PRISM to learn more.

Unit Testing

MEF was critical in the success of unit testing because all dependencies were exposed by contracts that MEF imported. For testing, the MEF initializer simply isn't called, allowing the test system to initialize the dependencies using test mocks and stubs. Take a look at using Moq with Silverlight for advanced unit tests.

Conclusion

Obviously, many of these examples could be easily handled using frameworks other than the Managed Extensibility Framework. The framework has the advantage of being included in the language run-time: it's not a third-party, out-of-band release, but a fundamental part of both the .NET 4.0 and the Silverlight 4.0 CLR. Based on my experience building very large line of business Silverlight applications, MEF not only made it easy to break those applications into modules and parts, it also accelerated development time by providing so many features "out of the box," especially the ability to tag exports with meta data and import multiple items for the same contract. Hopefully this will not only provide you with some ideas about how to use MEF in your own applications, but also demonstrates how MEF is being used effectively in production line of business applications.
Jeremy Likness

The Managed Extensibility Framework (MEF) is a very powerful tool for building modular, extensible Silverlight applications. If you've followed this blog, you'll know that it is not just for applications that anticipate plug-ins, but can be used as an inversion of control container, can facilitate region management, and much more. In preparing the material for my upcoming presentation that is an Introduction to MVVM, I decided to take an existing, publicly available Silverlight application and refactor it to use MVVM.

Everyone seems to like Twitter feeds and RSS Readers, so I chose John Papa's example that demonstrates RSS syndication and isolated storage to refactor. It is an excellent little demo and of course for the article the focus was the syndication and isolated storage, not MVVM.

I'm not going to include the full refactor here - I'll discuss it at the event and then post the code later. What I do want to touch upon, however, is a common issue that people run into when using MEF in conjuction with the Model-View-ViewModel pattern: design-time compatibility. Because the built-in designer for Blend and VS 2010 ("Cider" is the name for the VS 2010 flavor) doesn't actually use the Silverlight runtime, your controls are run in a different CLR than the target application. The result is that MEF compositions fail, which means controls that rely on MEF ultimately don't get rendered in the designer.

Here is our before picture: you can clearly see what the application is going to look like, but there is no data so it's not clear how the data will fit into the control:

MEF Design-Time Before

There are really just a few easy steps to making MEF views design-time friendly. Let's walk through it.

Step One: Create Your ViewModel

This is straightforward and part of the MVVM pattern. Right now, we'll not worry about design-time as much as having a robust ViewModel to use. For my example, I went with a base ViewModel based on the Prism 4.0 drops. The ViewModel itself ended up looking like this:

[Export]
public class FeedsViewModel : BaseViewModel, IPartImportsSatisfiedNotification
{        
    private const string ERROR_INVALID_URI = "Invalid Uri.";
    private const string ERROR_DUPLICATE_FEED = "Duplicate feed not allowed.";

    private bool _add;

    [Import]
    public IFeedStore FeedStore { get; set; }

    [Import]
    public IFeedService FeedService { get; set; }

    public FeedsViewModel()
    {
        Feeds = new ObservableCollection<SyndicationFeed>();           

        AddFeedCommand = new DelegateCommand<object>(
            obj =>
                {
                    _ValidateNewFeed();

                    if (!AddFeedCommand.CanExecute(obj)) return;

                    _add = true;
                    _AddFeed(new Uri(_newFeed, UriKind.Absolute));
                    NewFeed = string.Empty;
                },
            obj => !HasErrors
            );

        Feeds.CollectionChanged += (o, e) =>
                                        {
                                            RefreshFeedCommand.RaiseCanExecuteChanged();
                                            RaisePropertyChanged(() => Items);
                                        };

        RefreshFeedCommand = new DelegateCommand<object>(
            obj =>
                {
                    Feeds.Clear();
                    _RefreshFeeds();
                },
            obj => Feeds.Count > 0);
    }

     public DelegateCommand<object> AddFeedCommand { get; private set; }

    public DelegateCommand<object> RefreshFeedCommand { get; private set; }

    public ObservableCollection<SyndicationFeed> Feeds { get; private set; }

    public int Count { get; set; }

    public IEnumerable<SyndicationItemExtra> Items
    {
        get
        {                
            var query =
                from f in Feeds
                from i in f.Items
                orderby i.PublishDate descending
                select new SyndicationItemExtra {FeedTitle = f.Title.Text, Item = i};

            Count = query.Count();
            RaisePropertyChanged(()=>Count);
            return query;
        }
    }

    private string _newFeed;

    public string NewFeed
    {
        get { return _newFeed; }
        set
        {
            _newFeed = value;                

            RaisePropertyChanged(() => NewFeed);
            _ValidateNewFeed();
        }
    }

    private void _ValidateNewFeed()
    {
        Uri testUri;
        if (Uri.TryCreate(_newFeed, UriKind.Absolute, out testUri))
        {
            if ((from feed in Feeds where feed.BaseUri.Equals(testUri) select feed).Count() > 0)
            {
                SetError(() => NewFeed, ERROR_DUPLICATE_FEED);
            }
            else
            {
                ClearErrors(() => NewFeed);
            }
        }
        else
        {
            SetError(() => NewFeed, ERROR_INVALID_URI);
        }

        AddFeedCommand.RaiseCanExecuteChanged();
    }

    private void _SaveFeeds()
    {
        FeedStore.SaveFeeds(Feeds.Select(feedItem => feedItem.BaseUri).AsEnumerable());
    }

    private void _AddFeed(Uri feedUri)
    {
        FeedService.FetchFeed(feedUri, (ex, feed) =>
                                            {
                                                if (ex != null)
                                                {
                                                    SetError(() => NewFeed, ex.Message);
                                                    return;
                                                }

                                                var oldFeed = (from feedEntry in Feeds
                                                                where feedEntry.BaseUri.Equals(feed.BaseUri)
                                                                select feedEntry).FirstOrDefault();

                                                if (oldFeed != null)
                                                {
                                                    Feeds.Remove(oldFeed);
                                                }

                                                Feeds.Add(feed);

                                                if (!_add) return;

                                                _add = false;
                                                _SaveFeeds();
                                            });
    }

    private void _RefreshFeeds()
    {
        var feedList = new List<SyndicationFeed>(Feeds);
            
        if (feedList.Count == 0)
        {
            FeedStore.LoadFeeds(list=>
                                    {
                                        foreach(var feed in list)
                                        {
                                            _AddFeed(feed);
                                        }
                                    });
            return;
        }

        foreach (var feed in feedList)
        {
            _AddFeed(feed.BaseUri);
        }
    }

    public void OnImportsSatisfied()
    {
        _RefreshFeeds();
    }
}

As you can see, this ViewModel relies on MEF to compose many of its parts. I've pulled out the saving of the feed list to an external service so I can tweak it as needed, and I've also abstracted the call to the syndication service. I've exposed properties and commands and use a query to aggregate the feeds together. This is a lot of functionality and without the required service and storage dependencies, breaks down in the designer. That's OK, there is hope ...

Step Two (Optional): Define an Interface

This might be step one, actually, it all depends on how you work. I like to get my ViewModel working fine, then define the interface and keep up with it. The only purpose of the interface here is to make it easier to define a design-time ViewModel. If you use a tool like JetBrains ReSharper, it's as easy as right-clicking, choosing "Refactor" and then "Extract Interface." We end up with this:

public interface IFeedsViewModel
{
    DelegateCommand<object> AddFeedCommand { get; }

    DelegateCommand<object> RefreshFeedCommand { get; }

    ObservableCollection<SyndicationFeed> Feeds { get; }

    int Count { get; set; }

    IEnumerable<SyndicationItemExtra> Items { get; }

    string NewFeed { get; set; }
}

Step Three: Create a Design-Time ViewModel

Now that we have an interface, we can implement it in another ViewModel we create specifically for runtime. This ViewModel can create new instances of collections and wire in sample data for us. In our example, I've done this:

public class DesignFeedsViewModel : IFeedsViewModel 
{
    private const string DESIGN_FEED = @"http://feeds.feedburner.com/csharperimage/";
    private const string DESIGN_TITLE = "Test Feed ";
    private const string DESIGN_DESCRIPTION = "A test feed for design-time display";
    private const string LOREM = "Lorem ipsum dolor sit amet, consectetur adipiscing elit.";
    private const string FEED_TITLE = "Feed ";

    public DesignFeedsViewModel()
    {
        Count = 10;
        NewFeed = DESIGN_FEED;

        Feeds = new ObservableCollection<SyndicationFeed>();

        for (var x = 0; x ();
            
        for (var x = 0; x < 10; x++)
        {
            var item = new SyndicationItem(LOREM, string.Empty,
                                            new Uri(DESIGN_FEED, UriKind.Absolute));
            designItems.Add(new SyndicationItemExtra { FeedTitle = FEED_TITLE + x, Item = item });
        }

        Items = designItems;
    }

    public DelegateCommand<object> AddFeedCommand
    {
        get { return new DelegateCommand<object>(); }
    }

    public DelegateCommand<object> RefreshFeedCommand
    {
        get { return new DelegateCommand<object>(); }
    }

    public ObservableCollection<SyndicationFeed> Feeds { get; set; }
        
    public int Count { get; set; }
        
    public IEnumerable<SyndicationItemExtra> Items { get; set; }

    public string NewFeed { get; set; }        
}

Now, a quick note: at this point, you probably realize you could have gotten away with just one ViewModel. In that case, you'd do something like this:

if (DesignerProperties.IsInDesignTool)
{
   // code for design-time
   return;
}

That's perfectly fine but does a lot of mixing of code ... I've grown to prefer keeping my design-time view models separate and synchronizing them with the interface. It's totally up to you!

Step Four: Bind Your Production ViewModel

This is a key step. If you are directly binding the ViewModel in XAML, and using CompositionInitializer to fire up MEF, you'll need to wrap a condition around it so it doesn't fire that command in design time. There are many ways to bind the ViewModel to the view. I've written about a few:

The bottom line is you can bind it however it makes sense. For simple solutions, this is a pattern I've come to enjoy. While it does involve code-behind, it cleanly separates the MEF ViewModel from design-time because it is not invoked in the constructor (this only works if you export the View as well):

[Export("RootVisual",typeof(UserControl))]
public partial class Reader : IPartImportsSatisfiedNotification
{                
    [Import]
    public FeedsViewModel ViewModel { get; set; }

    public Reader()
    {
        InitializeComponent();
    }       

    public void OnImportsSatisfied()
    {
        LayoutRoot.DataContext = ViewModel;
    }
}

Here, I'm taking advantage of the interface that MEF uses when it wires up a class. Once all dependencies are resolved, it will call OnImportsSatisfied and I can glue my ViewModel. In the designer, the control is simply created using new() so there is no MEF call. So how do we get our design-time data?

Step Five: Bind Your Design-Time ViewModel

Binding the design-time ViewModel is actually very straightforward, especially with the help of design-time extensions. At the top of our XAML, we'll two references: one for the design-time extensions if they aren't already there, and one for the location of the design-time ViewModel:

<UserControl
    xmlns:design="clr-namespace:SilverlightSyndication.DesignTime"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    .../>

Next, on the root grid where the ViewModel should be bound, we take advantage of the d:DataContext and d:DesignInstance extensions:

<Grid d:DataContext="{d:DesignInstance design:DesignFeedsViewModel, IsDesignTimeCreatable=True}" ...>

Here we are defining a data context that is only valid at design time. We bind it to a "design instance" of our view model we created specifically for the designer.

Now, when we run the application, MEF finds and binds the production ViewModel for us. However, in the designer, the designer finds and binds the design-time view model. This gives us plenty of rich data to work with and keeps the designer so happy they're likely to buy you a steak dinner (that last was just in case any of the designers I work with are reading this).

With a little Toolkit Theme love, a rebuild, and a refresh of the XAML in the designer, I now get this:

MEF Design-Time After

Jeremy Likness

Published another quickstart. This is an introductory quickstart for the Managed Extensibility Framework, and is similar to the previous one except that it is specific to Silverlight. You can take a look at the article and watch the short video by clicking here.

Jeremy Likness

More Posts Next page »