服务器端 UI 自动化提供程序的实现

更新:2007 年 11 月

本节介绍如何为自定义控件实现服务器端 UI 自动化提供程序。

Windows Presentation Foundation (WPF) 元素和非 WPF 元素(如专为 Windows 窗体设计的元素)的实现有着根本的不同。WPF 元素通过从 AutomationPeer 派生的类提供对 UI 自动化的支持。而非 WPF 元素通过提供程序接口的实现来提供支持。

本主题包括下列各节。

  • 安全注意事项
  • Windows Presentation Foundation 元素的提供程序实现
  • 非 WPF 元素的提供程序实现
  • 相关主题

安全注意事项

在编写提供程序时,应当使其可用于部分信任的环境。由于 UIAutomationClient.dll 未配置为在部分信任的环境下运行,因此提供程序代码不应当引用该程序集。如果引用,那么该代码或许能在完全信任的环境中运行,但不能在部分信任的环境中运行。

尤其不要使用 UIAutomationClient.dll 中类的字段,如 AutomationElement 中的字段。而应当使用 UIAutomationTypes.dll 中类的等效字段,如 AutomationElementIdentifiers

Windows Presentation Foundation 元素的提供程序实现

有关本主题的更多信息,请参见 WPF 自定义控件的 UI 自动化

非 WPF 元素的提供程序实现

不属于 WPF 框架、但采用托管代码编写的自定义控件(多数情况下为 Windows 窗体控件)通过实现接口来提供对 UI 自动化的支持。每个元素必须至少实现下一部分的第一个表中列出的接口之一。此外,如果该元素支持一个或多个控件模式,则它必须为每个控件模式实现相应的接口。

UI 自动化提供程序项目必须引用以下程序集:

  • UIAutomationProviders.dll

  • UIAutomationTypes.dll

  • WindowsBase.dll

本节包含下列子节。

  • 提供程序接口
  • 非 WPF 提供程序的要求
  • 非 WPF 提供程序中的属性值
  • 非 WPF 提供程序中的事件
  • 非 WPF 提供程序导航
  • 重新设置非 WPF 提供程序的父级
  • 重新定位非 WPF 提供程序

提供程序接口

每个 UI 自动化提供程序必须实现下列接口之一。

接口

说明

IRawElementProviderSimple

提供窗口中承载的简单控件的功能,包括对控件模式和属性的支持。

IRawElementProviderFragment

继承自 IRawElementProviderSimple。为复杂控件中的元素添加功能,包括在片段中导航、设置焦点和返回元素的边框。

IRawElementProviderFragmentRoot

继承自 IRawElementProviderFragment。为复杂控件中的根元素添加功能,包括将子元素定位于指定坐标以及设置整个控件的焦点状态。

以下接口可提供附加功能,但并不需要实现。

接口

说明

IRawElementProviderAdviseEvents

使提供程序可跟踪事件的请求。

IRawElementProviderHwndOverride

可以在片段的 UI 自动化树中重新定位基于窗口的元素。

System.Windows.Automation.Provider 命名空间中的所有其他接口均用于支持控件模式。

非 WPF 提供程序的要求

控件必须实现以下主要功能,才能与 UI 自动化通信:

功能

实现

向 UI 自动化公开提供程序

在响应发送到控件窗口的 WM_GETOBJECT 消息时,返回实现 IRawElementProviderSimple(或派生接口)的对象。对于片段,此对象必须是片段根元素的提供程序。

提供属性值

实现 GetPropertyValue 以提供或重写值。

使客户端能与控件交互

实现支持控件模式的接口,如 IInvokeProvider。在 GetPatternProvider 的实现中返回这些模式提供程序。

引发事件

调用 AutomationInteropProvider 的一个静态方法来引发客户端可以侦听的事件。

在片段中进行导航和设置焦点

为片段中的每个元素实现 IRawElementProviderFragment。(对于不属于片段的元素则不必实现。)

对片段中的子元素设置焦点和定位

实现 IRawElementProviderFragmentRoot。(对于非片段根元素的元素则不必实现。)

非 WPF 提供程序中的属性值

自定义控件的 UI 自动化提供程序必须支持可供自动化系统和客户端应用程序使用的某些属性。对于窗口中承载的元素 (HWND),UI 自动化可以从默认的窗口提供程序中检索某些属性,但必须从自定义提供程序获取其他属性。

基于 HWND 的控件的提供程序通常不需要提供以下属性(由字段值标识):

说明:

窗口中承载的简单元素或片段根元素的 RuntimeIdProperty 是从窗口中获取的,但根元素下的片段元素(如列表框中的列表项)必须提供自己的标识符。有关更多信息,请参见 GetRuntimeId

应当为 Windows 窗体控件中承载的提供程序返回 IsKeyboardFocusableProperty。在这种情况下,默认的窗口提供程序可能无法检索正确的值。

NameProperty 通常由宿主提供程序提供。例如,如果自定义控件派生自 Control,那么该名称将派生自该控件的 Text 属性。

有关示例代码,请参见从 UI 自动化提供程序返回属性

非 WPF 提供程序中的事件

UI 自动化提供程序应当引发事件,以通知客户端应用程序 UI 的状态发生变化。以下方法用于引发事件。

方法

说明

RaiseAutomationEvent

引发各种事件,包括控件模式触发的事件。

RaiseAutomationPropertyChangedEvent

