如何使用MEF将数据从主机绑定到插件?
所以问题是:
MainViewModel
中,以便每个插件都可以使用实际数据。 UserControl
,将在ContentControl
中显示为MainViewModel
。到目前为止我所拥有的:
MainViewModel
MainViewModel
到视图的数据绑定。我需要什么:
- 插件需要将数据从MainViewModel
绑定到插件UI。
- 更改插件UI中的属性必须更新MainViewModel
中的数据并从所有其他插件更新UI。
PluginInterfaces:
public interface IPlugin
{
}
public interface IPluginData
{
string Name { get; }
}
MainViewModel:(部分内容)
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());
}
}
模型
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; } }
}
插件
[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.
}
}
我尝试使用INotifyPropertyChanged
但是没有那么远......
有没有人得到一个非常好的教程或者可以告诉我如何做到这一点?
我很感激&#34;如何&#34;而不仅仅是&#34;只需使用INotifyPropertyChanged
&#34;。
这甚至可能吗?
答案 0 :(得分:0)
对于使用ModelView的交换数据,您需要一个代表主机的接口。您还需要一个容器或方法来插入表示插件的可视控件。
interface IPluginHost
{
MyModelView ModelView {get;}
MyMainWindow View {get;}
}
interface IPlugin
{
void Register(IPluginHost host);
void Unregister();
}
在合成之后,您可以使用主机注册插件,这将使他们可以访问模型视图:
this.container.ComposeParts(this);
foreach(var plugin in Plugins)
{
plugin.Value.Register(this);
}
我需要: - 插件需要绑定数据 MainViewModel到插件UI。
插件可以访问MainViewModel的Register
方法,它可以执行所有必要的绑定。以下是可以采取的众多方法之一:
public partial class MyFirstPlugin : UserControl, IPlugin
{
...
void Register(IPluginHost host)
{
_host = host;
// Attach main model view as data context
this.DataContext = host.ModelView;
// Add control to the host's container
var mainWindow = host.View;
mainWindow.AddPluginControl((UserControl)this);
}
void Unregister()
{
if (_host == null)
{
return;
}
this.DataContext = null;
_host.View.RemovePluginControl(this);
_host = null;
}
IPluginHost _host;
}
AddPluginControl()
,RemovePluginControl()
是将插件的可视元素插入容器的公共方法。
答案 1 :(得分:0)
就我个人而言,我认为你的做法是错误的,MEF是专门为这种类型的管道设计的,所以你不必这样做。
在适当的MVVM应用程序中,视图通常通过数据模板创建,即使您不这样做,通常还需要导入其他全局数据,如画笔和行为等。如果使用模板(你真的应该这样做)然后你不需要明确地导出你的控件;简单地通过模板引用它们也会导致它们被导入。
您可以通过导入器的另一次传递在实践中实现此目的。为每个插件提供一个自定义的ResourceDictionary,并将所有全局数据/模板/ UI资源等放在那里(因此它实际上是插件的App.xaml版本)。诀窍是然后为这些ResourceDictionaries提供他们自己的代码隐藏文件,并使用Export装饰那些类。然后,您的所有主要应用程序必须执行的是导入ResourceDictionary类型的所有类(或者最好是返回字典的派生类或接口),并将每个类添加到Application.Current.Resources.MergedDictionaries
。从那时起,你的插件的开发就像它们在一个DLL项目中一样,你是静态链接通常的方式。