创建功能区应用程序

Windows 功能区框架由两个不同但依赖的开发平台组成:一种基于可扩展应用程序标记语言的标记语言 (XAML) 声明控件及其可视布局;一种 C++ 组件对象模型 (COM) 一组用于定义命令功能和应用程序挂钩的接口。 功能区框架体系结构中的这种分工要求想要利用框架提供的丰富 UI 功能的开发人员必须在标记中设计和描述 UI,然后使用功能区框架 COM 接口将框架连接到主机应用程序。

功能区路线图

功能区应用程序的可视方面(例如控件的显示和放置位置)在标记中声明 (请参阅 使用功能区标记声明命令和控件) 。 应用程序命令逻辑(例如按下按钮时发生的情况)在代码中实现。

实现功能区并将其合并到 Windows 应用程序的过程需要四个基本任务:编写标记、编译标记、编写代码以及编译和链接整个应用程序。

下图演示了典型功能区实现的工作流。

显示典型功能区实现工作流的示意图。

以下部分更详细地介绍了此过程。

编写标记

设计功能区 UI 后,应用程序开发人员的第一个任务是使用功能区标记描述 UI。

重要

功能区框架标记架构文件 UICC.xsd 随适用于 Windows 7 和 .NET Framework 4.0 的 Microsoft Windows 软件开发工具包 (SDK) 一起安装。 使用标准安装路径,该文件位于 %ProgramFiles%\Microsoft SDKs\Windows\[版本号]\Bin 文件夹中,许多 XML 编辑器可在其中引用它以提供提示和自动完成。

 

功能区控件、功能区命令 (控件无关的元素,这些元素为功能区控件) 提供基本功能,并且所有控件布局和视觉关系都在标记中声明。 功能区标记的结构通过两个主要节点层次结构强调功能区控件与命令之间的区别: 命令和资源 树和 视图 树。

功能区公开的所有容器和操作都在 命令和资源 树中声明。 根据 UI 设计的要求,每个 Command 元素都与一组资源相关联。

为应用程序创建命令后,在 视图 树中声明控件,并将每个控件绑定到命令以公开命令功能。 功能区框架根据此处声明的控件层次结构确定控件的实际位置。

下面的代码示例演示了如何声明 Button 控件、标记为“退出”应用程序,并将其与 Exit 命令相关联。

<Application xmlns="http://schemas.microsoft.com/windows/2009/Ribbon">
  <Application.Commands>
    <Command Name="cmdExit" LabelTitle="Exit application" />
  </Application.Commands>

  <Application.Views>
    <Ribbon>
      <Ribbon.Tabs>
        <Tab>
          <Group>
            <Button CommandName="cmdExit" />
          </Group>
        </Tab>
      </Ribbon.Tabs>
    </Ribbon>
  </Application.Views>
</Application>
        

提示

虽然可以将任何文件扩展名用于功能区标记文件,但建议使用 .xml 整个文档。

 

编译标记

创建功能区标记文件后,它必须由功能区标记编译器、UI 命令编译器 (UICC) 编译为二进制格式,该格式包含在 Windows 软件开发工具包 (SDK) 。 在主机应用程序初始化功能区框架期间,对此二进制文件的引用将传递给 IUIFramework::LoadUI 方法。

UICC 可以直接从命令行窗口执行,也可以在 Visual Studio 中添加为“自定义生成步骤”。

下图显示了 Windows 7 SDK CMD Shell 窗口中的 UICC 标记编译器。

显示命令行窗口中uicc.exe的屏幕截图。

下图显示了在 Visual Studio 中添加为自定义生成步骤的 UICC。

显示uicc.exe添加为 Visual Studio 中的自定义生成步骤的屏幕截图。

