从插件程序集将 WPF UI 加载到 MVVM 应用程序中 [英] Load WPF UI into MVVM application from plug-in assembly
问题描述
我正在开发一个应用程序,该应用程序使用插件架构来扩展其功能.从插件加载 WPF UI 的最佳方法是什么?
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?
我将有一个列出所有可用插件的列表框.选择插件后,插件中定义的 WPF UI 应显示在 ContentControl
中.我想到的选项包括:
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:
- 需要创建一个实现特定接口的
UserControl
.我认为这将使插件创建变得容易.实现一个接口,你就可以开始了.我对这种方法的问题是如何将UserControl
动态加载到ContentControl
中.此外,由于我使用的是 MVVM 设计模式,因此DataTemplate
似乎比UserControl
更受欢迎. - 允许从插件加载
DataTemplate
.我相信这将要求插件包含以某种方式命名的 XAML 文件.我的应用程序会将DataTemplate
读入我的资源字典,如 in this question. 我见过不少与此类似的问题,只是他们通常只需要加载一个额外的预定义程序集即可从中获取DataTemplates
.此问题需要搜索任意数量的未知程序集以查找DataTemplates
.
- 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
.
如果我选择第二个选项,我想我可以选择 DataTemplate
类似于 这个答案所描述的.
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?
推荐答案
我做了一些与 DataTemplates
提到的类似的事情.我使用 MEF 加载插件,然后加载了一个 Dictionary
并引用了ViewModel
和 View
在启动时.该插件使用 3 个主要组件构建.
I did something similar like mentioned with DataTemplates
. I used MEF to load plugins and then loaded a Dictionary
with a reference to the ViewModel
and View
at startup. The plugin isbuilt using 3 main components.
IBasePlugin.cs
这个简单的界面允许我们为插件创建一个框架.这将只包含非常基础的内容,因为这是我们将使用 MEF
将插件Import
用于我们的主应用程序的内容.
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 using MEF
.
public interface IBasePlugin
{
WorkspaceViewModel ViewModel { get; }
ResourceDictionary View{ get; }
}
插件.cs
下一部分是 Plugin.cs
文件.它包含我们插件的所有属性,以及所有必要的引用;例如我们的 View
&ViewModel
.
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 our View
& ViewModel
.
[Export(typeof(IBasePlugin))]
public class Plugin : IBasePlugin
{
[Import]
private MyPluginViewModel _viewModel { get; set; }
private ResourceDictionary _viewDictionary = new ResourceDictionary();
[ImportingConstructor]
public Plugin()
{
// First we need to set up the View components.
_viewDictionary.Source =
new Uri("/Extension.MyPlugin;component/View.xaml",
UriKind.RelativeOrAbsolute);
}
....Properties...
}
View.xaml
这是一个DataTemplate
,包含对插件View
和ViewModel
的引用.这是我们将用于 Plugin.cs
加载到主应用程序的内容,以便应用程序和 WPF
知道如何将所有内容绑定在一起.
This is a DataTemplate
containing a Reference to the plugin View
and ViewModel
. This is what we will use for Plugin.cs
to load into the main application, so that the application and WPF
will know how to bind everything together.
<DataTemplate DataType="{x:Type vm:MyPluginViewModel}">
<vw:MyPluginView/>
然后我们使用 MEF 加载所有插件,将它们提供给我们的工作区 ViewModel
负责处理插件,并将它们存储在用于显示所有可用插件的 ObservableCollection
中.
We then use MEF to load all the plugins, feed them to our Workspace ViewModel
responsible of handling the Plugins, and store them in an ObservableCollection
that will be used to display all the available plugins.
我们用来加载插件的代码看起来像这样.
The code we use to load plugins can look something like this.
var plugins = Plugins.OrderBy(p => p.Value.ViewModel.HeaderText);
foreach (var app in plugins)
{
// Take the View from the Plugin and Merge it with,
// our Applications Resource Dictionary.
Application.Current.Resources.MergedDictionaries.Add(app.Value.View)
// THen add the ViewModel of our plugin to our collection of ViewModels.
var vm = app.Value.ViewModel;
Workspaces.Add(vm);
}
一旦 Dictinoary
和 ViewModel
从我们的插件加载到我们的应用程序中,我们就可以使用例如 TabControl
来显示集合.
Once both the Dictinoary
and ViewModel
has been loaded from our Plugin into our application we can display the collection using for example a TabControl
.
<TabControl ItemsSource="{Binding Workspaces}"/>
我也给出了类似的答案 此处 以及一些您可能会感兴趣的其他详细信息.
I also gave a similar answer here as well with some additional details that you might find interesting.
这篇关于从插件程序集将 WPF UI 加载到 MVVM 应用程序中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!