MAF consists of the following assemblies
MAF gives your application the following benefits (at the expense of extra complexity and a steeper learning curve)
By the end of this article you should be able to produce something like below. I know it doesnât look like much, but itâs tackling a very specific scenario for a hobby project I am working on currently. The goal is to create a host WPF app that allows me (or third parties) to write addins for the host that will render custom WPF UI and allow interaction with the rest of the application.
Below we have a very basic WPF window with a TabControl. The cool thing about this application is that the TabControl is databound to an AddIn collection â the tabs themselves as well as the tab content are entirely rendered at runtime from an AddIn via the Managed AddIn framework.
The first thing you need to be (painfully) aware of, is the project/directory structure that the MAF Pipeline requires. There is some flexibility here but not a whole lot of wiggle room. Thankfully, the only project I have to concern myself with is the Contract assembly (CouchPotato.AddIn.Contract below). With a proper directory structure in place you can use a tool that the MAF team released called Pipeline Builder to generate the necessary MAF projects for you automatically. The arrows below indicate which projects were generated by Pipeline Builder â it is important to understand that the only project/code I actually wrote in this entire solution is the ICouchPotatoAddInContract.cs. Please see the screencast above or the resources below for more details on Pipeline Builder.
Ok letâs get started. The following instructions will create the optimal directory/project structure for a MAF-based application.
[AddInContract]
public interface ICouchPotatoAddInContract : IContract
{
string Name { get; }
string Description { get; }
void Initialize();
INativeHandleContract HomeScreen { get; }
}
[assembly: PipelineHints.SegmentAssemblyName(PipelineHints.PipelineSegment.HostView, "CouchPotato.AddIn.HostView")]
[assembly: PipelineHints.SegmentAssemblyName(PipelineHints.PipelineSegment.AddInView, "CouchPotato.AddIn.AddInView")]
[assembly: PipelineHints.SegmentAssemblyName(PipelineHints.PipelineSegment.HostSideAdapter, "CouchPotato.AddIn.HostSideAdapters")]
[assembly: PipelineHints.SegmentAssemblyName(PipelineHints.PipelineSegment.AddInSideAdapter, "CouchPotato.AddIn.AddInSideAdapters")]
Now that our AddIn Pipeline is complete letâs create the host application.
Open a new instance of Visual Studio and create a new WPF Project, create it inside the same parent folder that we used for our Contracts project.
<TabControl x:Name="PluginContainer" TabStripPlacement="Bottom">
<TabControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Name}" />
</StackPanel>
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate>
<Grid>
<ContentPresenter Content="{Binding HomeScreen}" />
</Grid>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
public Window1()
{
InitializeComponent();
AddInStore.Update(PipelineStoreLocation.ApplicationBase);
Collection<AddInToken> addinTokens = AddInStore.FindAddIns(typeof(ICouchPotatoAddIn), PipelineStoreLocation.ApplicationBase);
ObservableCollection<ICouchPotatoAddIn> addins = new ObservableCollection<ICouchPotatoAddIn>();
foreach (AddInToken addinToken in addinTokens)
{
ICouchPotatoAddIn addin = addinToken.Activate<ICouchPotatoAddIn>(AddInSecurityLevel.Internet);
addins.Add(addin);
}
PluginContainer.ItemsSource = addins;
}
For this last step we are going to create a fake PhotoGallery AddIn.
Set the AddIn output to a specific directory within the output/AddIns folder, for example:
<UserControl x:Class="CouchPotato.PhotoGalleryAddIn.PhotoGalleryControl"
xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
Height="300" Width="300">
<Grid>
<TextBlock Text="Happy Photos!" />
</Grid>
</UserControl>
Lastly, create a the WeatherAddIn.cs file
[AddIn("Photo Gallery", Version = "1.0.0.0")]
public class PhotoGalleryAddin : ICouchPotatoAddIn
{
private readonly PhotoGalleryControl _control;
public PhotoGalleryAddin()
{
_control = new PhotoGalleryControl();
}
public string Name
{
get { return "Photo Gallery"; }
}
public string Description
{
get { return "View all your photos"; }
}
public void Initialize()
{
}
public FrameworkElement HomeScreen
{
get { return _control; }
}
}
With any luck, hopefully you are able to run your host application and find the AddIn you created. There are a lot of working parts when you use the Managed AddIn Framework, and as such, there are many points of failure. As you can see there is a slight learning curve to utilize MAF but hopefully after this article and the Daniel Moth screencasts you should be pretty comfortable with the framework.
Â
Leave a Comment