简体   繁体   English

可插拔 .NET 4.5 功能区

[英]Pluggable .NET 4.5 Ribbon

I am looking for a way to provide a pluggable way to add items to the .NET 4.5 ribbon, and have made a few strides in doing so, but not quite the way I'd like it:我正在寻找一种方法来提供一种可插入的方式来向 .NET 4.5 功能区添加项目,并且在这方面取得了一些进展,但并不完全是我想要的方式:

[InheritedExport]
public interface IRibbonItem
{
    void Compose(DesignerRibbon ribbon);
}

public class TestItem : IRibbonItem
{
    public void Compose(CustomRibbon ribbon)
    {
        ribbon.ApplicationMenu.Items.Add((new RibbonApplicationMenuItem() { Header = "_Hello, World!" }));
    }
}

public class MEFRibbon : System.Windows.Controls.Ribbon.Ribbon
{
    [ImportMany]
    private IEnumerable<IRibbonItem> _oRibbons = null;

    public MEFRibbon() : base()
    {
         this.ApplicationMenu = new RibbonApplicationMenu();
         MEFHelper.Instance.ComposeParts(this);
         this._oRibbons.ToList().ForEach(x => x.Compose(this));
    }
}

While this works, it seems messy.虽然这有效,但看起来很混乱。 I'd prefer to write all of the plugins' content in XAML.我更喜欢用 XAML 编写所有插件的内容。 Is there a way I can achieve this goal?有没有办法实现这个目标?

Everything I've looked at references the old Ribbon or some other library.我看过的所有内容都引用了旧的 Ribbon 或其他一些库。

Thanks.谢谢。

I had the same issues so far.到目前为止,我遇到了同样的问题。 The goals I've planned to achieve:我计划实现的目标:

  • The application should be extensible via plugins.该应用程序应该可以通过插件进行扩展。
  • Application plugins should be able to add their own UI content into predefined UI regions: ribbon tabs, ribbon application menu, ribbon quick access toolbar and status bar.应用程序插件应该能够将自己的 UI 内容添加到预定义的 UI 区域:功能区选项卡、功能区应用程序菜单、功能区快速访问工具栏和状态栏。
  • The application should be built within MVVM architecture as close, as it possible.应用程序应尽可能在 MVVM 架构中构建。
  • Plugin developer should be able to describe UI content in XAML.插件开发人员应该能够在 XAML 中描述 UI 内容。 There shouldn't be any view model types, which reproduce hierarchy of ribbon controls (such as RibbonTabViewModel , RibbonButtonViewModel , etc), because this leads to parallel hierarchy of classes, and limits the abilities of XAML.不应该有任何视图模型类型来重现功能区控件的层次结构(例如RibbonTabViewModelRibbonButtonViewModel等),因为这会导致类的并行层次结构,并限制 XAML 的能力。
  • Plugins should use MEF to be loaded into host application.插件应使用 MEF 加载到主机应用程序中。

Here's the approach I've used.这是我使用的方法。
All my plugins are decorated with [ApplicationExtension(...)] and implement IApplicationExtension :我所有的插件都装饰有[ApplicationExtension(...)]并实现IApplicationExtension

public interface IApplicationExtension
{
    void Startup();
    bool CanShutdown();
    void Shutdown();
}

ApplicationExtension is declared as: ApplicationExtension声明为:

[MetadataAttribute]
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public sealed class ApplicationExtensionAttribute : ExportAttribute, IApplicationExtensionMetadata
{
    public ApplicationExtensionAttribute(/* ... */)
        : base(typeof(IApplicationExtension))
    {
        this.Name = name;
        this.UICompositionOrder = uiCompositionOrder;
    }

   // ...
}

IApplicationExtensionMetadata - some metadata, such as display name, etc. IApplicationExtensionMetadata - 一些元数据,例如显示名称等。

Host application, in turn, implements this interface:反过来,主机应用程序实现了这个接口:

public interface IApplicationInfrastructureProvider : IInfrastructureProvider
{
    ICollection<ViewModel> RibbonTabs { get; }
    ICollection<ViewModel> ApplicationMenuItems { get; }
    ICollection<ViewModel> QuickAccessToolbarItems { get; }
    ICollection<ViewModel> StatusBarItems { get; }
}

where ViewModel - some base view model class, and loads plugins via MEF:其中ViewModel - 一些基本视图模型类,并通过 MEF 加载插件:

    [ImportMany]
    private IEnumerable<Lazy<IApplicationExtension, IApplicationExtensionMetadata>> Extensions { get; set; }

When application initializes, it calls Startup method for each plugin.当应用程序初始化时,它为每个插件调用Startup方法。
Here plugin implementation is able to add tabs, menu items, etc. via IApplicationInfrastructureProvider as view models to extend application's UI.这里插件实现能够通过IApplicationInfrastructureProvider添加选项卡、菜单项等作为视图模型来扩展应用程序的 UI。

Note, that these view models are not any RibbontTabViewModel or RibbonButtonViewModel .请注意,这些视图模型不是任何RibbontTabViewModelRibbonButtonViewModel They are just some pieces of functionality.它们只是一些功能。

How it works at the UI side.它是如何在 UI 端工作的。
When, for example, RibbonTabs collection is changed, application calls custom service, which performs this job:例如,当RibbonTabs集合发生更改时,应用程序会调用自定义服务,该服务执行此工作:

  • First, it lookups a resource dictionary for the view model.首先,它查找视图模型的资源字典。 For simplicity, I'm using naming conventions: if the type of tab view model is MyCustomVm , the service looks for MyCustom.xaml in the same assembly.为简单起见,我使用命名约定:如果选项卡视图模型的类型是MyCustomVm ,则该服务会在同一程序集中查找MyCustom.xaml
  • Second, the service explores resource dictionary and looks for resource, whose key ends with _RibbonTabKey .其次,该服务探索资源字典并查找其键以_RibbonTabKey结尾的资源。 View model becomes the data context of found resource.视图模型成为找到的资源的数据上下文。 This assumes, that resource is at least FrameworkElement .这假设资源至少是FrameworkElement
  • Third, the found resource is being added to RibbonTabsUI collection of host application.第三,找到的资源被添加到宿主应用程序的RibbonTabsUI集合中。

The ribbon is bound to the RibbonTabsUI in XAML for host application:功能区绑定到主机应用程序的 XAML 中的RibbonTabsUI

<r:Ribbon x:Name="ribbon" Grid.Row="0" ItemsSource="{Binding RibbonTabsUI}">
    <!-- other content -->
</r:Ribbon>

The sample of ribbon tab looks like this:功能区选项卡的示例如下所示:

<r:RibbonTab x:Key="MyCustom_RibbonTabKey" x:Shared="False">
    <r:RibbonGroup Header="Some group">
        <!-- other content -->
    </r:RibbonGroup>
    <!-- other content -->
</r:RibbonTab>

ApplicationMenuItems and QuickAccessToolbarItems are being processed the same way, the difference is the resource key suffix. ApplicationMenuItemsQuickAccessToolbarItems的处理方式相同,区别在于资源键后缀。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM