Building the Hello MEF dashboard in Silverlight 4 – Part I

In my last post I illustrated some of the basics of MEF through a Hello MEF dashboard app that I used in my PDC talk. In this series of posts, we’ll build that application from scratch and then go even further than we did in that talk. This might take several posts, I am not sure yet, we’ll just have to see ;-) We’ll build the app in an incremental fashion, revisiting different parts along the way in order to introduce new functionality.

Before you invest the time, I’ll give you a preview of the topics we’ll cover along the way.

  • Exports / Imports / Part Initializer – All that jazz
  • Export metadata
  • Custom exports
  • Overriding Part Initializer
  • Dynamic XAP downloading

In this post, we’ll cover just the first bullet.

To follow along, you will need Silverlight 4 and the Silverlight 4 toolkit. You can download Silverlight 4 beta  here and the toolkit here.

The App

Below is a screenshot of the dashboard application.

image

May not look very complicated, but what we’re showing here is actually quite sophisticated. The dashboard itself is a dumb shell. The two “Hello MEF” widgets you see are actually exports that are discovered by MEF. The dashboard itself has not knowledge of what it will find, but it does know how to place things that are provided to it, and it has different locations on the screen where things can go. If you’re familiar with Prism, these are very similar to regions in principle though instead of modules pushing content into regions, MEF is pulling the content from whatever is available. More on this later.

Note: I’ll admit, I suck as a designer though I think I could be good if I REALLY try :-) Nice thing about SL is you don’t have to be, as your friendly neighborhood designer can make something hideous a work of art. With that note, don’t expect a work of art out of this post.

Step 1 – Create the app

Nothing fancy here, just create a new Silverlight application. Enter HelloMEF as the name.

image

Leave the “Host the Silverlight application in a new Web Site” checked. We’ll use this later as we get into XAP partitioning.

image

Step 2. Create the dashboard UI.

For this dashboard we’re going to create something simple, amazingly simple, amazingly stupidly simple. But it works. We’ll create a StackPanel with two items control which will be populated with our widges. Jump into your MainPage.xaml and paste the following.

<UserControl x:Class="HelloMEF.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">
    <StackPanel x:Name="LayoutRoot" Background="Black">
        <Border Background="Cyan">
            <ItemsControl x:Name="TopWidgets" Height="Auto" FontSize="30"></ItemsControl>
        </Border>
        <Border Background="Yellow">
            <ItemsControl x:Name="BottomWidgets" Height="Auto" FontSize="30"></ItemsControl>
        </Border>
    </StackPanel>
</UserControl>

Step 3. Find and show the widgets – Importing many

Our dashboard is supposed to populate itself with widgets. The first thing we need to think about is what exactly is a widget :-) In MEF when we have the concept of a contract. A contract represents something that will either be provided (exported) or consumed (imported). The easiest way to think about it for now is what type is the extension. In the case of our dashboard let’s just assume each widget is a UserControl. We could create a new base type or an interface, but we don’t need to. UserControl will do just fine.

So now we need to tell MEF we need a collection of UserControl, that is we want to import many UserControls. And for that we have the ImportMany attribute.

First add a reference to System.ComponentModel.Composition, and System.ComponentModel.Composition.Initialization.dll. To find them you’ll need to browse to your Silverlight SDK directory (C:\Program Files\Microsoft SDKs\Silverlight\v4.0\Libraries\Client). Next go into the code-behind of MainPage.xaml.cs and overwrite the class with the following.

using System;
using System.Windows.Controls;
using System.ComponentModel.Composition;

namespace HelloMEF
{
    public partial class MainPage : UserControl
    {
        public MainPage()
        {
            InitializeComponent();
        }

        [ImportMany]
        public UserControl[] Widgets { get; set; }
    }
}

Basically we’re saying “MEF, give me the widgets”

Once we have the widgets, we need to show them on the screen. For now, let’s assume all widgets will go in the same ItemsControl. Let’s add the logic to the constructor.

using System;
using System.Windows.Controls;
using System.ComponentModel.Composition;

namespace HelloMEF
{
    public partial class MainPage : UserControl
    {
        public MainPage()
        {
            InitializeComponent();
            foreach (var widget in Widgets)
                TopWidgets.Items.Add(widget);
        }

