backgroundTop
backgroundTop
Front Page
GreenBackgroundTop

Silverlight MEF

Silverlight MEF - Extensible Applications

MEF is all about extending applications. It allows you to specify a contract that "extenders" need to fulfill. But it's more. It also allows you to separate concerns in your application. MEF is now available for Silverlight. This screencast shows how to use MEF to make Silverlight applications extensible (by yourself or 3rd parties).

erikmork

7k Votes

GreenBackgroundBottom
 

Important Code

Mark as Inappropriate Content

This video is licensed under a Creative Commons License.

Creative Commons License Download the Video

Information From the Video

GreenBackgroundTop

MEF in Silverlight

We start with a simple Silverlight application, and we add the MEF project (can be found on Codeplex). This Silverlight project is created normally (you can start a Silverlight Application or Navigation Application or whatever you prefer).
GreenBackgroundBottom
    public partial class MainPage : UserControl
    {


        public MainPage()
        {
            InitializeComponent();
            GetData.Click += new RoutedEventHandler(GetData_Click);


        }

        void GetData_Click(object sender, RoutedEventArgs e)
        {
        }



    }
 
GreenBackgroundTop

MEF Takes over a Property

Here we tell MEF that it's responsible for finding the CityName
GreenBackgroundBottom
        [Import("CityName")]
        public string CityName;
 
GreenBackgroundTop

MEF Finds a Property

Here a property is decorated with a MEF attribute. This tells MEF to match this property up with an import property.
GreenBackgroundBottom
    public class City
    {
        [Export("CityName")]
        public string Name
        {
            get
            {
                return "Boston";
            }
            set { }
        }
    }
 
GreenBackgroundTop

MEF Marries the Imports and Exports

This code tells MEF to create a package based on the currently executing assembly. The CompositionContainer is then created, and the container matches up the exports with the imports (see the "ComposeParts" call).
GreenBackgroundBottom
            var catalog = new PackageCatalog();
            catalog.AddPackage(Package.Current);
            var container = new CompositionContainer(catalog);
            container.ComposeParts(this);

            OurTextBox.Text = CityName;
 
GreenBackgroundTop

Importing an ObservableCollection

The ImportMany attribute matches a single IEnumberable<T> with multiple, individual Ts. The AllowRecomposition paramater tells MEF that it's ok to add "Cities" exports whenever a package is added to the catalog. This is important in Silverlight MEF where packages can be added asynchronously.
GreenBackgroundBottom
        [ImportMany("Cities", AllowRecomposition=true)]
        public ObservableCollection<String> Cities{get;set;}
 
GreenBackgroundTop

Exports in Another .XAP

In this example, the "Cities" are coming from an external .xap file. To add an external .xap file, do 4 things: 1) Add a "Silverlight Application", 2) Add a reference to the new Silverlight Application, 3)Add a reference from the new application to MEF, 4)Set the new MEF reference to CopyLocal = False (makes the .xap file smaller as we already have a copy of MEF). Alternatively, you can also delete the App.xaml and MainPage.xaml from the new application as they won't be used. The exports in the separate .xap are similar to the ones we've seen before. However, these strings will be loaded into the single ObservableCollection<T>.
GreenBackgroundBottom
    public class CityContainer 
    {
        [Export("Cities")]
        public string City1 = "Chicago";

        [Export("Cities")]
        public string City2 = "Seattle";

        [Export("Cities")]
        public string City3 = "San Diego";



    }
 
GreenBackgroundTop

Dynamically Loading a .XAP

To dynamically load a .xap, set the reference to that .xap to CopyLocal=False. This will prevent the new .XAP from being downloaded and initialized along with the main application. We add a DownloadPackageAsync call which will trigger the download of the .xap *after* the main application has been started.
GreenBackgroundBottom
            var catalog = new PackageCatalog();
            catalog.AddPackage(Package.Current);
            Package.DownloadPackageAsync(new Uri("ExtendingApplication.xap", UriKind.Relative), (s, p) => catalog.AddPackage(p));
            var container = new CompositionContainer(catalog);
            container.ComposeParts(this);
 
GreenBackgroundTop

Downloading Based on User Interaction

Sometimes, we'll only want to download a .xap when a user has performed some action. In this example, the .xap is downloaded based on a button click. Once the .xap is downloaded, MEF will add that data to our running application (see the AllowRecomposition attribute).
GreenBackgroundBottom
        PackageCatalog catalog = new PackageCatalog();

        public MainPage()
        {
            InitializeComponent();
            GetData.Click += new RoutedEventHandler(GetData_Click);

            Cities = new ObservableCollection<string>();


            //var catalog = new PackageCatalog();
            catalog.AddPackage(Package.Current);
            var container = new CompositionContainer(catalog);
            container.ComposeParts(this);

            OurTextBox.Text = CityName;

            LayoutRoot.DataContext = Cities;
        }

        void GetData_Click(object sender, RoutedEventArgs e)
        {
            Package.DownloadPackageAsync(new Uri("ExtendingApplication.xap", UriKind.Relative), (s, p) => catalog.AddPackage(p));
        }
 
GreenBackgroundTop

Bringing in Code

Often, we want to use MEF to bring logic into our applications. In this example, we have a simple interface that we're using for our data Model.
GreenBackgroundBottom
    public interface IModel
    {
        string getData();

    }
 
GreenBackgroundTop

Exporting the Interface

Here, we export the implementation of an interface. Notice that the [Export] attribute requires an instance.
GreenBackgroundBottom
    public class ModelHolder
    {
        [Export]
        public IModel OurModel = new DataModel();
    }
    
    public class DataModel : IModel
    {

        #region IModel Members

        public string getData()
        {
            return "Moscow";
        }

        #endregion
    }
 
GreenBackgroundTop

Importing the Interface

The Import attribute doesn't require any parameters. This is because the type (IModel) is enough to specify the contract. MEF will use the type to determine how items get matched up.
GreenBackgroundBottom
        [Import]
        public IModel OurModel { get; set; }

//...
          OurTextBox.Text = OurModel.getData();
 
 
GreenBackgroundTop

References

Brad Abrams Post

This guide is based on Brad Abram's post.

Blenn Block's Blog

Glenn is deeply involved with MEF as well. His blog is here.

GreenBackgroundBottom
backgroundBottom
backgroundBottom