如何将数据从主机绑定到插件

时间:2015-10-01 17:10:48

标签: c# wpf mvvm data-binding mef

如何使用MEF将数据从主机绑定到插件?

所以问题是:

  • 我使用MVVM,因此我有我的模型,ViewModel和Views。
  • 我想使用MEF来扩展我的应用程序。
  • 我想将所有数据存储在MainViewModel中,以便每个插件都可以使用实际数据。
  • 该插件为UserControl,将在ContentControl中显示为MainViewModel

到目前为止我所拥有的:

  • MainViewModel
  • 模型
  • MainViewModel到视图的数据绑定。
  • 从文件夹X导入插件

我需要什么: - 插件需要将数据从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;。

这甚至可能吗?

2 个答案:

答案 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项目中一样,你是静态链接通常的方式。