UICC 生成三个文件:标记 (.bml) 的二进制版本、用于向功能区主机应用程序公开标记元素的 ID 定义标头 (.h 文件) ,以及) 将功能区映像和字符串资源链接到主机应用程序 的资源定义脚本 (.rc 文件。

有关编译功能区框架标记的更多详细信息,请参阅 编译功能区标记

生成应用程序

在标记中设计和实现功能区应用程序的初步 UI 后,必须编写应用程序代码来初始化框架、使用标记,并将标记中声明的命令绑定到应用程序中的相应命令处理程序。

重要

由于功能区框架是基于 COM 的,因此建议功能区项目使用 __uuidof () 运算符来引用功能区框架接口的 GUID (IID) 。 如果无法使用 __uuidof () 运算符,例如使用非 Microsoft 编译器或主机应用程序基于 C,则 IID 必须由应用程序定义,因为它们不包含在 uuid.lib 中。

如果 IID 由应用程序定义,则必须使用 UIRibbon.idl 中指定的 GUID。

UIRibbon.idl 作为 Windows 软件开发工具包 (SDK) 的一部分提供,可以在 %ProgramFiles%\Microsoft SDKs\Windows\v7.0\Include 的标准安装路径中找到。

 

初始化功能区

下图演示了实现简单功能区应用程序所需的步骤。

显示实现简单功能区实现所需步骤的示意图。

以下步骤详细介绍了如何实现简单的功能区应用程序。

  1. CoCreateInstance

    应用程序使用功能区框架类 ID 调用标准 COM CoCreateInstance 函数,以获取指向框架的指针。

    IUIFramework* pFramework = NULL;
    HRESULT hr = ::CoCreateInstance(
                CLSID_UIRibbonFramework, 
                NULL,
                CLSCTX_INPROC_SERVER, 
                IID_PPV_ARGS(&pFramework));
    if (FAILED(hr))
    {
      return hr;
    }
    
  2. 初始化 (hwnd、IUIApplication*)

    应用程序调用 IUIFramework::Initialize,传入两个参数:顶级窗口的句柄(将包含功能区)和指向允许框架对应用程序进行回调的 IUIApplication 实现的指针。

    ![重要提示]
    功能区框架初始化为单线程单元 (STA) 。

     

    hr = pFramework->Initialize(hWndHost, pApplication);
    if (FAILED(hr))
    {
      return hr;
    }
    
  3. LoadUI (实例、resourceName)

    应用程序调用 IUIFramework::LoadUI 来绑定标记资源。 此函数的第一个参数是功能区应用程序实例的句柄。 第二个参数是之前编译的二进制标记资源的名称。 通过将二进制标记传递到功能区框架,应用程序会指示功能区结构应该是什么以及控件的排列方式。 它还为框架提供一个命令清单,用于公开 ((如粘贴、剪切、查找) ),框架在运行时进行与命令相关的回调时使用这些命令。

    hr = pFramework->LoadUI(GetModuleHandle(NULL), L"APPLICATION_RIBBON");
    if (FAILED(hr))
    {
      return hr;
    }
    
  4. IUIApplication::OnCreateUICommand 回调

    完成步骤 1 到 3 后,功能区框架知道在功能区中公开哪些命令。 但是,在功能区完全正常运行之前,框架仍然需要两项操作:一种用于告知应用程序何时执行命令的方法,以及一种在运行时获取命令资源或属性的方法。 例如,如果要在 UI 中显示组合框,则框架需要请求用于填充组合框的项。

    这两个功能部分通过 IUICommandHandler 接口进行处理。 具体而言,对于在二进制标记中声明的每个命令 (请参阅上面的步骤 3) ,框架调用 IUIApplication::OnCreateUICommandCommand, 以请求应用程序为该命令提供 IUICommandHandler 对象

    注意

    IUICommandHandler 接口允许命令处理程序绑定到一个或多个命令。

     

应用程序至少需要实现返回E_NOTIMPL的 IUIApplication 方法存根,如以下示例所示。

STDMETHOD(OnViewChanged)(UINT32 viewId,
                         UI_VIEWTYPE typeID,
                         IUnknown *view,
                         UI_VIEWVERB verb,
                         INT32 uReasonCode)
{ 
  return E_NOTIMPL; 
}

STDMETHOD(OnCreateUICommand)(UINT32 commandId,
                             UI_COMMANDTYPE typeID,
                             IUICommandHandler **commandHandler)
{ 
  return E_NOTIMPL; 
}

STDMETHOD(OnDestroyUICommand)(UINT32 commandId,
                              UI_COMMANDTYPE typeID,
                              IUICommandHandler *commandHandler) 
{ 
  return E_NOTIMPL; 
}

此时,标记资源文件必须通过包含对标记资源定义文件的引用 (包含对应用程序资源文件中标记头文件的引用) ,将标记资源文件链接到主机应用程序。 例如,名为 RibbonApp 的应用程序以及名为 ribbonUI.rc 的资源文件需要 RibbonApp.rc 文件中的以下行。

#include "ribbonUI.rc"

根据所使用的编译器和链接器,资源定义脚本可能还需要在编译功能区应用程序之前进行编译。 Microsoft Visual Studio 和 Windows SDK 附带 的资源编译器 (RC) 命令行工具可用于此任务。

编译应用程序

编译功能区应用程序后,可以运行它并测试 UI。 如果 UI 需要调整,并且核心应用程序代码中任何关联的命令处理程序没有更改,请修改标记源文件,使用UICC.exe重新编译标记,并链接新的标记资源文件。 重启应用程序时,将显示修改后的 UI。

这一切可以在不涉及核心应用程序代码的情况下实现,这比标准应用程序开发和分发有了显著改进。

运行时汇报和执行

功能区框架的运行时通信结构基于推送和拉取或双向调用方模型。

此模型允许框架在执行命令时通知应用程序,并允许框架和应用程序查询、更新属性值和功能区资源并使其失效。 此功能通过许多接口和方法提供。

框架通过 IUICommandHandler::UpdateProperty 回调方法从功能区应用程序拉取更新的属性信息。 命令 ID 和属性键(标识要更新的 Command 属性)将传递给 方法,该方法随后向框架返回或推送该属性键的值。

框架在执行命令时调用 IUICommandHandler::Execute ,标识命令 ID 和 (UI_EXECUTIONVERB) 发生的 执行类型。 这是应用程序指定命令的执行逻辑的位置。

下图演示了框架和应用程序之间命令执行的运行时通信。

显示功能区框架与主机应用程序之间的运行时通信示例的示意图。

注意

最初在应用程序中显示功能区不需要实现 IUICommandHandler::UpdatePropertyIUICommandHandler::Execute 函数。 但是,这些方法是必要的,以确保应用程序在用户执行命令时正常运行。

 

OLE 支持

功能区应用程序可以配置为 OLE 服务器,以支持就地 OLE 激活。

在 OLE 服务器应用程序中创建的对象在插入 (粘贴或放置) 到 OLE 客户端应用程序 (或容器) 时保持与服务器应用程序的关联。 在就地 OLE 激活中,双击客户端应用程序中的 对象会打开服务器应用程序的专用实例,并加载对象进行编辑。 服务器应用程序关闭后,对对象所做的所有更改都会反映在客户端应用程序中。

注意

功能区框架不支持就地 OLE 激活。 无法在基于功能区的 OLE 服务器中创建的对象从 OLE 客户端应用程序中进行编辑。 需要服务器应用程序的外部专用实例。

使用功能区标记声明命令和控件

功能区用户体验指南

功能区设计过程