为 WPF 应用程序创建加载项

Creating add-ons for WPF applications

我有一个简单的数据库应用程序,用户可以在其中添加或删除人员。此外,应用程序有一个按钮"Add new button to application"。此应用程序是使用 Prism 框架构建的。有两个模块:

我的要求是在运行时添加新按钮。

让我们想象一个情况。我住在华盛顿,我对这两个按钮(Add PersonDelete Person)很满意。但是我住在新泽西州的朋友 Bob 希望添加新按钮 Edit Button 而无需重新编译整个应用程序。也就是Bob在可以编辑person的地方写dll,然后在RibbonControlModule中点击Add new button to application。之后,EditPerson 按钮出现在 RibbonControl 中,例如 ContextMenu。也许 EditPerson dll 会是另一个 Prism 模块,我不知道。

即我的要求是:

是否可以使用 WPF、MVVM 和 Prism?我很喜欢Prism,不想否定Prism,但是如果"the end justifies the means",我想用其他技术。

如果可以,我该怎么做?

这就是 MEF plugin architecture 的设计目的。

简而言之,您创建一个包含插件接口的 SDK,并将其作为独立库提供给您的客户。然后,您客户端的插件会实现此接口并使用 MEF Export 属性导出它们,然后您的主应用程序会导入该属性。

有点棘手的是数据模板,这通常是 MVVM 的关键组件。长话短说,您的插件需要将它们的数据模板放在资源字典中,为该字典提供它自己的部分 class 文件,并使用 MEF 的 [Export] 属性导出它。然后您的主应用程序需要导入这些并将它们添加到全局 ResourceDictionary 的 'MergedDictionaries' 数组中。这通常与在单独的通道中导入的所有视图模型 classes 分开完成。最终效果是您的插件可以在运行时同时提供视图和视图模型,以及将两者绑定在一起的数据模板,并且它们都将像静态编译到您的原始应用程序中一样工作。这也意味着您可以为您的客户创建插件 API,而无需暴露主应用程序的内部结构。

这是一个非常复杂的话题,考虑到这个问题的普遍性,如果这个问题没有被标记,我会感到惊讶。如果您想了解更多详细信息,请告诉我,我们可以将其移至讨论页面。

您可以使用 Prism 中的区域来执行您所描述的操作。您可以将一个命名区域添加到您的功能区,允许 Prism 模块在模块首次加载时或稍后当用户单击您描述的某些 UI 模块中的按钮时将新按钮插入该区域。

为此,将 ItemsControl 添加到功能区内的某个窗格中,您希望插入的控件显示在该窗格中。将 prism 命名空间添加为 XAML 命名空间,如下所示:

xmlns:prism="http://prismlibrary/"

然后将以下附件 属性 添加到您的 ItemsControl 中:

prism:RegionManager.RegionName="CustomModuleCommandRegion"

然后在您的模块中,如果在加载模块后应立即添加命令,则在模块 class 本身中注入 IRegionManager,如果在特定的特定时间之前不会发生,则在 ViewModel 中的其他地方注入 IRegionManager视图已加载或您描述的某些用户交互:

public ConstructorForModuleOrViewModel(IRegionManager regionManager)
{
    _regionManager = regionManager;
}

private SomeCommandHandler()
{
    var commandButton = // create button and wire up command here)
    _regionManager.AddViewToRegion(commandButton, "CustomModuleCommandRegion");
}

您还可以选择使用区域管理器的 RegisterViewWithRegion 方法来设置工厂方法或仅指定要注入的视图类型(即按钮)。但是对于按钮,您需要在将其放入区域之前(或之后)连接一个命令处理程序,因此 AddViewToRegion 可能更合适。如果它是上下文相关的东西——即你只希望按钮显示在功能区中,也许是在视图中进行选择时——那么你可以先从区域管理器获取区域,然后使用 AddRemove 方法在 IRegion 上动态添加和删除您的视图(按钮),如下所示:

IRegion region = _regionManager.Regions["CustomModuleCommandRegion"];
region.Add(myCommandView);
...
region.Remove(myCommandView);

结合使用 Prism 模块和区域,您可以实现应用程序的运行时可扩展性 - 即此新功能可以 "dropped in" 而无需重新编译主应用程序或应用程序中的其他模块。为此,您需要使用任一配置来指定模块,以便可以在部署的环境中进行编辑以添加模块,或者您可以使用 DirectoryModuleCatalog 在启动时扫描目录以查找模块。甚至可以使用 FileSystemWatcher 来监视在应用程序 运行 时放入的模块的目录,并在放置在监视目录中时让它们立即亮起。