I learnt how to inject WPF DataTemplates into a window using MEF

I am working on a WPF project where it needs to be able to support new item types dynamically. I am writing the core framework and other teams will produce functionality specific to certain object types.

This has all been working fine until I hit the scenario where I have a screen and a section of it needs to be built based on the object type.

In the non-extensible approach you would use a series of data templates which would then populate the section based on the item type.

However in my scenario these templates need to implemented by third parties. Wouldn’t it be nice to be able to inject these into the window at run-time.

We are using MEF for our extensibility and already have the means to inject custom controls into windows. However this problem seems more suited to using DataTemplates rather than having to know which control to inject.

The solution I have produced is as follows:

1. The user creates a data template in a resource dictionary and adds it to their assembly. Fairly standard stuff.

2. I have a static class (yes this could be injected as well) that locates a resource within an assembly.

    public static class ResourceLocator
{
/// <summary>
/// Gets the first matching resource of the type.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="assemblyName">Name of the assembly.</param>
/// <param name="resourceFilename">The resource filename.</param>
/// <returns></returns>
public static T GetResource<T>(string assemblyName, string resourceFilename) where T : class
{
return GetResource<T>(assemblyName, resourceFilename, String.Empty);
}

/// <summary>
/// Gets the resource by name
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="assemblyName">Name of the assembly.</param>
/// <param name="resourceFilename">The resource filename.</param>
/// <param name="name">The name.</param>
/// <returns></returns>
public static T GetResource<T>(string assemblyName, string resourceFilename, string name) where T : class
{
if (string.IsNullOrEmpty(assemblyName) || string.IsNullOrEmpty(resourceFilename))
return default(T);
string uriPath = string.Format("/{0};component/{1}", assemblyName, resourceFilename);
Uri uri = new Uri(uriPath, UriKind.Relative);
ResourceDictionary resource = Application.LoadComponent(uri) as ResourceDictionary;
if (resource == null)
return default(T);
if (!string.IsNullOrEmpty(name))
{
if (resource.Contains(name))
return resource[name] as T;
return default(T);
}
return resource.Values.OfType<T>().FirstOrDefault();
}
}


 



3. In the third party assembly it calls the ResourceLocator somewhere to locate the template:



m_template = ResourceLocator.GetResource<DataTemplate>("TheAssemblyName","Resources/TheResources.xaml");


Where the first parameter is the name of the assembly and the second in the name of the file with the resource (this could be in the static constructor).



4. This is where MEF kicks in. I now have a property that exposes this DataTemplate using a known contract name.



        [Export(MyTemplateContract)]
public DataTemplate MyTemplate
{
get { return m_template; }
}


5. In MEF I can now import all the instances of the MyTemplateContract and inject them into my window resources.



        private void LoadTemplates()
{
IEnumerable<DataTemplate> templates = Composer.GetExportedObjects<DataTemplate>(MyTemplateContract);
foreach (DataTemplate template in templates)
Resources.Add(template.DataTemplateKey, template);
}


And that’s it. Now the other teams can create a new data template, use the resource locator to find it and export it as a property. My application will then pick these up at run-time and inject them into the window.