C# UI Automation调用FromPoint报未缓存属性/模式错误
代码疏漏点
- CacheRequest 作用域完全不匹配:
CacheRequest.Activate()仅对using块内部执行的UI自动化检索操作生效,原代码中激活缓存后仅执行了根元素下查找计算器窗口的FindFirst操作,后续调用FromPoint获取鼠标位置元素的逻辑完全在缓存激活上下文之外,拿到的元素没有任何预缓存内容。 - 缓存与目标对象无关联:原代码中通过
FindFirst拿到的计算器窗口对象elementList后续完全没有被使用,和FromPoint返回的元素是相互独立的两个实例,之前配置的缓存规则不会作用到FromPoint返回的对象上。 - 缓存范围配置错误:原代码设置的
TreeScope仅覆盖目标元素本身和直接子元素,就算缓存绑定到了计算器窗口,鼠标指向计算器内部深层控件(比如按钮、输入框)时,这些控件也不在缓存覆盖范围内,访问缓存属性依然会报错。 - 属性访问方式不匹配:如果拿到的是没有预缓存的普通AutomationElement对象,调用
Cached开头的属性/模式接口就会直接抛出题目中的错误,这类对象只能通过Current开头的接口直接读取实时属性。
修正方法
根据使用场景二选一即可:
- 无缓存模式(适合单次、低频查询场景,代码简单无额外配置):不需要提前配置任何CacheRequest,获取到AutomationElement后,统一通过
Current前缀的属性接口读取值即可,不会触发缓存相关报错。 - 缓存模式(适合高频、批量读取场景,减少跨进程UI通信开销,性能更好):在执行
FromPoint检索操作之前激活配置好的CacheRequest,让检索返回的元素直接携带预缓存的属性和模式,之后就可以正常通过Cached接口读取值。
修正后的可运行代码示例:
public static void GetElements(System.Drawing.Point pt) { AutomationElement targetElement; // 按需配置需要缓存的属性、控件模式 CacheRequest uiCache = new CacheRequest(); uiCache.Add(AutomationElement.NameProperty); uiCache.Add(AutomationElement.AutomationIdProperty); uiCache.Add(AutomationElement.ControlTypeProperty); uiCache.Add(AutomationElement.IsEnabledProperty); uiCache.Add(InvokePattern.Pattern); uiCache.Add(SelectionItemPattern.Pattern); // 配置缓存范围:仅缓存当前命中元素本身,需要缓存子元素可追加TreeScope.Children/TreeScope.Descendants uiCache.TreeScope = TreeScope.Element; // 在缓存激活上下文内执行FromPoint检索,返回的元素自带缓存 using (uiCache.Activate()) { System.Windows.Point hitPoint = new System.Windows.Point(pt.X, pt.Y); targetElement = AutomationElement.FromPoint(hitPoint); } // 此时读取Cached属性不会抛出异常 string eleName = targetElement.Cached.Name; ControlType eleType = targetElement.Cached.ControlType; bool eleEnabled = targetElement.Cached.IsEnabled; }
补充提示:如果系统开启了DPI缩放,
GetPhysicalCursorPos拿到的物理坐标需要做DPI换算,否则FromPoint可能命中错误的UI元素。不建议一次性缓存元素的全部属性,会带来不必要的性能开销,按需加入需要读取的属性即可。
内容的提问来源于stack exchange,提问作者Komal Chaudhary
相关产品推荐
相关产品推荐

