通过


自定义的自动化对等

本文介绍 Microsoft UI 自动化 中的自动化对等体,以及如何为自定义 UI 类提供可靠的自动化支持。

注释

本指南使用 WinUI 3/Windows 应用 SDK 的命名空间和引用,基于 Microsoft.UI.Xaml.Automation.Peers.AutomationPeer

UI 自动化提供了一个框架,供自动化客户端用于跨平台检查和与用户界面交互。 在Windows应用中,大多数内置控件都已提供UI 自动化支持。 从现有非密封类派生新控件或支持类型时,可能会引入默认对等方未表示的行为。 在这种情况下,可以通过从相应的AutomationPeer派生,添加所需的提供者行为,并确保控件基础结构创建您的对等项,来增强自动化支持。

UI 自动化支持辅助功能工具(如屏幕阅读器)和自动化测试系统。 在这两种情况下,外部代码都可以检查 UI 元素并模拟与应用的交互。 有关更广泛的平台指南,请参阅 UI 自动化 概述

对于优先进行辅助功能和自动测试的团队,自动化协作伙伴也是可靠性契约。 稳定的自动化结构和准确的模式支持提高了辅助技术行为和长期测试稳定性。

UI 自动化有两个主要受众。

  • UI 自动化 clients调用UI 自动化 API 来发现和与当前可用的 UI 进行交互。 例如,屏幕阅读器是UI 自动化客户端。 用户导航自动化元素树,并可以针对某个应用或整个桌面树。
  • UI 自动化 providers通过实现应用引入控件的API,将信息发布到该树中。 生成自定义控件时,您正在参与提供程序模型,应确保控件能够被无障碍和测试客户端使用。

框架通常公开并行 API 图面:一个用于客户端,一个用于提供程序。 本主题重点介绍提供程序的扩展性,尤其是对等的类和提供程序接口。 引用客户端 API 仅供上下文理解。 有关客户端指南,请参阅UI 自动化客户端程序员指南

注释

UI 自动化客户端通常是桌面应用,通常不使用托管代码。 UI 自动化基于标准,而不是特定实现或框架。 许多现有的UI 自动化客户端,包括屏幕阅读器等辅助技术产品,使用组件对象模型(COM)接口与子窗口中运行的UI 自动化、系统和应用进行交互。 有关 COM 接口以及如何使用 COM 编写UI 自动化客户端的详细信息,请参阅 UI 自动化 基础知识

确定自定义 UI 类的 UI 自动化 支持的现有状态

在实现自定义自动化对等对象之前,请检查基础控件及其自动化对等对象是否已提供所需的支持。 在许多情况下, FrameworkElementAutomationPeer、特定于控件的对等方及其内置模式已足够。 自定义需求取决于控件与基本对象模型之间的分歧程度,以及模板或交互更改是否引入了需要其他辅助功能支持的新用户体验。

作为此评估的一部分,请验证默认的节点行为是否足以支持自动化的无障碍测试,而不仅仅依赖于手动检查。 如果测试方案依赖于特定模式、名称或层次结构,请实现自定义对等方,以便这些期望保持显式且可维护。

即使基本行为在功能上是可以接受的,但在精确 ClassName 报告对自动化和测试可靠性十分重要时,仍建议定义自己的对等组件,尤其是当控件被计划用于他人重用时。

自动化对等类

WinUI 和相关的 XAML 框架建立在早期托管 UI 栈(如 Windows 窗体、WPF 和 Silverlight)中的 UI 自动化 约定上。 许多控件和对等概念都遵循这些既定模式。

按照约定,对等类名以控件类名开头,以“AutomationPeer”结尾。 例如, ButtonAutomationPeerButton 控件类的对等类。

注释

出于本主题的目的,我们在实现控件对等对象时,将与辅助功能相关的属性视为更加重要。 但是,对于更一般化的UI 自动化支持概念,应根据UI 自动化提供商程序员指南UI 自动化基础知识中的建议来实现对应组件。 这些主题未涵盖在 WinUI 和 Windows 应用 SDK 中使用的特定 AutomationPeer API,但它们确实描述了标识类或提供其他信息或交互的属性。

