如何将数据从主机绑定到插件
How to bind data from host to plugin
如何使用 MEF 将数据从主机绑定到插件?
所以事情是:
- 我使用 MVVM,所以我有我的模型、视图模型和视图。
- 我想使用 MEF 来扩展我的应用程序。
- 我想将所有数据存储在
MainViewModel
中,这样每个插件都可以使用实际数据。
- 该插件是
UserControl
,它将在 MainViewModel
中显示为 ContentControl
。
我目前拥有的:
MainViewModel
- 型号
- 从
MainViewModel
到视图的数据绑定。
- 从文件夹 X 导入插件
我需要的:
- 插件需要将数据从 MainViewModel
绑定到插件 UI。
- 更改插件 UI 中的 属性 必须更新 MainViewModel
中的数据并更新所有其他插件中的 UI。
插件接口:
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
但没达到那么远..
是否有人为此提供了非常好的教程,或者可以告诉我如何操作?
我希望 "how to" 而不仅仅是 "just use INotifyPropertyChanged
".
这可能吗?
要与 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);
}
What I need: - the plugins need to bind the data from the
MainViewModel to the plugin UI.
插件可以在它的 Register
方法中访问 MainViewModel,它可以执行所有必要的绑定。这是可以完成的多种方法之一:
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()
是 public 将插件的可视元素插入容器的方法。
就我个人而言,我认为您的做法是错误的,MEF 是专门为执行此类管道而设计的,因此您不必这样做。
在适当的 MVVM 应用程序中,视图通常是通过数据模板创建的,即使您不这样做,通常也需要导入其他全局数据,例如画笔和行为等。如果您这样做使用模板(你真的应该这样做)然后你不需要显式导出你的控件;简单地通过模板引用它们将导致它们也被导入。
您可以通过导入程序的另一遍在实践中实现这一点。给每个插件一个自定义的 ResourceDictionary 并将所有全局 data/templates/UI 资源等放在那里(所以它实际上是插件版本的 App.xaml)。诀窍是为那些 ResourceDictionaries 提供它们自己的代码隐藏文件,并用 Export 装饰 those classes。然后,您所有的主要应用程序所要做的就是导入 ResourceDictionary 类型的所有 classes(或者最好是派生的 class 或 returns 字典的接口)并将每一个添加到 Application.Current.Resources.MergedDictionaries
.从那时起,您的插件开发就好像它们在您以通常方式静态链接的 DLL 项目中一样。
如何使用 MEF 将数据从主机绑定到插件?
所以事情是:
- 我使用 MVVM,所以我有我的模型、视图模型和视图。
- 我想使用 MEF 来扩展我的应用程序。
- 我想将所有数据存储在
MainViewModel
中,这样每个插件都可以使用实际数据。 - 该插件是
UserControl
,它将在MainViewModel
中显示为ContentControl
。
我目前拥有的:
MainViewModel
- 型号
- 从
MainViewModel
到视图的数据绑定。 - 从文件夹 X 导入插件
我需要的:
- 插件需要将数据从 MainViewModel
绑定到插件 UI。
- 更改插件 UI 中的 属性 必须更新 MainViewModel
中的数据并更新所有其他插件中的 UI。
插件接口:
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
但没达到那么远..
是否有人为此提供了非常好的教程,或者可以告诉我如何操作?
我希望 "how to" 而不仅仅是 "just use INotifyPropertyChanged
".
这可能吗?
要与 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);
}
What I need: - the plugins need to bind the data from the MainViewModel to the plugin UI.
插件可以在它的 Register
方法中访问 MainViewModel,它可以执行所有必要的绑定。这是可以完成的多种方法之一:
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()
是 public 将插件的可视元素插入容器的方法。
就我个人而言,我认为您的做法是错误的,MEF 是专门为执行此类管道而设计的,因此您不必这样做。
在适当的 MVVM 应用程序中,视图通常是通过数据模板创建的,即使您不这样做,通常也需要导入其他全局数据,例如画笔和行为等。如果您这样做使用模板(你真的应该这样做)然后你不需要显式导出你的控件;简单地通过模板引用它们将导致它们也被导入。
您可以通过导入程序的另一遍在实践中实现这一点。给每个插件一个自定义的 ResourceDictionary 并将所有全局 data/templates/UI 资源等放在那里(所以它实际上是插件版本的 App.xaml)。诀窍是为那些 ResourceDictionaries 提供它们自己的代码隐藏文件,并用 Export 装饰 those classes。然后,您所有的主要应用程序所要做的就是导入 ResourceDictionary 类型的所有 classes(或者最好是派生的 class 或 returns 字典的接口)并将每一个添加到 Application.Current.Resources.MergedDictionaries
.从那时起,您的插件开发就好像它们在您以通常方式静态链接的 DLL 项目中一样。