        [ImportMany]
        public UserControl[] Widgets { get; set; }
    }
}

Step 4: Create a widget – Export

Now that we’ve got our basic Dashboard setup, let’s create a widget. Right click on the “HelloMEF” project and add a new Silverlight UserControl specifying Widget1 for the name.

image

Our widget is also going to be dead simple, and simply be a button. Go into Widget1.xaml and paste the following.

<UserControl x:Class="HelloMEF.Widget1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">

    <Grid x:Name="LayoutRoot" Height="Auto">
        <Button x:Name="Button" Content="Hello MEF!" Width="300" Height="100"></Button>
    </Grid>
</UserControl>

Now we need to tell MEF that we want to provide our widget to importers of UserControl. To do this we will Export it. Go into HelloMEF.Widget1.cs and paste the following:

using System;
using System.ComponentModel.Composition;
using System.Windows.Controls;
using System.Windows;

namespace HelloMEF
{
    [Export(typeof(UserControl))]
    public partial class Widget1 : UserControl
    {
        public Widget1()
        {
            InitializeComponent();
        }
    }
}

Notice above we added an Export attribute and specified UserControl as the type. If we did not pass the type, then MEF would have just exported Widget1 as itself, which would not be of much use as the dashboard will never find it! That being said there are times when it does make sense to use the concrete type, but this is not one of them :-)

Step 5 – Compose the dashboard

OK, we’ve implemented our Dashboard, specified our imports, and created our widget. That means if we run the app, we’ll see widgets right? Wrong :-) Try running and you’ll see this nasty exception.

image  
What happened? Our Widgets property is null, but why? The reason is because we never told MEF to do anything with it? Yes we put an ImportMany attribute, but MEF needs to somehow our MainPage in order to know it needs to provide anything. Which brings us to our last concept, composition.

In MEF there are basically 3 things you need to do. First two, declare your exports and imports which we did already. Third, tell MEF to actually go and compose, that is satisfy all imports. The places to do this (you can do it more than once) are where there are 1 or more imports and no exports. In this case our MainPage is the place where we import Widgets so that is the place.

Note: We won’t put it in the widgets themselves as they export themselves. Why not? Because when MEF pulls on an export, it automatically satisfies any of the imports on the thing it pulls. There is an exception to this, but we’ll cover it later.

In general whenever you have user controls that are created in XAML, you’ll use this technique. Telling MEF to compose in Silverlight takes only about 12 lines of code. It’s really easy code and 12 lines that are well worth it.

Kidding :-)

To tell MEF to compose you invoke a single call, PartInitializer.SatisfyImports(this). In MEF, anything that has imports or exports we consider a Part, which is why the name. Below is the code added in MainPage.cs

using System;
using System.Windows.Controls;
using System.ComponentModel.Composition;

namespace HelloMEF
{
    public partial class MainPage : UserControl
    {
        public MainPage()
        {
            InitializeComponent();
            PartInitializer.SatisfyImports(this);
            foreach (var widget in Widgets)
                TopWidgets.Items.Add(widget);
        }

        [ImportMany]
        public UserControl[] Widgets { get; set; }
    }
}

Now when we Run, we see our first widget show up. 

image

 

Summary

OK, it’s 2:17 am, time to go to bed. I guess this will run several posts after all. :-)

In this post we’ve seen the basics of exporting, importing and composition in MEF. We’ve also touched on the concept of contracts and parts, which we will delve further into the future.

In the next post we’ll cover the following

  • Providing / Accessing export metadata
  • Other ways to import and a deeper look at contracts
  • Providing custom exports

PS: This is not my normal style of posting. I am following in the lead of my mentor, guru and overall awesome guy Brad Abrams. Please feel free to give feedback on how I can improve. I am looking forward to taking this trip with you.

Code is attached

