How do I bind data from host to a plugin with MEF?
So the thing is:
MainViewModel
so every plugin can work with the actual data. UserControl
wich will be displayed as a ContentControl
in the MainViewModel
.What I have so far:
MainViewModel
MainViewModel
to View.What I need:
- the plugins need to bind the data from the MainViewModel
to the plugin UI.
- changing the property in the plugin UI must update the data in the MainViewModel
and update the UI from all other plugins.
The PluginInterfaces:
public interface IPlugin
{
}
public interface IPluginData
{
string Name { get; }
}
The MainViewModel: (part of it)
private MyModel myfirstmodel;
private DirectoryCatalog catalog;
private CompositionContainer container;
[ImportMany]
IEnumerable<Lazy<IPlugin, IPluginData>> Plugins;
public MainWindowViewModel()
{
string pluginPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
pluginPath = Path.Combine(pluginPath, "plugins");
if (!Directory.Exists(pluginPath))
Directory.CreateDirectory(pluginPath);
catalog = new DirectoryCatalog(pluginPath, "*.dll");
container = new CompositionContainer(catalog);
try
{
this.container.ComposeParts(this);
}
catch (CompositionException compositionException)
{
Console.WriteLine(compositionException.ToString());
}
}
The Model
public class MyModel
{
private string message;
private int number;
private DateTime date;
public string Message { get { return message; } set { message = value; } }
public int Number { get { return number; } set { number = value; } }
public DateTime Date { get { return date; } set { date = value; } }
}
The Plugin
[Export(typeof(IPlugin))]
[ExportMetadata("Name", "MyFirstPlugin")]
public partial class MyFirstPlugin : UserControl, IPlugin
{
public MyFirstPlugin()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
//Change the message in MainWindowViewModel and the date when it gets changed.
}
}
I tried using INotifyPropertyChanged
but did not came that far..
Does anybody got a really good tutorial for that or can show me how to do this?
I would appreciate a "how to" and not just a "just use INotifyPropertyChanged
".
Is this even possible?
Personally I think you're going about this the wrong way, MEF was specifically designed to do this type of plumbing so that you don't have to.
In a proper MVVM application the views usually get created by way of data templates, and even if you don't do this there is usually other global data you need to import like brushes and behaviours etc. And if you do use templates (which you really should be doing) then you don't need to explicitly export your controls; simply referencing them by the templates will result in them getting imported as well.
You can achieve this in practice with another pass of the importer. Give each plugin a custom ResourceDictionary and put all the global data/templates/UI resources etc in there (so it's effectively the plugin's version of App.xaml). The trick is to then give those ResourceDictionaries their own code-behind file and decorate those classes with Export. Then all your main application has to do is Import all the classes of type ResourceDictionary (or preferably a derived class or interface that returns the dictionary) and add each one to Application.Current.Resources.MergedDictionaries
. From that point on the development of your plugins is pretty much the same as if they were in a DLL project that you were statically linking the usual way.