对等方、模式和控件类型

控件模式是一种接口实现,它向 UI 自动化 客户端揭示控件功能的特定方面。 UI 自动化客户端使用通过控件模式公开的属性和方法来检索有关控件功能的信息,或在运行时操作控件的行为。

控件模式独立于控件的视觉效果或特定类标识来展示行为。 例如,表格控件可以公开 Grid ,以便客户端可以查询维度和检索项。 客户端可以将 Invoke 用于可调用控件(如按钮)和 滚动 用于可滚动图面(如列表控件)。 模式是可组合的,因此单个控件可以公开多个行为。

控件模式与 UI 相关,因为接口与 COM 对象相关。 在 COM 中,可以查询对象以询问它支持哪些接口,然后使用这些接口访问功能。 在UI 自动化中,UI 自动化客户端可以查询UI 自动化元素来找出它支持的控件模式,然后通过受支持控件模式公开的属性、方法、事件和结构与元素及其对等控件进行交互。

自动化对等方的主要职责之一是声明支持哪些模式。 提供程序通过重写GetPatternCore,这是GetPattern的支持方式,来执行此操作。 客户端一次查询一个模式;如果受支持,则对等方返回对象(通常本身),否则返回 null

控件类型用于广泛分类由对等方表示的功能。 这不同于控件模式:模式描述特定功能,而控件类型则描述更高级别的角色。 每个控件类型都有以下方面的指南:

  • UI 自动化控件模式:控件类型可能支持多个模式,每个模式表示不同的信息或交互分类。 每个控件类型都有一组控件模式,控件必须支持的一组控件模式、一个可选集,以及控件不能支持的集。
  • UI 自动化属性值:每种控件类型都有一组必须支持的属性。 这些是常规属性,如 UI 自动化 Properties Overview 中所述,而不是特定于模式的属性。
  • UI 自动化事件:每个控件类型都有一组控件必须支持的事件。 同样,这些是常规的,而不是特定于模式的,如 UI 自动化 事件概述中所述。
  • UI 自动化树结构:每个控件类型定义控件在UI 自动化树结构中的显示方式。

无论框架详细信息如何,客户端行为都不会绑定到特定的 XAML 应用模型。 许多现有客户端(包括辅助技术)通过 COM 进行交互。 在该模型中,客户端通过QueryInterface请求模式接口或常规自动化接口,自动化基础结构负责封送调用到应用程序的提供程序和对等实现。

为托管代码Windows应用实现控制模式时,可以使用.NET接口来表示这些模式,而不是 COM 接口语法。 例如,用于 .NET 提供程序实现的 UI 自动化模式接口是 IInvokeProvider

有关控件模式、提供程序接口及其用途的列表,请参阅 控件模式和接口。 有关控件类型,请参阅 UI 自动化 控件类型概述

有关如何实现控件模式的指南

控制模式指南是整个 UI 自动化 平台的一部分,而不仅仅是特定应用模型的一部分。 实现模式时,请使行为与Microsoft文档和UI 自动化惯例保持一致。 首先开始实现UI 自动化中的控制模式,尤其是每个模式的实现和必需成员部分。 尽管这些引用通常描述本机 COM 接口,但在 Microsoft.UI.Xaml.Automation.Provider 中提供了 WinUI 的等效提供程序接口。

如果您使用默认的自动化对等体并扩展其行为,则这些对等体已经按照UI 自动化准则编写。 如果它们支持控制模式,您可以依赖这些模式支持,以符合实现UI 自动化控制模式中的指导。 如果控件对等方报告说它代表由 UI 自动化 定义的控件类型,那么该对等方已遵循Supporting UI 自动化 控件类型中记录的指导。

实现默认控件未涵盖的模式或控件类型时,通常需要其他解释。 例如,默认 XAML 控件不实现批注模式。 如果应用依赖于批注工作流,则对等方可以实现 IAnnotationProvider ,并报告具有传达批注功能的属性 的文档 控件类型。

