从插件程序集将 WPF UI 加载到 MVVM 应用程序中 [英] Load WPF UI into MVVM application from plug-in assembly

查看:23
本文介绍了从插件程序集将 WPF UI 加载到 MVVM 应用程序中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一个应用程序,该应用程序使用插件架构来扩展其功能.从插件加载 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 the UserControl into a ContentControl. Also, since I am using the MVVM design pattern it seems that a DataTemplate would be preferred over a UserControl.
  • 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 the DataTemplate 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 get DataTemplates from. This problem would require any number of unknown assemblies to be searched for DataTemplates.

如果我选择第二个选项,我想我可以选择 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 并引用了ViewModelView 在启动时.该插件使用 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,包含对插件ViewViewModel 的引用.这是我们将用于 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);
}

一旦 DictinoaryViewModel 从我们的插件加载到我们的应用程序中,我们就可以使用例如 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