MEF and the CompositeWPF both offer distinct and very valuable services. MEF allows us to easily create Add-in components and the CompositeWPF makes it easy to decouple our services and views. Today I started integrating the two (reference MEF forum message).
Note: I am currently working on the Proof-Of-Concept (POC), when I have it completed it I will start TDD and refactor it as applicable. See FLASH DEMO HERE FULL SOURCE HERE (7meg) see notes under image.
My objective will be to make it as simple as possible to implement the integration without making any changes to the CompositeWPF or MEF libraries - all of the wiring up will be done in the MEFContrib.Library project.
Below you'll see the only code required in the App.xaml.cs code behind file:
Notice that I have the MEF, CompositeWPF and Unity source code under SRC - these are the complete source code packages. When the smoke settles I'll only upload DLLs, for now it will be helpful to step into code when it comes time to refactor.
Above the Parts folder contains MEF parts, they are compiled to the bin\Extensions folder. The bootstrapper references our MEFContrib.Library.
The bootstrapper code that pertains to the CompositeWPF follows below. The LoadReferencedModules class below tells the CompositeWPF to load all modules referenced by the BasicWPFApp - in our case it will be the RSSFeed module that I copied/pasted from a CompositeWPF demo I wrote earlier.
namespace MEFContrib.Library.Base
{
public class MEFBootStrapper : UnityBootstrapper
{
private Assembly _assembly;
private Application _application;
private MEFCompositionContainer _container;
/// <summary>
/// CompositeWPF
/// </summary>
/// <returns></returns>
protected override DependencyObject CreateShell()
{
_application.MainWindow.Show();
return _application.MainWindow;
}
/// <summary>
/// CompositeWPF
/// </summary>
/// <returns></returns>
protected override IModuleEnumerator GetModuleEnumerator()
{
Container.RegisterType<ILogger, TraceToolLogger>();
return LoadReferencedModules.GetModules(
_application.MainWindow.GetType());
}
/// <summary>
/// MEF
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
public MEFBootStrapper(object sender, BootStrapperEventArgs e)
{
_application = sender as Application;
_assembly = e.Assembly;
_application.Exit += new ExitEventHandler(_application_Exit);
if (Compose())
Run();
else
_application.Shutdown();
}
The Window1.xaml.cs code-behind file contains an earlier POC so I left it as is. Note there are no references to the MessageBoxLogger nor DebugLogger in our BasicWPFApp. MEF will load whatever it finds in the bin\extensions folder which happens to contain these two logging features.
The Windows XAML below has two region names "MainRegion" and "MainView".
<Window x:Class="BasicWPFApp.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cal="http://www.codeplex.com/CompositeWPF"
Title="Window1" Height="400" Width="600">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="25"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="2*" />
</Grid.ColumnDefinitions>
<StackPanel Orientation="Horizontal" Grid.ColumnSpan="2">
<TextBox Name="textBox1" Width="120">Hello World</TextBox>
<Button Name="button1" Width="57" Click="button1_Click">Debug</Button>
<Button Name="button2" Width="55" Click="button2_Click">MB</Button>
</StackPanel>
<GridSplitter Grid.Row="1" Width="10"/>
<ItemsControl Grid.Row="1" Name="MainRegion"
cal:RegionManager.RegionName="MainRegion" Margin="0,0,6,0">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<DockPanel/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
<ItemsControl Grid.Row="1" Grid.Column="1" Name="MainView"
cal:RegionManager.RegionName="MainView">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<DockPanel/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</Grid>
</Window>
When the RSSFeed module loads it will populate the MainRegion with the RSSFeedView, which in turn will populate the MainView RSSViewer.
namespace RSSFeed
{
[Module(ModuleName = "RSSFeedModule")]
public class RSSFeedModule : ModuleBase
{
/// <summary>
/// Injection Constructor
/// </summary>
/// <param name="regionManager">Registered IRegionManager</param>
/// <param name="container">Registered IUnityContainer</param>
/// <param name="presenter">Registered IMainPresenter</param>
public RSSFeedModule(IRegionManager regionManager,
IUnityContainer container)
{
RegionManager = regionManager;
Container = container;
}
protected override void RegisterViewsAndServices()
{
base.RegisterViewsAndServices();
// Add view to region
IRegion mainRegion = RegionManager.Regions["MainRegion"];
// Name it so we can move it later in MainController.cs
mainRegion.Add(Container.Resolve<RSSFeedView>(), "RssFeed");
}
public override void Initialize()
{
base.Initialize();
}
}
}
Tags:
mef,
compositewpf
Categories:
CompositeWPF |
MEF