建议按照您在实现UI自动化控件模式支持UI自动化控件类型中的指南使用,以作为指导方向和常规指南。 API 链接提供有关 API 用途的说明和备注。 对于 WinUI 语法的具体使用,请使用 Microsoft.UI.Xaml.Automation.Provider 命名空间中的等效 API。

内置自动化对等程序类

通常,当元素是交互式的或向辅助技术提供有意义信息时,它们会公开自动化同级对象。 并非所有视觉元素都需要对等方。 例如, ButtonTextBox 具有对等方,而基于 边框面板的布局类型(如 网格画布 )则没有。 面板只提供布局,并且没有直接的辅助功能交互模型,因此其有意义的子元素通过具有对等的最近的上级浮出水面。

UI 自动化 进程边界

UI自动化用于检查Windows应用的客户端通常在进程外运行。 UI 自动化基础结构处理跨进程通信。 有关详细信息,请参阅 UI 自动化 基础知识

OnCreateAutomationPeer

UIElement 派生的所有类都包含受保护的虚拟方法 OnCreateAutomationPeer。 自动化代理的对象初始化序列调用 OnCreateAutomationPeer 来获取每个控件的自动化代理对象,从而构建运行时使用的 UI 自动化树。 UI 自动化代码可以使用同级对象获取有关控件的特性和功能的信息,并通过其控件模式模拟用户交互。 支持自动化的自定义控件必须重写 OnCreateAutomationPeer ,并返回派生自 AutomationPeer 的类的实例。 例如,如果自定义控件派生自 ButtonBase 类, OnCreateAutomationPeer 返回的对象应派生自 ButtonBaseAutomationPeer

如果您正在编写自定义控件并定义自定义对等,请重写OnCreateAutomationPeer以返回该对等类型的新实例。 对等方必须直接或间接地从 AutomationPeer 派生。

例如,以下代码声明自定义控件NumericUpDown 使用NumericUpDownPeer 来实现 UI 自动化。

using Microsoft.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 : Microsoft.UI.Xaml.Controls.Primitives.RangeBase
    {
        NumericUpDown();
        Int32 MyProperty;
    }
}

// NumericUpDown.h
...
struct NumericUpDown : NumericUpDownT<NumericUpDown>
{
    ...
    Microsoft::UI::Xaml::Automation::Peers::AutomationPeer OnCreateAutomationPeer()
    {
        return winrt::make<MyNamespace::implementation::NumericUpDownAutomationPeer>(*this);
    }
};
//.h
public ref class NumericUpDown sealed : Microsoft::UI::Xaml::Controls::Primitives::RangeBase
{
// other initialization not shown
protected:
    virtual AutomationPeer^ OnCreateAutomationPeer() override
    {
         return ref new NumericUpDownAutomationPeer(this);
    }
};

注释

OnCreateAutomationPeer 的实现不应做任何其他事情,只需初始化自定义自动化对等方的新实例,将调用的控件作为所有者传递,并返回该实例。 请勿尝试此方法中的其他逻辑。 具体而言,任何可能导致在同一调用中销毁 AutomationPeer 的逻辑都可能导致意外的运行时行为。

在典型的 OnCreateAutomationPeer 实现中, 所有者Me,因为重写在控制实例范围内执行。

可以在控件所在的同一文件中或在单独的文件中定义对等类。 框架对等类型位于 Microsoft.UI.Xaml.Automation.Peers,但您的自定义对等项可以存在于任何命名空间中,只要在实现OnCreateAutomationPeer时引用所需的命名空间即可。

选择正确的对等基类

从与控件的功能基类匹配的最接近的对等基类派生自定义 AutomationPeer 。 在前面的示例中, NumericUpDown 派生自 RangeBase,因此 RangeBaseAutomationPeer 是正确的对等基。 这样,便可以重复使用现有的 IRangeValueProvider 行为,而不是重新实现它。

Control 类没有相应的对等类。 如果需要一个对等类来对应于派生自 Control 的自定义控件,请从 FrameworkElementAutomationPeer 派生自定义对等类。

如果直接派生自 ContentControl ,该类没有默认的自动化对等行为,因为没有引用对等类的 OnCreateAutomationPeer 实现。 因此,请确保实现 OnCreateAutomationPeer 来使用特定的辅助对象,或者如果辅助功能支持级别足以满足控件的需求,则使用 FrameworkElementAutomationPeer 作为辅助对象。

