MEF for Beginner (Import from Xaml) – part 11

2010/03/20

MEF for Beginner (Import from Xaml) – part 11

this is the 11th post of the MEF for Beginner series, the series TOC is available here.

this post will focus on Importing mef parts directly from the Xaml.

Import, ImportMany, MEF, composition, CLR 4

the code sample for this post is available here.

 

assuming that we have the following exports:

Code Snippet
  1. class DemoStrings
  2. {
  3.     [Export("MyTag")]
  4.     public string Text1 { get { return "Hello world"; } }
  5.     [Export("MyTag")]
  6.     public string Text2 { get { return "export using custom attribute"; } }
  7.     [Export("NotMyTag")]
  8.     public string Text3 { get { return "not included (Not My Tag contract)"; } }
  9.     [Export("MyTag")]
  10.     public string Text4 { get { return "Wpf markup extension"; } }
  11.     [Export]
  12.     public string Text5 { get { return "not included (have no contract)"; } }
  13. }

 

we may want to have it import into the Xaml as follow:

Code Snippet
  1. <Window x:Class="Bnaya.Samples.MainWindow"
  2.         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3.         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4.         xmlns:mef="clr-namespace:Bnaya.Samples"
  5.         Title="MainWindow" Height="350" Width="525">
  6.     <Grid>
  7.         <ListBox
  8.                  DataContext="{mef:ImportManyStrings MyTag}"
  9.                  ItemsSource="{Binding}"/>
  10.     </Grid>
  11. </Window>

as you can see at line 8 the data context is using special definition for importing all exported strings that
define the their contract as MyTag (looking at the exports it will import the exports at lines 4,6,10).

 

what should we have in order to achieve that functionality?

actually very little, all we have to do is to define a markup extension that return the exported parts.

 

the following code is how the markup extension should be define:

Code Snippet
  1. [MarkupExtensionReturnType(typeof(IEnumerable<string>))]
  2. public class ImportManyStringsExtension : MarkupExtension
  3. {
  4.     private readonly IEnumerable<string> _dataSource;
  5.     public ImportManyStringsExtension(string contract)
  6.     {
  7.         _dataSource = CompositionHost.Provider.GetExportedValues<string>(contract);
  8.     }
  9.  
  10.     public override object ProvideValue(IServiceProvider serviceProvider)
  11.     {
  12.         return _dataSource;
  13.     }   
  14. }

line 1, decorate that our markup extension for returning IEnumerable<string>.

line 2, derive from MarkupExtension.

line 7, at the construction time, dynamically ask mef for any discoverable parts that follow the contract.

the CompositionHost is a very small helper class that was taken from the MEF Silverlight implementation

with some very minor enhancements.

lines 10-13, returning the discoverable parts to the Xaml.

 

One last thing

we should remove the StartupUri from the App.Xaml and using the OnStartup override instead:

Code Snippet
  1. protected override void OnStartup(StartupEventArgs e)
  2. {
  3.     base.OnStartup(e);
  4.  
  5.     if (!Utils.IsInDesignTool)
  6.     {
  7.         var asmCatalog = new AssemblyCatalog(typeof(App).Assembly);
  8.         var catalogs = new AggregateCatalog(asmCatalog);
  9.         var container = new CompositionContainer(catalogs);
  10.         CompositionHost.Initialize(container);
  11.         container.Compose(new CompositionBatch());
  12.         
  13.         var root = new MainWindow();
  14.         root.ShowDialog();
  15.     }
  16. }

line 5, preventing MEF operation during design time.

lines 7-9, setting the MEF container.

line 10, setting the MEF container as the main container of the application

(this way it can be reachable anywhere).

line 11, do the composition,

IMPOERANT: the composition should happens before the window instantiation,

because that when the markup extension will be invoke.

the exported part should be available at this time.

lines 13-14, starting the application.

 

Summary

we can extend the Xaml very easily in order to get better Xaml->Mef experience.

 

the code sample for this post is available here.

 

תגים של Technorati:‏ ,,,,

 

kick it on DotNetKicks.com


Add comment
facebook linkedin twitter email

Leave a Reply

Your email address will not be published. Required fields are marked *

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=""> <strike> <strong>