如何强制刷新UI自动化树?Chrome自动化元素识别问题求助
先梳理下你的问题:调用AutomationElement.FindAll(TreeScope.Children, Condition.TrueCondition)获取Chrome节点的子元素时始终返回0,但这些元素在inspect.exe里清晰可见,刷新inspect后程序又能正常获取到。你尝试了通过SystemParametersInfo设置屏幕阅读器状态的方案,但没有任何效果。
为什么你当前的方案无效?
SPI_SETSCREENREADER这个API是用来通知系统屏幕阅读器状态变化的,早期Chrome会根据这个状态决定是否完整暴露accessibility树。但现在Chrome的无障碍逻辑已经更新,单纯设置这个参数可能无法触发Chrome的自动化树更新——而且你只设置了开启状态,没有先关闭再切换,Chrome可能根本没检测到状态变化。另外,这个API是系统级的,无法精准针对Chrome触发刷新。
更有效的解决办法
1. 强制Chrome开启无障碍渲染模式
启动Chrome时添加命令行参数--force-renderer-accessibility,这个参数会强制Chrome在启动时就完整构建并暴露accessibility树,从根源上避免元素无法被Automation获取的问题。
你可以这样启动Chrome:
Process.Start(@"C:\Program Files\Google\Chrome\Application\chrome.exe", "--force-renderer-accessibility");
2. 刷新目标Automation元素
在调用FindAll之前,先调用目标元素的Refresh()方法,强制刷新其自动化树:
targetElement.Refresh(); var children = targetElement.FindAll(TreeScope.Children, Condition.TrueCondition);
3. 等待元素加载或重试查询
Chrome的UI元素加载是异步的,可能你查询的时候元素还没被添加到自动化树里。可以添加等待逻辑,或者重试几次:
AutomationElementCollection GetChildrenWithRetry(AutomationElement element, int retryCount = 3) { for (int i = 0; i < retryCount; i++) { element.Refresh(); var children = element.FindAll(TreeScope.Children, Condition.TrueCondition); if (children.Count > 0) return children; Thread.Sleep(500); // 等待500ms再重试 } return element.FindAll(TreeScope.Children, Condition.TrueCondition); }
4. 发送WM_CHANGEUISTATE消息触发Chrome更新
给Chrome的主窗口发送WM_CHANGEUISTATE消息,强制它更新UI状态和自动化树:
首先添加DllImport:
[DllImport("user32.dll", CharSet = CharSet.Auto)] static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, uint wParam, uint lParam); const uint WM_CHANGEUISTATE = 0x0127; const uint UIS_INITIALIZE = 0x0000;
然后获取Chrome窗口句柄并发送消息:
// 假设你已经获取到Chrome主窗口的AutomationElement IntPtr chromeHwnd = new IntPtr((int)chromeMainElement.Current.NativeWindowHandle); SendMessage(chromeHwnd, WM_CHANGEUISTATE, UIS_INITIALIZE, 0); // 等待片刻后再查询 Thread.Sleep(200); var children = targetElement.FindAll(TreeScope.Children, Condition.TrueCondition);
5. 检查TreeScope的范围
有时候元素不是直接的子节点(TreeScope.Children),而是更深层级的后代节点,尝试用TreeScope.Descendants代替:
var descendants = targetElement.FindAll(TreeScope.Descendants, Condition.TrueCondition);
总结
最可靠的方案是启动Chrome时添加--force-renderer-accessibility参数,确保自动化树完整构建。如果无法修改Chrome的启动参数,可以结合Refresh()方法和重试逻辑,或者发送WM_CHANGEUISTATE消息触发刷新。
内容的提问来源于stack exchange,提问作者Christoph Bruns