注释

通常不会继承 AutomationPeer,而是 FrameworkElementAutomationPeer。 如果直接从 AutomationPeer 派生,就需要复制很多原本由 FrameworkElementAutomationPeer 提供的基本无障碍支持。

自定义对等类的初始化

自定义对等应公开一个类型安全的构造函数,该构造函数接收所有者控件并将其传递给基类初始化程序。 在下一个示例中, owner 传递给 RangeBaseAutomationPeer,最终 FrameworkElementAutomationPeer 使用该值来设置 FrameworkElementAutomationPeer.Owner

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 : Microsoft.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 :  Microsoft::UI::Xaml::Automation::Peers::RangeBaseAutomationPeer
//.cpp
public:    NumericUpDownAutomationPeer(NumericUpDown^ owner);

AutomationPeer 的核心方法

可重写的自动化方法以对的形式呈现:一个供提供程序基础设施使用的公共方法,和一个用于自定义的受保护Core方法。 默认情况下,公共方法会转发到相应的 Core 方法,在需要时回退到基本实现。

在为自定义控件实现协作对象时,当行为与基本协作对象行为不同时,应重写 Core 方法。 UI 自动化通过公共方法检索信息,但自定义的切入点在于相应的Core重写。

至少,每当定义新的对等类时,都实现 GetClassNameCore 方法,如下一示例所示。

protected override string GetClassNameCore()
{
    return "NumericUpDown";
}

注释

你可能希望将字符串存储为常量,而不是直接存储在方法正文中,但由你决定。 对于 GetClassNameCore,无需本地化此字符串。 LocalizedControlType 属性在UI 自动化客户端需要本地化字符串时使用,而不是ClassName

获取自动化控件类型

某些辅助技术提供 UI 自动化 Name以及 GetAutomationControlType。 如果控件的角色与基类角色有显著不同,请实现自定义对等对象并重写 GetAutomationControlTypeCore。 从 ItemsControlContentControl 等通用基础派生时,这一点尤其重要。

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。 如果受支持,重写应返回实现对象,通常是对等体本身。 如果不受支持,则返回 null (通常通过委托基行为并让其返回 null)。

当模式受支持时, GetPatternCore 可以返回 模式或 Me。 然后,客户端将 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 自动化 客户端能够使用这些模式。

有关 WinUI 支持的UI 自动化提供程序模式的列表,请参阅 Microsoft。Ui。Xaml.Automation.Provider。 每个此类模式都有一个对应的 PatternInterface 枚举值,UI 自动化 客户端就是通过在 GetPattern 调用中请求该模式。

对等方可以报告它支持多个模式。 如果是这样,重写应包括每个支持的 PatternInterface 值的返回路径逻辑,并在每种匹配的情况中返回对应的对象。 调用方应一次仅请求一个接口,而且需要由调用方负责将其转换为预期的接口。

下面是自定义对等方 GetPatternCore 重写的示例。 它报告对两种模式的支持: IRangeValueProviderIToggleProvider。 此处的控件是一个媒体显示控件,可以显示为全屏(切换模式),并且具有一个进度栏,用户可以在其中选择位置(范围控件)。 此代码来自 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);
}

其他核心方法

你的控件可能需要核心方案的键盘替代项;有关详细信息,请参阅 键盘辅助功能。 密钥行为属于控制逻辑,但对等方应通过 GetAcceleratorKeyCoreGetAccessKeyCore 报告密钥元数据。 如果关键说明面向用户,请通过资源对其进行本地化。

如果控件公开集合,请使用已实现集合行为的函数类和对等基类。 否则,重写 GetChildrenCore 以准确表示自动化树中的父子关系。

实现 IsContentElementCoreIsControlElementCore ,以指示控件是否应被视为内容、控件或两者。 两者都默认为 true。 这些值可帮助屏幕阅读器等客户端有效地筛选和导航树。 如果 GetPatternCore 将行为转发到子元素的对应实体,则子元素可以返回 false ,以避免进入公开树。

