.net - 使用 UI 自动化时避免切换焦点

标签 .net wpf focus ui-automation

出于好奇,我决定编写一个简单的工具,其功能类似于 UI Spy 。基本上,它显示控件树并允许查看每个控件的属性。现在,我已经开始实现模式交互,并遇到了以下问题:一旦用户在我的应用程序 UI 自动化中单击“InvokePatter.Invoke”,就会将焦点切换到我的目标应用程序。其他模式也会发生同样的情况。它在原始 UI Spy 应用程序中的行为方式也相同。

这种行为使得我无法使用我的应用程序操作菜单,因为当我再次单击我的应用程序时,测试的应用程序将失去焦点并且菜单正在关闭。我想做的是使用 UI 自动化与应用程序交互,但保持我的(UI Spy)应用程序的焦点。有什么想法如何实现它?或者至少如何实现所需的功能 - 允许用户与菜单交互?

最佳答案

UIAutomation 是有意这样做的:应用程序通常只希望在获得焦点时接收输入。为了发送键盘输入,您必须首先将其聚焦。或者,如果您单击某个控件与之交互 - 它通常会因单击而获得焦点,然后执行操作。如果您在没有先向它们发送焦点的情况下向某些应用程序发送输入,它们会变得非常困惑(有时甚至会崩溃)。

(例如,这些应用程序可能会初始化 WM_SETFOCUS 中的某些内部状态,并在接收输入时依赖该状态已准备好。这实际上不能被视为错误,因为 Windows 本质上 promise 在发送输入之前发送 WM_SETFOCUS,所以这确实是发送“伪造”输入的工具破坏了这里的契约(Contract)。)

菜单是一个比较棘手的情况:首先,在 Windows 中,菜单仅出现在具有焦点的应用程序上。因此,要显示菜单,具有菜单的应用程序必须具有焦点,因此焦点必须从 UISpy 切换出来:没有办法解决这个问题。但菜单的真正问题不是 UIAutomation 将焦点切换到应用程序:而是单击工具 (UISpy) 将导致菜单被关闭。这不是 UIAutomation 问题 - 这只是 Win32 处理菜单的方式。因此,这里真正的问题是:当单击该工具将关闭我正在尝试使用的菜单时,如何使用工具来浏览或以其他方式操作菜单?

有几种方法可以解决这个问题 - 其中 Inspect Objects tool (inspect.exe) uses 。 Inspect.exe 是 UISpy 的旧 MSAA 前身,但更新版本(作为 SDK 的一部分提供)现在支持 MSAA 和 UIAutomation。以下技术仅在几个地方实现(例如 SetFocus、导航命令,但不是 Invoke.Invoke()),但您可以根据需要在自己的工具中使用这些技术。

它使用两种方法解决这个问题:

  • 热键 - 热键本身不会改变焦点或关闭菜单 - 所以使用 RegisterHotKey()为您可能想要对当前对象执行的每个操作分配一个热键(例如 Ctrl-Shift-X)。现在,当目标应用程序获得焦点并且菜单出现时,您可以使用热键组合向工具发出信号以执行适当的操作。

  • 创造性地使用鼠标:你不能使用鼠标来点击UI,但你仍然可以利用鼠标的位置。 Inspect 有一个“事件悬停工具栏”选项(在“选项”菜单下):选择后,如果将鼠标悬停在工具栏项目上几秒钟,它会将其视为已单击。例如,这允许您浏览菜单项,而无需实际单击任何检查 UI。在内部,它可能使用轮询和 TB_HITTEST 的某种组合。找出指针位于哪个按钮上。

或者您可以组合使用这些方法:使用热键在鼠标指针悬停在工具上时触发命令 - 无论哪种方式适合您。

关于.net - 使用 UI 自动化时避免切换焦点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9354221/

相关文章:

.net - Nant:指示 MySql 创建数据库并运行脚本

jquery - 如何模仿对div元素的关注?

javascript - jQuery失去焦点事件

java - Java Swing FocusListener的MVC实现

c# - 添加引用对话框中的程序集是否因使用的 .Net 框架而异?

c# - AutoMapper:根据枚举的值将类映射到 View 模型

c# - 将按钮控件嵌入到现有的 Direct3D 应用程序中

c# - 如何在WPF应用程序上修复 “The calling thread cannot access this object because a different thread owns it.”

c# - VB.NET 和 C# 之间的二进制移位差异

c# - 如何在轮盘赌中将球停在特定数字