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="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="https://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="https://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="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="https://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="https://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.

https://cid-f8b2fd72406fb218.skydrive.live.com/self.aspx/blog/Hello%20MEF/HelloMEF%5E_Part%5E_I.zip