某些控件可能支持标记方案,其中文本标签部件提供非文本部件的信息,或控件旨在与 UI 中的另一个控件处于已知的标记关系中。 如果可以提供有用的基于类的行为,则可以通过重写 GetLabeledByCore 来实现该行为。

GetBoundingRectangleCoreGetClickablePointCore 主要用于自动测试方案。 如果要支持控件的自动测试,可能需要重写这些方法。 对于范围类型控件,这可能是所期望的,因为用户单击坐标空间对一个范围有不同的影响,因此无法仅建议单个点。 例如,默认 ScrollBar 自动化伙伴会重写 GetClickablePointCore 以返回“非数字” 值。

GetLiveSettingCore影响 UI 自动化 中控件 `LiveSetting` 值的默认设置。 如果您希望控件返回值不是AutomationLiveSetting.Off,则可能需要重写此设置。 有关 LiveSetting 所表示的内容的详细信息,请参阅 AutomationProperties.LiveSetting

如果控件具有可映射到 AutomationOrientation 的可设置方向属性,则可以替代 GetOrientationCore ScrollBarAutomationPeerSliderAutomationPeer 类执行此操作。

FrameworkElementAutomationPeer 中的基本实现

FrameworkElementAutomationPeer 基本实现提供从框架级布局和行为状态推断的自动化信息。

注释

默认框架对等方通过使用内部本机代码实现行为,不一定使用投影托管代码。 无法通过公共语言运行时 (CLR) 反射或类似技术检查完整的实现详细信息。 你也不会看到特定于子类的基对等行为的替代的不同引用页。 例如,TextBoxAutomationPeerGetNameCore 可能有其他行为,该行为不会在 AutomationPeer.GetNameCore 参考页上描述,并且没有专用的 TextBoxAutomationPeer.GetNameCore 参考页。 相反,请阅读最直接对等类的参考主题,并在“备注”部分查找实现说明。

Peers 和 AutomationProperties

自动化对等方应为辅助功能元数据提供合理的默认值。 你仍然可以在控件实例上通过 AutomationProperties 附加属性来覆盖该元数据的各个部分。 这适用于内置控件和自定义控件。 例如:<Button AutomationProperties.Name="Special" AutomationProperties.HelpText="This is a special button."/>

有关 AutomationProperties 附加属性的详细信息,请参阅 基本辅助功能信息

某些 AutomationPeer 方法用于符合一般提供程序合同,但通常不会在控制对等项中进行自定义,因为应用程序通常通过 AutomationProperties 提供这些数据。 例如,许多应用与 AutomationProperties.LabeledBy 建立标签关系。 相比之下, LabeledByCore 通常仅在为内部项/标头关系建模的对等方中实现。

实现模式

请考虑具有展开/折叠功能的控件。 当为 GetPattern 查询 PatternInterface.ExpandCollapse 时,其对应接口应返回自身,需实现 IExpandCollapseProvider 并定义 ExpandCollapseExpandCollapseState

将辅助功能设计到控件 API 本身。 当可以通过直接 UI 交互或自动化模式触发行为时,请通过共享控制逻辑路由这两个路径。 例如,如果按钮处理程序和键盘命令可以展开/折叠状态,则应调用 “展开 ”和 “折叠”的对等实现所使用的相同内部方法。 无论调用路径如何,这都会保持行为和视觉状态转换一致。

典型的实现是提供程序 API 首先调用 所有者 ,以便在运行时访问控制实例。 然后,可以在该对象上调用必要的行为方法。

public class IndexCardAutomationPeer : FrameworkElementAutomationPeer, IExpandCollapseProvider {
    private IndexCard ownerIndexCard;
    public IndexCardAutomationPeer(IndexCard owner) : base(owner)
    {
         ownerIndexCard = owner;
    }
}

另一种实现方式是控件本身可以引用其对等体。 如果从控件引发自动化事件,这是一种常见模式,因为 RaiseAutomationEvent 方法是对等方法。

UI 自动化事件

UI 自动化事件通常属于这些类别。