当 UI 自动化属性更改时引发事件。

RaiseStructureChangedEvent

当 UI 自动化树的结构更改时引发事件,例如,移除或添加元素时。

事件的目的是通知客户端用户界面 (UI) 中发生了某些变化,而无论活动是否由 UI 自动化系统自身触发。例如,只要调用控件(无论是通过用户直接输入还是通过客户端应用程序调用 Invoke),就应当引发由 InvokedEvent 标识的事件。

若要优化性能,提供程序可以有选择地引发事件,或者根本不引发事件(如果没有注册客户端应用程序以接收事件)。以下方法用于优化。

方法

说明

ClientsAreListening

此静态属性指定是否有任何客户端应用程序已订阅 UI 自动化事件。

IRawElementProviderAdviseEvents

当客户端对片段注册或取消注册事件的事件处理程序时,片段根元素上此接口的提供程序使其可以收到通知。

非 WPF 提供程序导航

简单控件(如窗口中承载的自定义按钮 (HWND))的提供程序不需要支持 UI 自动化树中的导航。从该元素以及到该元素的导航由宿主窗口的默认提供程序处理,这一点在 HostRawElementProvider 的实现中指定。但是,在实现复杂自定义控件的提供程序时,必须支持片段的根节点与其子代,以及同级节点之间的导航。

说明:

除根元素以外的片段元素必须从 HostRawElementProvider 返回 null 引用,因为这些元素并不直接承载于窗口中,没有默认的提供程序能支持从它们以及到它们的导航。

片段的结构由 Navigate 的实现确定。对于每个片段的每个可能方向,此方法都会为该方向上的元素返回提供程序对象。如果在该方向上没有元素,则此方法返回 null 引用。

片段根元素仅支持到子元素的导航。例如,如果方向为 FirstChild,则列表框返回列表中的第一项;如果方向为 LastChild,则返回列表中的最后一项。片段根元素不支持到父级或同级的导航,这由宿主窗口提供程序处理。

根元素以外的片段元素必须支持父级、所有同级及子级的导航。

重新设置非 WPF 提供程序的父级

弹出窗口实际上是顶级窗口,因此,默认情况下在 UI 自动化树中显示为桌面的子级。但是,在大多数情况下,弹出窗口逻辑上是其他某些控件的子级。例如,组合框的下拉列表逻辑上是组合框的子级。同样,菜单弹出窗口逻辑上是菜单的子级。UI 自动化支持重新设置弹出窗口的父级,以使其显示为相关控件的子级。

若要重新设置弹出窗口的父级,请执行以下操作:

  1. 为弹出窗口创建提供程序。这要求预先知道弹出窗口的类。

  2. 照常实现该弹出窗口的所有属性和模式,就好像它本身是一个控件一样。

  3. 实现 HostRawElementProvider 属性,使其返回从 HostProviderFromHandle 获取的值,其中参数是弹出窗口的窗口句柄。

  4. 实现弹出窗口及其父级的 Navigate,以便可以正确处理从逻辑父级到逻辑子级,以及同级子级之间的导航。

当 UI 自动化遇到弹出窗口时,可识别该重写了默认值的导航,并会在遇到作为桌面子级的弹出窗口时,跳过此弹出窗口。此节点只能通过片段到达。

当控件能承载任何类的窗口时,不适合重新设置父级。例如,rebar 能在其带区内承载任何类型的 HWND。为处理这种情况,UI 自动化支持备用形式的 HWND 重定位,如下一部分所述。

重新定位非 WPF 提供程序

UI 自动化片段可以包含两个或更多个包含在窗口中的元素 (HWND)。因为每个 HWND 都有自己的默认提供程序(将 HWND 视为包含 HWND 的子级),所以默认情况下 UI 自动化树将片段中的 HWND 显示为父窗口的子级。在大多数情况下,此行为都很恰当,但有时会导致混乱,因为它与 UI 的逻辑结构不匹配。

rebar 控件就是一个很好的示例。rebar 控件包含带区,每个带区又可以包含基于 HWND 的控件,如工具栏、编辑框或组合框。rebar HWND 的默认窗口提供程序将带区控件 HWND 视为子级,rebar 提供程序将带区视为子级。因为 HWND 提供程序和 rebar 提供程序先后运行,并组成其子级,所以带区和基于 HWND 的控件都显示为 rebar 的子级。但是,逻辑上只有带区应当显示为 rebar 的子级,并且每个带区提供程序应与它所包含控件的默认 HWND 提供程序结合使用。

为此,rebar 的片段根元素提供程序公开一组表示带区的子级。每个带区都有一个可以公开属性和模式的提供程序。在其 HostRawElementProvider 实现中,带区提供程序通过调用 HostProviderFromHandle 并在控件的窗口句柄中传递,来获取并返回控件 HWND 的默认窗口提供程序。最后,rebar 的片段根元素提供程序实现 IRawElementProviderHwndOverride 接口,并在其 GetOverrideProviderForHwnd 实现中,返回指定的 HWND 中所包含控件的相应带区提供程序。

请参见

任务

公开服务器端 UI 自动化提供程序

从 UI 自动化提供程序返回属性

从 UI 自动化提供程序中引发事件

在 UI 自动化片段提供程序中启用导航

在 UI 自动化提供程序中支持控件模式

简单提供程序的示例

片段提供程序示例

概念

UI 自动化提供程序概述