MEF for Beginner – Part 4 (a-sync Silverlight loading)

2009/12/26

iStock_000005308317XForIcon 

MEF for Beginner – Part 4 (a-sync Silverlight loading)

in this post we will continue from the point that we left our Silverlight application at part 3 of this series.

the post will focus on how to consume external plug-ins using a-sync loading into Silverlight application using MEF.

you can find more about the MEF on part 1, part 2 and part 3 of this series.

 

this post is written on Visual Studio 2010 and Silverlight 4.0 (using Visual studio 2008 and Silverlight 3

will need some minor modification and download the MEF Silverlight 3 bits from the MEF site).

 

the code sample for this post can be download from here.

if you want to start from our previous post code, you can download it from here.

 

Step 1: Download the Silverlight 4 Beta Toolkit

downloading a-sync Silverlight Packages (XAP) does not include in in the box at this point (i hope it will on the release time),

so you have to download the Silverlight 4 Beta Toolkit, which you can download here. You’ll need latter on this post.

 

Step 2: Create XAP (Silverlight App) for the new plug-in

the a-sync discovery technique  that we are going to use in this post, will search for plug-ins in XAP files

that was deployed at the same virtual folder as our shell application deployed.

therefore we have to create Silverlight application rather then Silverlight class library.

 

create Silverlight application.

mef silverlight .net 4 clr 4

 

before approving the new application you have to uncheck the "make it the start page" check box

so it will keep the current Silverlight application as the startup application.

mef silverlight

 

Step 2.1: delete the App.xaml

delete the app.xaml from the plug-in application, we don’t need it there.

 

Step 3: add reference to MEF

before adding the plug-able functionality, we have to add reference to MEF.

add new reference and browse for System.ComponentModel.Composition.dll under the following folder:

64 bit: C:\Program Files (x86)\Microsoft SDKs\Silverlight\v4.0\Libraries\Client

32 bit: C:\Program Files\Microsoft SDKs\Silverlight\v4.0\Libraries\Client

mef silverlight

 

Step 4: Change the main page xaml (plug-in application)

at the plug-in application that we created in the previous step, change the MainPage.xaml to:

Code Snippet
  1. <Grid x:Name="LayoutRoot" Background="White">
  2.     <Button Command="{Binding}" Width="Auto" Height="Auto">
  3.         <TextBlock Text="External plug"/>
  4.     </Button>
  5. </Grid>

we are using the main page as our plug-in.

 

Step 5: Expose the plug-in

go the the code behind of the plug-in MainPage.xaml and decorate the class with the following Export attribute:

Code Snippet
  1. [Export(typeof(UserControl))]
  2. public partial class MainPage : UserControl, ICommand
  3. {
  4.     public MainPage()
  5.     {
  6.         InitializeComponent();
  7.  
  8.         DataContext = this;
  9.     }

add using to System.ComponentModel.Composition

and set the DataContext to this.

 

Step 5.1: Add Imports

adding imports for the exposed shell TextBlock and Border.

Code Snippet
  1. [Import]
  2. public TextBlock ShellText { get; set; }
  3.  
  4. [Import]
  5. public Border ShellBorder { get; set; }

 

Step 6: implement the ICommand interface

add the ICommand to the inheritance of the class and implement the interface.

the Execute method should look like the following code:

Code Snippet
  1. public void Execute(object parameter)
  2. {
  3.     ShellText.Text = "External plug";
  4.     ShellText.FontSize = 32.0;
  5.     ShellBorder.Background = new SolidColorBrush(Colors.Yellow);
  6.     var grdCol = new GradientStopCollection();
  7.     grdCol.Add (new GradientStop { Color=Colors.Green, Offset=0});
  8.     grdCol.Add (new GradientStop { Color=Colors.Purple, Offset=0.25});
  9.     grdCol.Add (new GradientStop { Color=Colors.Orange, Offset=0.5});
  10.     grdCol.Add (new GradientStop { Color=Colors.Blue, Offset=0.75});
  11.     var brush = new LinearGradientBrush (grdCol,45);
  12.     ShellText.Foreground = brush;
  13. }

 

Step 7: A-Sync composition

add reference to the System.ComponentModel.Composition.Packaging.Toolkit.dll to the shell project

you should find it at:

C:\Program Files (x86)\Microsoft SDKs\Silverlight\v4.0\Toolkit\Nov09\Bin\System.ComponentModel.Composition.Packaging.Toolkit.dll   for 64 bit

C:\Program Files\Microsoft SDKs\Silverlight\v4.0\Toolkit\Nov09\Bin\System.ComponentModel.Composition.Packaging.Toolkit.dll   for 32 bit

 

Step 7.1: Allow Recomposition

the a-sync composition will result in re-adding plug-ins to the existing plug-ins collection,

this behavior required to modify the Import policy to allow recomposition.

at the shell project, MainPage.xaml code behind, modify the import declaration to:

Code Snippet
  1. [ImportMany (AllowRecomposition=true)]
  2. public ObservableCollection<UserControl> ToolbarItems { get; set; }

 

Step 7.2: Minor changes to the InitializeContainer method

because we will need the PackageCatalog latter for adding the new

discovered packages we have to take it out to the class level scope.

at the app.xaml code behind , change the InitializeContainer  method as follow:

Code Snippet
  1. PackageCatalog _catalogs = new PackageCatalog();
  2. private void InitializeContainer(UIElement mainWin)
  3. {
  4.     _catalogs = new PackageCatalog();
  5.     _catalogs.AddPackage(Package.Current);
  6.     var mainWinPart = AttributedModelServices.CreatePart(mainWin);
  7.     var batch = new CompositionBatch(new[] { mainWinPart }, null);
  8.     var container = new CompositionContainer(_catalogs);
  9.     container.Compose(batch);
  10. }

 

Step 7.3: Loading external plug-ins
Code Snippet
  1. private void Application_Startup(object sender, StartupEventArgs e)
  2. {
  3.     this.RootVisual = new MainPage();
  4.     InitializeContainer(this.RootVisual);
  5.     var uri = new Uri("MyPlugIn.xap", UriKind.Relative);
  6.     Package.DownloadPackageAsync(uri,
  7.         (args, p) =>
  8.         {
  9.             Thread.Sleep(3000);// just waiting in order to emphasize the a-sync effect
  10.             _catalogs.AddPackage(p);
  11.         });
  12. }

lines 5-11 are responsible for the a-sync package loading.

 

Summary

the a-sync pattern is really powerful, and we can benefit from better startup time of the

Silverlight application by pushing heavy loading into plug-able components (which will be loaded a-sync).

another benefit is the capability of on demand plug-ins loading.

 

Downloads

the code sample for this post can be download from here.

you will need Silverlight 4 and the Silverlight 4 toolkit. You can download Silverlight 4 beta  here and the toolkit here.

 

Learn More

you can find more information on how to use MEF over Silverlight in the following posts (by Glenn Block):

Building Hello MEF – Part III – XAP Partitioning (with the host’s permission) and the sweetness of recomposition.

 

Point of Interest

if you living in Israel you can hear me speaking about MEF at the SDP at Monday 28.12.2009 (mark your calendar)

Sela Developer Practice (SDP)

Digg This
Add comment
facebook linkedin twitter email

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*