I am working on an application that uses a plug-in architecture to expand it's functionality. What is the best way to load WPF UIs from a plug-in?
I will have a listbox listing all of the available plug-ins. When a plug-in is selected, a WPF UI defined in the plug-in should be displayed in a ContentControl
. The options I have thought of include:
- Require a
UserControl
to be created that implements a specific interface. I am thinking this would make it easy for plug-in creation. Implement an interface and you are good to go. My question with this method is how to dynamically load theUserControl
into aContentControl
. Also, since I am using the MVVM design pattern it seems that aDataTemplate
would be preferred over aUserControl
. - Allow a
DataTemplate
to be loaded from the plug-in. I believe this would require the plug-in to contain a XAML file named a certain way. My application would read theDataTemplate
into my resource dictionary like shown in this question. I have seen quite a few questions similar to this, except they usually only need to load one additional, predefined assembly to getDataTemplates
from. This problem would require any number of unknown assemblies to be searched forDataTemplates
.
If I choose the second option, I think I could select the DataTemplate
similarly to how this answer describes.
Which method do you think is better? Or do you have a better way to accomplish this?
I did something similar like mentioned with
DataTemplates
. I used MEF to load plugins and then loaded aDictionary
with a reference to theViewModel
andView
at startup. The plugin isbuilt using 3 main components.IBasePlugin.cs
This simple interface allows us to create a skeleton for the plugin. This will only contains the very basics, as this is what we will use to
Import
plugins to our main application usingMEF
.Plugin.cs
The next part is the
Plugin.cs
file. It contains all the properties of our plugin, as well as all the necessary references; such as to ourView
&ViewModel
.View.xaml
This is a
DataTemplate
containing a Reference to the pluginView
andViewModel
. This is what we will use forPlugin.cs
to load into the main application, so that the application andWPF
will know how to bind everything together.We then use MEF to load all the plugins, feed them to our Workspace
ViewModel
responsible of handling the Plugins, and store them in anObservableCollection
that will be used to display all the available plugins.The code we use to load plugins can look something like this.
Once both the
Dictinoary
andViewModel
has been loaded from our Plugin into our application we can display the collection using for example aTabControl
.I also gave a similar answer here as well with some additional details that you might find interesting.
It sounds like what you are looking for has already been accomplished with Prism. You define regions and then modules get loaded at runtime that may or may not have views for those regions. This works if all your applications are built against the modularity concepts derived from Prism. There are others out there, but Prism has this taken care of pretty extensively.
I use a similar approach to Fuji. The only difference is that I export the
ViewModel
and theResourceDictionary
independently from each other so they are still loosely coupled.In my plugin application I add all
ResourceDictionaries
.app.xaml.cs
For the sake of completeness