自定义的自动化对等
介绍Microsoft UI 自动化自动化对等互连的概念,以及如何为自己的自定义 UI 类提供自动化支持。
UI 自动化提供了自动化客户端可用于检查或操作各种 UI 平台和框架的用户界面的框架。 如果要编写 Windows 应用,则你用于 UI 的类已经提供了 UI 自动化支持。 可以从现有的非密封类派生,以定义一种新的 UI 控件或支持类。 在执行此操作的过程中,你的类可能会添加应具有辅助功能支持的行为,但默认UI 自动化支持未涵盖。 在这种情况下,你应当通过以下方法扩展现有的 UI 自动化支持:从基实现使用的 AutomationPeer 类进行派生,为你的对等实现添加任何必需的支持,并通知 Windows 应用控件基础结构应当创建新的对等。
UI 自动化不仅支持辅助功能应用程序和辅助技术,如屏幕阅读器,而且还支持质量保证(测试)代码。 在任一方案中,UI 自动化客户端都可以检查用户界面元素,并从应用外部的其他代码模拟用户交互。 有关跨所有平台及其更广泛的含义UI 自动化的信息,请参阅UI 自动化概述。
有两个不同的受众使用UI 自动化框架。
- UI 自动化客户端调用UI 自动化 API,了解当前向用户显示的所有 UI。 例如,屏幕阅读器等辅助技术充当UI 自动化客户端。 UI 显示为相关的自动化元素树。 UI 自动化客户端可能一次只对一个应用或整个树感兴趣。 UI 自动化客户端可以使用UI 自动化 API 来导航树并读取或更改自动化元素中的信息。
- UI 自动化提供程序通过实现公开作为应用一部分引入的 UI 中的元素的 API,为UI 自动化树提供信息。 创建新控件时,现在应充当UI 自动化提供程序方案中的参与者。 作为提供程序,应确保所有UI 自动化客户端都可以使用UI 自动化框架与控件进行交互,以实现辅助功能和测试目的。
通常UI 自动化框架中有并行 API:一个用于UI 自动化客户端的 API,另一个 API 与UI 自动化提供程序的类似命名 API。 在大多数情况下,本主题介绍UI 自动化提供程序的 API,特别是支持该 UI 框架中提供程序扩展性的类和接口。 我们偶尔会提到 UI 自动化UI 自动化客户端使用的 API,提供一些透视,或者提供与客户端和提供程序 API 关联的查阅表。 有关客户端视角的详细信息,请参阅UI 自动化客户端程序员指南。
注意
UI 自动化客户端通常不使用托管代码,通常不作为 UWP 应用实现(它们通常是桌面应用)。 UI 自动化基于标准,而不是特定实现或框架。 许多现有的UI 自动化客户端,包括屏幕阅读器等辅助技术产品,使用组件对象模型(COM)接口与子窗口中运行的UI 自动化、系统和应用进行交互。 有关 COM 接口以及如何使用 COM 编写UI 自动化客户端的详细信息,请参阅UI 自动化基础知识。
确定自定义 UI 类UI 自动化支持的现有状态
在尝试为自定义控件实现自动化对等之前,应测试基类及其自动化对等是否已提供所需的辅助功能或自动化支持。 在许多情况下,FrameworkElementAutomationPeer 实现、特定对等和它们实现的模式的组合可以提供基本但令人满意的辅助功能体验。 这是否属实取决于你对对象模型暴露在控件与基类中的更改数。 此外,这取决于对基类功能的添加与模板协定中的新 UI 元素或控件的视觉外观相关联。 在某些情况下,更改可能会引入用户体验的新方面,这些方面需要额外的辅助功能支持。
即使使用现有的基对等类提供了基本的辅助功能支持,它仍然是定义对等的最佳做法,以便你可以将精确的 ClassName 信息报告为自动测试方案UI 自动化。 如果要编写用于第三方使用的控件,则此注意事项尤其重要。
自动化对等类
UWP 基于以前的托管代码 UI 框架(如 Windows 窗体、Windows Presentation Foundation(WPF)和 Microsoft Silverlight 等现有UI 自动化技术和约定构建。 许多控件类及其函数和用途也源自以前的 UI 框架。
按照约定,对等类名以控件类名开头,以“AutomationPeer”结尾。 例如,ButtonAutomationPeer 是 Button 控件类的对等类。
注意
出于本主题的目的,我们将与辅助功能相关的属性视为在实现控件对等时更重要。 但是,对于更一般的概念UI 自动化支持,应按照UI 自动化提供商程序员指南和UI 自动化基础知识中所述的建议实施对等方。 这些主题未涵盖用于在 UWP 框架中提供UI 自动化信息的特定 AutomationPeer API,但它们确实描述了标识类或提供其他信息或交互的属性。
对等方、模式和控件类型
控件模式是一个接口实现,它向UI 自动化客户端公开控件功能的特定方面。 UI 自动化客户端使用通过控件模式公开的属性和方法来检索有关控件功能的信息,或在运行时操作控件的行为。
控件模式提供了一种方法,用于独立于控件类型或控件的外观对控件的功能进行分类和公开。 例如,呈现表格界面的控件使用网格控件模式公开表中的行数和列数,并允许UI 自动化客户端从表中检索项。 与其他示例一样,UI 自动化客户端可以使用可调用的控件的“调用”控件模式,例如按钮,以及具有滚动条的控件的滚动控件模式,例如列表框、列表视图或组合框。 每个控件模式表示单独的功能类型,控件模式可以组合起来来描述特定控件支持的完整功能集。
控件模式与 UI 相关,因为接口与 COM 对象相关。 在 COM 中,你可以查询对象以询问它支持什么接口,然后使用这些接口访问功能。 在UI 自动化中,UI 自动化客户端可以查询UI 自动化元素,找出它支持的控件模式,然后通过受支持控件模式公开的属性、方法、事件和结构与元素及其对等控件进行交互。
自动化对等的主要用途之一是向UI 自动化客户端报告 UI 元素可以通过其对等支持的控件模式。 为此,UI 自动化提供程序实现新的对等互连,这些对等方通过重写 GetPatternCore 方法来更改 GetPattern 方法行为。 UI 自动化客户端进行调用,UI 自动化提供程序映射到调用 GetPattern。 UI 自动化客户端查询要与之交互的每个特定模式。 如果对等方支持该模式,它将返回对自身的对象引用;否则返回 null。 如果返回结果不为 null,则UI 自动化客户端期望它可以将模式接口的 API 调用为客户端,以便与该控件模式进行交互。
控件 类型 是一种广泛定义对等表示的控件的功能的方法。 这与控件模式的概念不同,因为当模式通知UI 自动化它可以获取哪些信息或通过特定接口执行的操作时,控件类型存在高于该级别的级别。 每个控件类型都有有关UI 自动化以下方面的指导:
- UI 自动化控件模式:控件类型可能支持多个模式,每个模式表示不同的信息或交互分类。 每个控件类型都有一组控件模式,控件必须支持的一组控件模式、一个可选集,以及控件不能支持的集。
- UI 自动化属性值:每个控件类型都有一组控件必须支持的属性。 这些是常规属性,如UI 自动化属性概述中所述,而不是特定于模式的属性。
- UI 自动化事件:每个控件类型都有一组控件必须支持的事件。 同样,这些是常规的,而不是特定于模式的,如UI 自动化事件概述中所述。
- UI 自动化树结构:每个控件类型定义控件在UI 自动化树结构中的显示方式。
无论如何实现框架的自动化对等,UI 自动化客户端功能都不会绑定到 UWP,事实上,现有的UI 自动化客户端(如辅助技术)可能会使用其他编程模型(如 COM)。 在 COM 中,客户端可以为 COM 控件模式接口查询Interface,该接口可实现请求的模式或属性、事件或树检查的常规UI 自动化框架。 对于模式,UI 自动化框架将接口代码封送到针对应用UI 自动化提供程序和相关对等方运行的 UWP 代码中。
当你为托管代码框架(例如使用 C# 或 Microsoft Visual Basic 的 UWP 应用)实现控件模式时,你可以使用 .NET Framework 接口来表示这些模式,而不是使用 COM 接口表示。 例如,调用模式的 Microsoft .NET 提供程序实现的UI 自动化模式接口为 IInvokeProvider。
有关控件模式、提供程序接口及其用途的列表,请参阅 控件模式和接口。 有关控件类型的列表,请参阅UI 自动化控件类型概述。
有关如何实现控件模式的指导
控件模式及其用途是UI 自动化框架的较大定义的一部分,并且不仅适用于 UWP 应用的辅助功能支持。 实现控件模式时,应确保采用与这些文档中记录的指南匹配并位于 UI 自动化规范中的方式来实现它。 如果你正在查找指南,通常可以使用 Microsoft 文档,无需参考该规范。 此处介绍了每种模式的指南:实现UI 自动化控件模式。 你会注意到,本区域下的每个主题都有一个“实施准则和约定”部分和“必需成员”部分。 本指南通常指提供程序引用的控件模式接口中相关控件模式接口的特定 API。 这些接口是本机/COM 接口(及其 API 使用 COM 样式语法)。 但是你看到的所有内容在 Windows.UI.Xaml.Automation.Provider 命名空间中都有等效项。
如果使用默认自动化对等并扩展其行为,则这些对等已编写符合UI 自动化准则。 如果它们支持控件模式,则可以依赖于该模式支持,以符合实现UI 自动化控件模式的指导。 如果控件对等方报告它代表由UI 自动化定义的控件类型,则支持UI 自动化控件类型的指南后跟该对等方。
不过,可能需要针对控件模式或控件类型提供其他指导,以便遵循对等实现中的UI 自动化建议。 如果要实现 UWP 控件中尚不存在为默认实现的模式或控件类型支持,则情况尤其如此。 例如,注释模式未在任何默认 XAML 控件中实现。 但你可能有一个应用,该应用广泛使用批注,因此你想要显示可访问的功能。 对于此方案,对等应实现 IAnnotationProvider,并且可能以具有适当属性的文档控件类型报告自身,以指示文档支持批注。
建议使用在“支持UI 自动化控件类型”下针对“实现UI 自动化控件模式”或“控件类型”下的模式看到的指南作为方向和常规指南。 甚至可能尝试遵循一些 API 链接,了解 API 用途的说明和备注。 但是,对于 UWP 应用编程所需的语法细节,可在 Windows.UI.Xaml.Automation.Provider 命名空间中找到等效的 API,并使用这些参考页了解详细信息。
内置自动化对等类
通常,如果元素接受来自用户的 UI 活动,或者元素包含表示应用的交互式或有意义的 UI 的用户所需的信息,则实现自动化对等类。 并非所有 UWP 视觉元素都具有自动化对等互连。 实现自动化对等的类的示例包括 Button 和 TextBox。 不实现自动化对等的类的示例包括 Border 和基于 Panel 的类,例如 Grid 和 Canvas。 面板没有对等方,因为它提供仅视觉对象的布局行为。 用户与面板交互没有与辅助功能相关的方法。 面板包含的任何子元素都报告给UI 自动化树作为具有对等或元素表示形式的树中下一个可用父元素的子元素。
UI 自动化和 UWP 进程边界
通常,UI 自动化访问 UWP 应用的客户端代码已过期。 UI 自动化框架基础结构使信息能够跨越进程边界。 UI 自动化基础知识中更详细地介绍了此概念。
OnCreateAutomationPeer
从 UIElement 派生的所有类都包含受保护的虚拟方法 OnCreateAutomationPeer。 自动化对等方的对象初始化序列调用 OnCreateAutomationPeer 以获取每个控件的自动化对等对象,从而构造用于运行时使用的UI 自动化树。 UI 自动化代码可以使用对等方获取有关控件的特征和特征的信息,并通过控件模式模拟交互式使用。 支持自动化的自定义控件必须重写 OnCreateAutomationPeer,并返回派生自 AutomationPeer 的类的实例。 例如,如果自定义控件派生自 ButtonBase 类,OnCreateAutomationPeer 返回的对象应派生自 ButtonBaseAutomationPeer。
如果要编写自定义控件类并打算提供新的自动化对等,则应替代 自定义控件的 OnCreateAutomationPeer 方法,以便它返回对等的新实例。 对等类必须直接或间接地从 AutomationPeer 派生。
例如,以下代码声明自定义控件NumericUpDown
应将对等方NumericUpDownPeer
用于UI 自动化目的。
using Windows.UI.Xaml.Automation.Peers;
...
public class NumericUpDown : RangeBase {
public NumericUpDown() {
// other initialization; DefaultStyleKey etc.
}
...
protected override AutomationPeer OnCreateAutomationPeer()
{
return new NumericUpDownAutomationPeer(this);
}
}
Public Class NumericUpDown
Inherits RangeBase
' other initialization; DefaultStyleKey etc.
Public Sub New()
End Sub
Protected Overrides Function OnCreateAutomationPeer() As AutomationPeer
Return New NumericUpDownAutomationPeer(Me)
End Function
End Class
// NumericUpDown.idl
namespace MyNamespace
{
runtimeclass NumericUpDown : Windows.UI.Xaml.Controls.Primitives.RangeBase
{
NumericUpDown();
Int32 MyProperty;
}
}
// NumericUpDown.h
...
struct NumericUpDown : NumericUpDownT<NumericUpDown>
{
...
Windows::UI::Xaml::Automation::Peers::AutomationPeer OnCreateAutomationPeer()
{
return winrt::make<MyNamespace::implementation::NumericUpDownAutomationPeer>(*this);
}
};
//.h
public ref class NumericUpDown sealed : Windows::UI::Xaml::Controls::Primitives::RangeBase
{
// other initialization not shown
protected:
virtual AutomationPeer^ OnCreateAutomationPeer() override
{
return ref new NumericUpDownAutomationPeer(this);
}
};
注意
OnCreateAutomationPeer 实现应只执行任何操作,而不是初始化自定义自动化对等方的新实例,将调用控件作为所有者传递,并返回该实例。 请勿尝试此方法中的其他逻辑。 具体而言,任何可能导致在同一调用中销毁 AutomationPeer 的逻辑都可能导致意外的运行时行为。
在 OnCreateAutomationPeer 的典型实现中,所有者被指定为此或 Me,因为方法重写与控件类定义的其余部分位于同一范围内。
实际的对等类定义可以在与控件相同的代码文件中或单独的代码文件中完成。 对等定义全部存在于 Windows.UI.Xaml.Automation.Peers 命名空间中,该命名空间是独立于它们为对等方提供的控件的命名空间。 也可以选择在单独的命名空间中声明对等,前提是引用 OnCreateAutomationPeer 方法调用所需的命名空间。
选择正确的对等基类
确保 AutomationPeer 派生自一个基类,该基类为你提供了与派生自的控件类的现有对等逻辑的最佳匹配。 在前面的示例中,由于NumericUpDown
派生自 RangeBase,因此有一个 RangeBaseAutomationPeer 类可供你基于你的对等方。 通过将最匹配的对等类与派生控件本身的方式并行使用,可以避免至少重写某些 IRangeValueProvider 功能,因为基对等类已经实现它。
基 Control 类没有相应的对等类。 如果需要一个对等类来对应于派生自 Control 的自定义控件,请从 FrameworkElementAutomationPeer 派生自定义对等类。
如果直接派生自 ContentControl,该类没有默认的自动化对等行为,因为没有引用对等类的 OnCreateAutomationPeer 实现。 因此,请确保实现 OnCreateAutomationPeer 以使用自己的对等,或者如果辅助功能支持级别足以用于控件,则使用 FrameworkElementAutomationPeer 作为对等方。
注意
通常不会派生自 AutomationPeer,而不是 FrameworkElementAutomationPeer。 如果确实直接从 AutomationPeer 派生,则需要复制大量基本辅助功能支持,否则这些支持来自 FrameworkElementAutomationPeer。
自定义对等类的初始化
自动化对等应定义一个类型安全的构造函数,该构造函数使用所有者控件的实例进行基本初始化。 在下一个示例中,实现将所有者值传递到 RangeBaseAutomationPeer 基础,最终是实际使用所有者设置 FrameworkElementAutomationPeer.Owner 的 FrameworkElementAutomationPeer。
public NumericUpDownAutomationPeer(NumericUpDown owner): base(owner)
{}
Public Sub New(owner As NumericUpDown)
MyBase.New(owner)
End Sub
// NumericUpDownAutomationPeer.idl
import "NumericUpDown.idl";
namespace MyNamespace
{
runtimeclass NumericUpDownAutomationPeer : Windows.UI.Xaml.Automation.Peers.AutomationPeer
{
NumericUpDownAutomationPeer(NumericUpDown owner);
Int32 MyProperty;
}
}
// NumericUpDownAutomationPeer.h
...
struct NumericUpDownAutomationPeer : NumericUpDownAutomationPeerT<NumericUpDownAutomationPeer>
{
...
NumericUpDownAutomationPeer(MyNamespace::NumericUpDown const& owner);
};
//.h
public ref class NumericUpDownAutomationPeer sealed : Windows::UI::Xaml::Automation::Peers::RangeBaseAutomationPeer
//.cpp
public: NumericUpDownAutomationPeer(NumericUpDown^ owner);
AutomationPeer 的核心方法
出于 UWP 基础结构的原因,自动化对等的可重写方法是一对方法的一部分:UI 自动化提供程序用作UI 自动化客户端的转发点的公共访问方法,以及 UWP 类可以替代的受保护“核心”自定义方法以影响行为。 方法对默认连接在一起,这样一来,对访问方法的调用始终调用具有提供程序实现的并行“Core”方法,或者作为回退调用基类的默认实现。
为自定义控件实现对等时,请重写基本自动化对等类中的任何“Core”方法,在该类中要公开自定义控件唯一的行为。 UI 自动化代码通过调用对等类的公共方法获取有关控件的信息。 若要提供有关控件的信息,请在控件实现和设计创建辅助功能方案或其他与基本自动化对等类支持的方案不同的其他UI 自动化方案时,使用以“Core”结尾的名称替代每个方法。
至少,每当定义新的对等类时,都实现 GetClassNameCore 方法,如下一示例所示。
protected override string GetClassNameCore()
{
return "NumericUpDown";
}
注意
你可能希望将字符串存储为常量,而不是直接存储在方法正文中,但由你决定。 对于 GetClassNameCore,无需本地化此字符串。 每当UI 自动化客户端(而不是 ClassName)需要本地化字符串时,都使用 LocalizedControlType 属性。
GetAutomationControlType
某些辅助技术在报告UI 自动化树中项的特征时直接使用 GetAutomationControlType 值,作为UI 自动化名称之外的其他信息。 如果控件与从中派生的控件大相径庭,并且想要报告控件使用的基对等类所报告的内容不同的控件类型,则必须在对等实现中实现对等并重写 GetAutomationControlTypeCore。 如果派生自 ItemsControl 或 ContentControl 等通用基类,其中基对等方不提供有关控件类型的精确信息,则这一点尤其重要。
GetAutomationControlTypeCore 的实现通过返回 AutomationControlType 值来描述控件。 虽然可以返回 AutomationControlType.Custom,但如果它准确地描述了控件的主要方案,则应返回一种更具体的控件类型。 下面是一个示例。
protected override AutomationControlType GetAutomationControlTypeCore()
{
return AutomationControlType.Spinner;
}
注意
除非指定 AutomationControlType.Custom,否则无需实现 GetLocalizedControlTypeCore 即可向客户端提供 LocalizedControlType 属性值。 UI 自动化通用基础结构为每个可能的字符串提供翻译后的字符串AutomationControlType 值,而不是 AutomationControlType.Custom。
GetPattern 和 GetPatternCore
对等方 GetPatternCore 的实现返回支持输入参数中请求的模式的对象。 具体而言,UI 自动化客户端调用将转发到提供程序的 GetPattern 方法的方法,并指定命名所请求模式的 PatternInterface 枚举值。 GetPatternCore 的重写应返回实现指定模式的对象。 该对象是对等体本身,因为每当该对等方报告它支持模式时,该对象都应实现相应的模式接口。 如果对等方没有模式的自定义实现,但你知道对等的基础确实实现了模式,则可以从 GetPatternCore 调用基类型的 GetPatternCore 实现。 如果对等方不支持模式,则对等的 GetPatternCore 应返回 null 。 但是,通常依赖于对基本实现的调用,而不是直接从实现返回 null ,以返回 任何不受支持的模式的 null 。
当模式受支持时,GetPatternCore 实现可以返回此模式或 Me。 预期是,每当 GetPattern 返回值不为 null 时,UI 自动化客户端都会将 GetPattern 返回值强制转换为请求的模式接口。
如果对等类继承自另一对等,并且基类已处理所有必要的支持和模式报告,则不需要实现 GetPatternCore。 例如,如果要实现派生自 RangeBase 的范围控件,并且对等派生自 RangeBaseAutomationPeer,则对等方返回 PatternInterface.RangeValue 本身,并且具有支持该模式的 IRangeValueProvider 接口的工作实现。
虽然它不是文本代码,但此示例近似于 RangeBaseAutomationPeer 中已存在的 GetPatternCore 的实现。
protected override object GetPatternCore(PatternInterface patternInterface)
{
if (patternInterface == PatternInterface.RangeValue)
{
return this;
}
return base.GetPatternCore(patternInterface);
}
如果要实现一个对等方,而你没有基对等类所需的所有支持,或者想要更改或添加到对等可支持的基继承模式集,则应重写 GetPatternCore,使UI 自动化客户端能够使用模式。
有关UI 自动化支持的 UWP 实现中提供的提供程序模式的列表,请参阅 Windows.UI.Xaml.Automation.Provider。 每个此类模式都有一个相应的 PatternInterface 枚举值,即UI 自动化客户端在 GetPattern 调用中请求模式的方式。
对等方可以报告它支持多个模式。 如果是这样,重写应包括每个支持的 PatternInterface 值的返回路径逻辑,并在每个匹配的情况下返回对等。 预计调用方一次只请求一个接口,由调用方强制转换为预期接口。
下面是自定义对等方 GetPatternCore 重写的示例。 它报告对两种模式的支持:IRangeValueProvider 和 IToggleProvider。 此处的控件是一个媒体显示控件,可以显示为全屏(切换模式),并且具有一个进度栏,用户可以在其中选择位置(范围控件)。 此代码来自 XAML 辅助功能示例。
protected override object GetPatternCore(PatternInterface patternInterface)
{
if (patternInterface == PatternInterface.RangeValue)
{
return this;
}
else if (patternInterface == PatternInterface.Toggle)
{
return this;
}
return null;
}
从子元素转发模式
GetPatternCore 方法实现还可以将子元素或部件指定为其主机的模式提供程序。 此示例模拟 ItemsControl 如何将滚动模式处理传输到其内部 ScrollViewer 控件的对等方。 若要为模式处理指定子元素,此代码获取子元素对象,使用 FrameworkElementAutomationPeer.CreatePeer.CreatePeerForElement 方法为子元素创建对等,并返回新的对等。
protected override object GetPatternCore(PatternInterface patternInterface)
{
if (patternInterface == PatternInterface.Scroll)
{
ItemsControl owner = (ItemsControl) base.Owner;
UIElement itemsHost = owner.ItemsHost;
ScrollViewer element = null;
while (itemsHost != owner)
{
itemsHost = VisualTreeHelper.GetParent(itemsHost) as UIElement;
element = itemsHost as ScrollViewer;
if (element != null)
{
break;
}
}
if (element != null)
{
AutomationPeer peer = FrameworkElementAutomationPeer.CreatePeerForElement(element);
if ((peer != null) && (peer is IScrollProvider))
{
return (IScrollProvider) peer;
}
}
}
return base.GetPatternCore(patternInterface);
}
其他核心方法
你的控件可能需要支持主要方案的键盘等效项;有关为何可能需要此操作的详细信息,请参阅 键盘辅助功能。 实现密钥支持必然是控件代码的一部分,而不是对等代码,因为这是控件逻辑的一部分,但对等类应重写 GetAcceleratorKeyCore 和 GetAccessKeyCore 方法,以向UI 自动化使用密钥的客户端报告。 请考虑报告关键信息的字符串可能需要本地化,因此应该来自资源,而不是硬编码字符串。
如果要为支持集合的类提供对等,最好是从具有该集合支持的函数类和对等类派生。 如果无法执行此操作,维护子集合的控件的对等方可能必须重写与集合相关的对等方法 GetChildrenCore,以便将父子关系正确报告给UI 自动化树。
实现 IsContentElementCore 和 IsControlElementCore 方法,以指示控件是包含数据内容还是满足用户界面(或两者)中的交互角色。 默认情况下,这两种方法返回 true。 这些设置提高了辅助技术(如屏幕阅读器)的可用性,这些技术可以使用这些方法来筛选自动化树。 如果 GetPatternCore 方法将模式处理转移到子元素对等方,则子元素对等的 IsControlElementCore 方法可能会返回 false,以隐藏自动化树中的子元素对等。
某些控件可能支持标记方案,其中文本标签部件提供非文本部件的信息,或控件旨在与 UI 中的另一个控件处于已知的标记关系中。 如果可以提供有用的基于类的行为,则可以重写 GetLabeledByCore 以提供此行为。
GetBoundingRectangleCore 和 GetClickablePointCore 主要用于自动测试方案。 如果要支持控件的自动测试,可能需要重写这些方法。 对于范围类型控件,可能不需要这样做,因为用户单击坐标空间对某个范围有不同的影响,因此不能仅建议单个点。 例如,默认 ScrollBar 自动化对等会重写 GetClickablePointCore 以返回“非数字”点值。
GetLiveSettingCore 影响 UI 自动化 LiveSetting 值的控件默认值。 如果希望控件返回 AutomationLiveSetting.Off 以外的值,可能需要重写此值。 有关 LiveSetting 所表示的内容的详细信息,请参阅 AutomationProperties.LiveSetting。
如果控件具有可映射到 AutomationOrientation 的可设置方向属性,则可以替代 GetOrientationCore。 ScrollBarAutomationPeer 和 SliderAutomationPeer 类执行此操作。
FrameworkElementAutomationPeer 中的基本实现
FrameworkElementAutomationPeer 的基本实现提供了一些UI 自动化信息,这些信息可以从框架级别定义的各种布局和行为属性进行解释。
- GetBoundingRectangleCore:基于已知布局特征返回 Rect 结构。 如果 IsOffscreen 为 true,则返回 0 值 Rect。
- GetClickablePointCore:返回基于已知布局特征的点结构,前提是存在非零 BoundingRectangle。
- GetNameCore:比此处汇总的更广泛的行为;请参阅 GetNameCore。 基本上,它会尝试对 ContentControl 或具有内容的相关类的任何已知内容进行字符串转换。 此外,如果 LabeledBy 有一个值,则该项的 Name 值将用作 Name。
- HasKeyboardFocusCore:根据所有者的 FocusState 和 IsEnabled 属性进行评估。 不是控件的元素始终返回 false。
- IsEnabledCore:如果它是控件,则根据所有者的 IsEnabled 属性进行评估。 不是控件的元素始终返回 true。 这并不意味着所有者在传统交互意义上已启用;这意味着,尽管所有者没有 IsEnabled 属性,但启用对等方。
- IsKeyboardFocusableCore:如果所有者是控件,则返回 true;否则返回 false。
- IsOffscreenCore:所有者元素或其任何父元素上折叠的可见性等同于 IsOffscreen 的真实值。 异常: 即使其所有者的父对象不是,Popup 对象也可见。
- SetFocusCore:调用 焦点。
- GetParent:从所有者调用 FrameworkElement.Parent ,并查找相应的对等方。 这不是与“Core”方法的替代对,因此无法更改此行为。
注意
默认 UWP 对等方通过使用实现 UWP 的内部本机代码来实现行为,不一定使用实际的 UWP 代码。 你将无法通过公共语言运行时(CLR)反射或其他技术查看实现的代码或逻辑。 你也不会看到特定于子类的基对等行为的替代的不同引用页。 例如,TextBoxAutomationPeer 的 GetNameCore 可能有其他行为,这不会在 AutomationPeer.GetNameCore 参考页上描述,并且没有 TextBoxAutomationPeer.GetNameCore 的参考页。 甚至 没有 TextBoxAutomationPeer.GetNameCore 参考页。 相反,请阅读最直接对等类的参考主题,并在“备注”部分查找实现说明。
Peers 和 AutomationProperties
自动化对等方应为控件的辅助功能相关信息提供适当的默认值。 请注意,使用控件的任何应用代码都可以通过在控件实例上包括 AutomationProperties 附加属性值来替代某些行为。 调用方可以为默认控件或自定义控件执行此操作。 例如,下面的 XAML 创建一个按钮,该按钮具有两个自定义的 UI 自动化属性:<Button AutomationProperties.Name="Special" AutomationProperties.HelpText="This is a special button."/>
有关 AutomationProperties 附加属性的详细信息,请参阅基本辅助功能信息。
由于UI 自动化提供程序应如何报告信息的一般协定,因此存在一些 AutomationPeer 方法,但这些方法通常不会在控制对等方中实现。 这是因为该信息应由 AutomationProperties 值提供,这些值应用于使用特定 UI 中的控件的应用代码。 例如,大多数应用将通过应用 AutomationProperties.LabeledBy 值来定义 UI 中两个不同的控件之间的标记关系。 但是,LabeledByCore 在某些对等方中实现,这些对等方表示控件中的数据或项关系,例如使用标头部件标记数据字段部件、使用其容器标记项或类似方案。
实现模式
让我们看看如何通过实现展开折叠的控件模式接口来为实现展开折叠行为的控件编写对等。 每当使用 PatternInterface.ExpandCollapse 值调用 GetPattern 时,对等方都应通过返回自身来启用扩展折叠行为的可访问性。 然后,对等方应继承该模式的提供程序接口(IExpandCollapseProvider),并为该提供程序接口的每个成员提供实现。 在这种情况下,接口有三个要重写的成员:Expand、Collapse、ExpandCollapseState。
在类本身的 API 设计中提前规划辅助功能会很有帮助。 只要你的行为可能是由于与在 UI 中工作的用户或通过自动化提供程序模式进行的典型交互而请求的行为,请提供 UI 响应或自动化模式可以调用的单个方法。 例如,如果控件具有可展开或折叠控件的有线事件处理程序的按钮部件,并且具有这些操作的键盘等效项,则让这些事件处理程序调用从对等方中 IExpandCollapseProvider 的展开或折叠实现正文中调用的相同方法。 使用通用逻辑方法也可以是一种有用的方法,以确保控件的视觉状态更新为以统一的方式显示逻辑状态,而不考虑调用行为的方式。
典型的实现是提供程序 API 首先调用 所有者 ,以便在运行时访问控制实例。 然后,可以在该对象上调用必要的行为方法。
public class IndexCardAutomationPeer : FrameworkElementAutomationPeer, IExpandCollapseProvider {
private IndexCard ownerIndexCard;
public IndexCardAutomationPeer(IndexCard owner) : base(owner)
{
ownerIndexCard = owner;
}
}
备用实现是控件本身可以引用其对等。 如果从控件引发自动化事件,这是一种常见模式,因为 RaiseAutomationEvent 方法是对等方法。
UI 自动化事件
UI 自动化事件属于以下类别。
事件 | 说明 |
---|---|
属性更改 | 当UI 自动化元素或控件模式上的属性发生更改时触发。 例如,如果客户端需要监视应用的复选框控件,则可以注册以侦听 ToggleState 属性上的属性更改事件。 选中或取消选中复选框控件时,提供程序会触发事件,客户端可以根据需要进行操作。 |
元素操作 | 当用户或编程活动在 UI 中的更改结果时触发;例如,通过调用模式单击或调用按钮时。 |
结构更改 | 当UI 自动化树的结构发生更改时触发。 当桌面上有新 UI 项变得可见、隐藏或删除时,结果便发生更改。 |
全局更改 | 当对客户端进行全局兴趣的操作(例如焦点从一个元素切换到另一个元素或子窗口关闭时)时触发。 一些事件不一定意味着 UI 状态已更改。 例如,如果用户选项卡到文本输入字段,然后单击一个按钮来更新字段,即使用户实际上没有更改文本, TextChanged 事件也会触发。 处理事件时,客户端应用程序在执行操作之前可能有必要检查是否实际发生了任何更改。 |
AutomationEvents 标识符
UI 自动化事件由AutomationEvents 值。 枚举的值唯一标识事件类型。
引发事件
UI 自动化客户端可以订阅自动化事件。 在自动化对等模型中,自定义控件的对等方必须通过调用 RaiseAutomationEvent 方法报告与辅助功能相关的控件状态的更改。 同样,当键UI 自动化属性值更改时,自定义控件对等方应调用 RaisePropertyChangedEvent 方法。
下一个代码示例演示如何从控件定义代码中获取对等对象,并调用方法从该对等方触发事件。 作为优化,代码确定此事件类型是否有任何侦听器。 仅当侦听器避免不必要的开销并帮助控件保持响应状态时,才触发事件并创建对等对象。
if (AutomationPeer.ListenerExists(AutomationEvents.PropertyChanged))
{
NumericUpDownAutomationPeer peer =
FrameworkElementAutomationPeer.FromElement(nudCtrl) as NumericUpDownAutomationPeer;
if (peer != null)
{
peer.RaisePropertyChangedEvent(
RangeValuePatternIdentifiers.ValueProperty,
(double)oldValue,
(double)newValue);
}
}
对等导航
定位自动化对等方后,UI 自动化客户端可以通过调用对等对象的 GetChildren 和 GetParent 方法来导航应用的对等结构。 对等方实现 GetChildrenCore 方法支持控件中的 UI 元素之间的导航。 UI 自动化系统调用此方法以构建控件中包含的子元素树;例如,列表框中的列表项。 FrameworkElementAutomationPeer 中的默认 GetChildrenCore 方法遍历元素的可视化树,以生成自动化对等树。 自定义控件可以重写此方法,以向自动化客户端公开子元素的不同表示形式,返回传达信息或允许用户交互的元素的自动化对等。
本机自动化对文本模式的支持
某些默认 UWP 应用自动化对等方为文本模式(PatternInterface.Text)提供控制模式支持。 但是,它们通过本机方法提供此支持,所涉及的对等方不会注意到 (托管) 继承中的 ITextProvider 接口。 不过,如果托管或非托管UI 自动化客户端查询对等模式,它将报告对文本模式的支持,并在调用客户端 API 时为模式的各个部分提供行为。
如果打算从其中一个 UWP 应用文本控件派生,并创建派生自其中一个与文本相关的对等的自定义对等,请检查对等方的“备注”部分,详细了解对模式的任何本机级别支持。 如果从托管提供程序接口实现调用基实现,则可以访问自定义对等中的本机基行为,但很难修改基本实现的作用,因为对等控件及其所有者控件上的本机接口不会公开。 通常,应按原样使用基本实现(仅调用基)或完全将功能替换为你自己的托管代码,并且不调用基本实现。 后者是一种高级方案,你需要非常熟悉控件正在使用的文本服务框架,以便在使用该框架时支持辅助功能要求。
AutomationProperties.AccessibilityView
除了提供自定义对等,还可以通过在 XAML 中设置 AutomationProperties.AccessibilityView 来调整任何控件实例的树视图表示形式。 这不是作为对等类的一部分实现的,但我们将在此处提及它,因为它是对自定义控件或自定义模板的整体辅助功能支持。
使用 AutomationProperties.AccessibilityView 的主要方案是从UI 自动化视图中故意省略模板中的某些控件,因为它们不会对整个控件的辅助功能视图造成有意义的贡献。 若要防止出现这种情况,请将 AutomationProperties.AccessibilityView 设置为“Raw”。
从自动化对等方引发异常
允许为自动化对等支持实现的 API 引发异常。 预计在引发大多数异常后,侦听的任何UI 自动化客户端都足以继续运行。 在侦听器查看所有包含除你自己的应用在内的全面自动化树的可能性下,只是因为客户端调用其 API 时,树的一个区域引发了基于对等的异常,因此这是一种无法接受的客户端设计来关闭整个客户端。
对于传入对等方的参数,验证输入是可以接受的,例如,如果参数传递为 null 且该参数不是实现的有效值,则引发 ArgumentNullException。 但是,如果对等执行了后续操作,请记住,对等方与宿主控件的交互具有一些异步字符。 对等方所做的任何操作都不一定阻止控件中的 UI 线程(并且可能不应这样做)。 因此,在创建对等时或首次调用自动化对等方法时,可能有一些属性可用或具有某些属性的情况,但在此期间,控件状态已更改。 对于这些情况,提供程序可以引发两个专用异常:
- 如果无法根据 API 传递的原始信息访问对等所有者或相关对等元素,则引发 ElementNotAvailableException。 例如,你可能有一个正在尝试运行其方法的对等方,但自那以后,所有者已被从 UI 中删除,例如已关闭的模式对话框。 对于非 .NET 客户端,该对等将映射到 UIA_E_ELEMENTNOTAVAILABLE。
- 如果仍有所有者,则引发 ElementNotEnabledException,但该所有者处于 IsEnabled
=
false 等模式,阻止了对等方尝试完成的某些特定编程更改。 对于非 .NET 客户端,该对等将映射到 UIA_E_ELEMENTNOTENABLED。
除此之外,对等方应该相对保守,因为他们从对等支持中引发的异常。 大多数客户端无法处理来自对等方的异常,并将这些异常转换为用户与客户端交互时可以做出的可操作选择。 因此,有时不执行任何操作,并且捕获异常而不在对等实现中重新引发,这比每次对等方尝试执行的操作都不起作用时引发异常更好。 另请注意,大多数UI 自动化客户端不是用托管代码编写的。 大多数客户端将采用 COM 编写,并仅用于在调用最终会访问对等的 UI 自动化客户端方法时,在 HRESULT 中检查 S_OK。