动态批注的替代方法
还有其他方法可为 UI 元素提供自定义 的 IAccessible 支持,在某些情况下,它们是正确的解决方案。 在动态批注之前,这些替代技术是开发人员唯一可用的选项。 它们包括实现所有 IAccessible 接口和编程技术。
实现所有 IAccessible 接口
另一种方法是实现所有 IAccessible 接口。 此方法通常是自定义控件或完全不同的 UI 元素所必需的;但是,开发和测试成本非常巨大,除非确实有必要,否则应避免这样做。 如果目标是修改单个属性,则成本难以证明。
编程技术
另一种选择是使用子类化和包装技术来修改为特定属性公开的信息。 这是动态批注旨在取代的技术。 若要使用子类化和包装替代单个属性,开发人员必须执行以下步骤:
- 子类 IAccessible 对象的 HWND。
- 截获正确的 IParam/OBJID 值的 WM_GETOBJECT 消息。
- 使用 CallWndProc 回调函数将WM_GETOBJECT消息转发到基类。 如果返回零,则调用 CreateStdAccessibleObject;否则,对返回的值调用 LresultFromObject 以获取控件的本机 IAccessible 接口指针。
- 创建一个包装类,该类实现 IAccessible 并包装上一步返回的 IAccessible 接口指针。 此包装类将所有方法和属性发送到原始 IAccessible 接口指针,但要重写的方法和属性除外。 这涉及到为所有 IAccessible 接口的 21 个属性和方法编写转发代码,而不管实际重写多少。
此外,开发人员必须验证以下条件:
- 重写的方法或属性必须仅处理所需的子 ID,并将所有其他子 ID 转发到原始 IAccessible 接口指针。
- 仅当原始对象支持 IEnumVARIANT 和 IOleWindow 接口时,包装还必须转发它们。
- 必须正确处理引用计数,尤其是在支持其他接口的情况下。
- 必须正确处理 IDispatch 返回值,尤其是使用 ITypeInfo::Invoke 方法,必须使用指向包装器接口的接口指针(而不是指向原始 IAccessible 接口的指针)调用该方法。
即使只需要重写一个或两个属性,这些技术也需要大量的工作。 生成的大多数代码都与子类化和包装有关,实际上只有一小部分提供重写的信息。
但是,在某些情况下需要这些技术。 例如,如果要进行结构更改以创建占位符 UI 元素,则应使用这些技术,而不是动态批注。
修复从标签派生的名称
某些 Microsoft Win32 常用控件(如编辑框控件)几乎始终与标签 (资源文件) 中的 LTEXT 条目或资源文件) 中 GROUPBOX (GROUPBOX 的组框一起使用。 Microsoft Active Accessibility 会自动从其标签派生控件的名称属性。 对于此类控件,窗口文本 (Microsoft Visual Studio 中显示为 Name 或 ID 属性) 将被忽略,因为它通常是自动生成的,并且很少具有描述性;例如“IDC_EDIT1”。
如果应用程序的用户界面设计不正确,Microsoft Active Accessibility 可能无法正确设置名称。 若要与控件关联,标签或组框必须紧靠在 Tab 键顺序中的动态控件前面。
当资源编辑器) 打开时,可以使用 Visual Studio 中的工具 (“ 格式 ”菜单上的工具来更改 Tab 键顺序,也可以直接编辑资源文件。
以下示例显示了资源文件对包含两个标记编辑框的对话框的说明。
IDD_INPUTNAME DIALOGEX 22, 17, 312, 118
STYLE DS_SETFONT | DS_MODALFRAME | WS_CAPTION | WS_SYSMENU
CAPTION "Enter your name"
FONT 8, "System", 0, 0, 0x0
BEGIN
DEFPUSHBUTTON "OK",IDOK,179,35,30,11,WS_GROUP
LTEXT "First Name:",IDC_STATIC,8,16,43,8
LTEXT "Last Name:",IDC_STATIC,8,33,43,8
EDITTEXT IDC_EDITFIRSTNAME,53,15,120,12,ES_AUTOHSCROLL
EDITTEXT IDC_EDITLASTNAME,53,34,120,12,ES_AUTOHSCROLL
END
在此示例中,标签和控件未按正确的 Tab 键顺序列出。 因此,Microsoft Active Accessibility 会将名称“姓氏”分配给名字编辑框,而姓氏编辑框根本没有名称。
以下示例显示了正确的资源列表。 另请注意,标签中已指定快捷键。
IDD_INPUTNAME DIALOGEX 22, 17, 312, 118
STYLE DS_SETFONT | DS_MODALFRAME | WS_CAPTION | WS_SYSMENU
CAPTION "Enter your name"
FONT 8, "System", 0, 0, 0x0
BEGIN
LTEXT "&First Name:",IDC_STATIC,8,16,43,8
EDITTEXT IDC_EDITFIRSTNAME,53,15,120,12,ES_AUTOHSCROLL
LTEXT "&Last Name:",IDC_STATIC,8,33,43,8
EDITTEXT IDC_EDITLASTNAME,53,34,120,12,ES_AUTOHSCROLL
DEFPUSHBUTTON "OK",IDOK,179,35,30,11,WS_GROUP
END
当控件具有补充标签(例如跟踪条上的最小值和最大值)时,这些标签应按 Tab 键顺序放置在控件之后。 控件的main标签必须紧接在控件本身之前。
不带标签的命名控件
并非总是可能或需要为每个控件提供可见标签。 但是,仍可以通过添加不可见标签来为控件提供名称。 与往常一样,不可见标签必须紧接在 Tab 键顺序的控件前面。
如果在 Microsoft Visual Studio .NET 中使用资源编辑器,可以将 Visible 属性设置为 False。 若要使标签在编辑资源文件 (.rc) 时不可见,请将 NOT WS_VISIBLE 或 添加到标签控件的样式部分,如以下示例所示。
LTEXT "&FullName:",IDC_STATIC,111,23,44,8,NOT WS_VISIBLE
请注意,即使标签不可见,任何指定的快捷键也能正常工作。