可插拔的.NET 4.5功能区

时间:2014-04-15 06:38:52

标签: c# .net ribbon

我正在寻找一种方法来提供一种可插入的方式来向.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));
    }
}

虽然这有效但看起来很混乱。我更喜欢写所有的插件&#39; XAML中的内容。有没有办法实现这个目标?

我所看到的所有内容都引用旧功能区或其他库。

感谢。

1 个答案:

答案 0 :(得分:2)

到目前为止,我遇到了同样的问题。 我计划实现的目标:

  • 应用程序应该可以通过插件进行扩展。
  • 应用程序插件应该能够将自己的UI内容添加到预定义的UI区域:功能区选项卡,功能区应用程序菜单,功能区快速访问工具栏和状态栏。
  • 应尽可能在MVVM架构内构建应用程序。
  • 插件开发人员应该能够在XAML中描述UI内容。不应该有任何视图模型类型,它们重现功能区控件的层次结构(例如RibbonTabViewModelRibbonButtonViewModel等),因为这会导致类的并行层次结构,并限制XAML的功能。
  • 插件应该使用MEF加载到主机应用程序中。

这是我用过的方法 我的所有插件都装有[ApplicationExtension(...)]并实施IApplicationExtension

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

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 - 一些元数据,例如显示名称等。

主机应用程序反过来实现此接口:

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

其中ViewModel - 一些基本视图模型类,并通过MEF加载插件:

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

当应用程序初始化时,它会为每个插件调用Startup方法 这里的插件实现能够通过IApplicationInfrastructureProvider作为视图模型添加选项卡,菜单项等,以扩展应用程序的UI。

请注意,这些视图模型不是任何RibbontTabViewModelRibbonButtonViewModel。它们只是一些功能。

如何在UI方面工作。
例如,当RibbonTabs集合发生更改时,应用程序会调用执行此作业的自定义服务:

  • 首先,它查找视图模型的资源字典。为简单起见,我使用命名约定:如果选项卡视图模型的类型为MyCustomVm,则服务在同一程序集中查找MyCustom.xaml
  • 其次,该服务探索资源字典并查找资源,其密钥以_RibbonTabKey结尾。视图模型成为找到的资源的数据上下文。假设该资源至少为FrameworkElement
  • 第三,找到的资源正被添加到主机应用程序的RibbonTabsUI集合中。

功能区绑定到XAML中的RibbonTabsUI以用于主机应用程序:

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

功能区选项卡示例如下所示:

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

ApplicationMenuItemsQuickAccessToolbarItems的处理方式相同,不同之处在于资源键后缀。