This entry was posted in HelloMEF, MEF, silverlight, SL4. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • Noida

    where the code champ

  • Anonymous

    Hi,

    Thanks for the post! I just have a question please, I have tried this on
    SL4 Nav.App. and instead of mainPage i use the “Views.HomePage” and the rest
    is just the same. I have managed to view the widget1 within the HomePage
    and Nav away to “AboutPage” then when i try to nav back to Home i have had an
    error. How do i handle this because i am working with Nav.Apps all way
    along with SL4. THANKS!  

  • http://blogs.msdn.com/gblock Glenn Block

    Hi

    I’m at the “Keeping it Realtime” conference in Portland followed by vacation. Will return on Friday 11/11.

  • wcd

    Your images disappeared from this articles :( .

  • http://blogs.msdn.com/gblock Glenn Block

    OOF on vacation in China returning on 7/12/2011. Will have very little access to mail.

  • Subodh007_sp

    Part Initializer changed toCompositionInitializer.SatisfyImports(this);

  • Richard Waddell

    PartInitializer has apparently been renamed to CompositionInitializer.

    Thanks for the post, really easy to understand. Love the designer humor – I feel the same, except when I read an article by an actual designer who did take the time to REALLY try – I’m deeply humbled. : > )

  • Josh Gough

    Thanks Glenn, this is helping me a lot.

  • Adriaan Davel

    Hi Glenn,
    Thanks for the post, I’m considering this for allowing people to “upload” new technology to my applications (implemented by an interface), is this the correct technology for this? How will I store the uploads, and re-publish them to clients? (Storing is probably easy)
    If you already answered this, sorry :)

  • http://codebetter.com/members/gblock/default.aspx Glenn Block

    @Josh thanks, glad you like it.

  • http://blogger.forgottenskies.com Steve
  • http://blogger.forgottenskies.com Steve

    Glenn,

    Could you discuss how is this different than using an IOC container and injecting the correct usercontrol vs. using MEF ?

    Thank you

  • http://codebetter.com/members/gblock/default.aspx Glenn Block

    @Corrado, thanks and i will :-)

  • http://codebetter.com/members/gblock/default.aspx Glenn Block

    @Matt Herb you might want to check out my Prism/MEF post. Short answer, like all things “It depends” ;-)

  • http://codebetter.com/members/gblock/default.aspx Glenn Block

    @SilverlightTrainer It’s entirely possible though I don’t think anyone is looking at that yet. We’re certainly always pushing :-)

  • http://www.custom-training-courses.co.uk/Bespoke/UK/Silverlight/Course.aspx Silverlight Trainer

    This makes building silverlight dashboards soooo simple. Do you imaging Microsoft will include a dashboard usercontrol template in the future so all the developer need do is write the widgets?

  • http://codebetter.com/members/gblock/default.aspx Glenn Block

    @John I love that. :-)

    Kathleen Dollard uses a different analogy of kids in a Kindergarten. One kid (the importer) says “I need a fire-engine”. Another kid on the other side of the room says “I have a fire engine”. The teacher than brings the two kids together.

  • http://johnpapa.net John Papa

    Nice post Glenn. I finally got around to reading through it and I am glad I did. I like to think of Import and Export as the act of a parent (MEF) putting its 2 kids in different rooms. They are told to hang loose until the count of 3. When the parent (MEF again) says counts down and says “Go” (aka Composition), the 2 kids race towards each other to play. OK, not a great analogy, but seriously, I like that import and export don;t just know about each other. No automagic composition.

    Good stuff.

  • http://joshrobb.com Josh Robb

    Glen – thanks for the writeup! This was _really_ helpful.

  • http://codebetter.com/members/gblock/default.aspx Glenn Block

    Thanks guys, I added the code.

    @Fallon

    1. It’s called a dashboard, because it represents a pluggable dashboard like one would have in a portal style app.

    2. Attached now.

  • http://ctlabs.blogspot.com/ Sameer C Thiruthikad

    Thanks for the great post with new style. Can you please address making a Silverlight Navigation application using MEF so that each page or set of pages are loaded dynamically from different XAP files?

  • Corrado Cavalli

    Amazing post Glenn, I love this style, simple and clear please go on!

  • Fallon Massey

    I have two questions.

    1. Why is this called a Dashboard, and
    2. Where is the project for this posting?

    Thank You.

  • matt herb

    good!

    first MEF article I made it to the end and totally understood what I read

    I am still confused if I can use this instead of Prism though.. Id like to just concentrate on learning one for creating a decoupled app