事件 说明
属性更改 当某个UI 自动化元素或控件模式下的属性发生变化时触发。 例如,如果客户端需要监视应用的复选框控件,则可以注册以侦听 ToggleState 属性上的属性更改事件。 选中或取消选中复选框控件时,提供程序会触发事件,客户端可以根据需要进行操作。
元素操作 当用户或程序活动导致 UI 中发生更改时触发; 例如,当通过 Invoke 模式点击按钮或调用时。
结构更改 当UI 自动化树的结构发生更改时触发。 当新 UI 项在桌面上可见、隐藏或删除时,结构会发生变化。
全局更改 当对客户端进行全局兴趣的操作(例如焦点从一个元素切换到另一个元素或子窗口关闭时)时触发。 某些事件不一定意味着 UI 的状态已更改。 例如,如果用户按下“Tab”键移动到文本输入字段,然后单击一个按钮来更新字段,即使用户实际上没有更改文本,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 自动化客户端可以通过调用 GetChildrenGetParent 来导航应用的对等结构。 在控件中,子级导航由 GetChildrenCore 生成,UI 自动化使用其生成子树(例如列表中的项)。 FrameworkElementAutomationPeer 中的默认实现遍历可视化树。 自定义控件可以重写此项,以展示更有意义的自动化表达。

原生自动化对文本模式的支持

某些默认框架组件通过原生实现支持文本模式(PatternInterface.Text),因此 ITextProvider 可能不会出现在托管继承中。 即便如此,来自托管或非托管客户端的模式查询仍可以报告文本模式支持并公开相应的行为。

如果您打算从某个文本控件派生,并创建一个从与文本相关的对等对象派生的自定义对等对象,请检查 API 参考中的“备注”部分,以了解关于本机级别对模式支持的更多信息。 如果您从托管提供程序接口的实现中调用基础实现,则可以访问自定义端点中的本机基础行为,但要修改基础实现的作用就很困难,因为对等控件及其所有者控件上的本机接口未公开。 通常,您应无修改地使用基本实现(仅调用基本实现),或者完全用您自己的托管代码替换该功能,并且不调用基本实现。 后者是一种高级场景,它要求对控件使用的文本服务框架有深入了解,以便满足辅助功能要求。

自动化属性.可访问性视图

除了自定义对等对象,还可以通过在 XAML 中设置 AutomationProperties.AccessibilityView 来调整为每个控件实例的自动化树表示形式。 这不是同行代码,但在改进自定义模板的无障碍性时通常很重要。

主要用例是省略没有为组合控件提供有意义的辅助功能语义的模板部件。 为此,请将 AutomationProperties.AccessibilityView 设置为“Raw”。

从自动化同级对象抛出异常

允许对等实现引发异常,预期可靠的客户端会继续处理。 实际上,客户端通常会检查跨多个应用的自动化树,因此一个子树中的故障不应终止客户端进程。

输入验证是适当的。 例如,如果实现的 null 无效,则引发 ArgumentNullException。 此外,还需考虑时间因素:对等体交互并不总是与当前视觉状态同步,因此在对等体创建和方法执行之间,控制状态可能会发生变化。 对于这些场景,供应商可以使用两种专用异常处理:

  • 如果无法根据 API 传递的原始信息访问对等所有者或相关对等元素,则引发 ElementNotAvailableException 。 例如,你可能有一个正在尝试运行其方法的对等方,但自那以后,所有者已被从 UI 中删除,例如已关闭的模式对话框。 对于非.NET客户端,这对应于UIA_E_ELEMENTNOTAVAILABLE
  • 如果仍有所有者,则引发 ElementNotEnabledException ,但该所有者处于 IsEnabled=false 等模式,阻止了对等方尝试完成的某些特定编程更改。 对于非.NET客户端,这映射到 UIA_E_ELEMENTNOTENABLED

更普遍地说,要谨慎处理例外情况。 许多客户端无法将提供程序异常转换为有意义的用户操作。 在某些路径中,无操作行为或本地异常处理比反复抛出更可取。 另请记住,许多UI 自动化客户端都是基于 COM 的,主要评估 HRESULT 结果,例如 S_OK