使用C#和UI Automation来获取未知控件类型的内容

在下图中,有一个区域,其中包含一个未知(自定义)类。 这不是网格或表格。

在此处输入图像描述

我需要能够:

  • 选择此区域的行
  • 从每个单元格中获取值

问题是,因为这不是一个常见的类型元素 – 我不知道如何谷歌这个问题或自己解决它。 到目前为止,代码如下:

Process[] proc = Process.GetProcessesByName("programname"); AutomationElement window = AutomationElement.FromHandle(proc [0].MainWindowHandle); PropertyCondition xEllist2 = new PropertyCondition(AutomationElement.ClassNameProperty, "CustomListClass", PropertyConditionFlags.IgnoreCase); AutomationElement targetElement = window.FindFirst(TreeScope.Children, xEllist2); 

我已经尝试将此区域作为文本框,作为网格,作为combobox来威胁,但到目前为止还没有解决我的问题。 有没有人有任何建议如何从这个区域获取数据并迭代行?

编辑:抱歉,我做了一个错误的假设。 实际上,这个区域的标题(第1列,第2列,第3列)和“下半部分”是不同的控制类型 !!

感谢Wininspector,我能够挖掘有关这些控件类型的更多信息:

  • 标头具有以下属性:HeaderControl 0x056407DC(90441692)Atom:#43288 0xFFFFFFFF(-1)
  • 下半部分有:ListControl 0x056408A4(90441892)primefaces:#43288 0x02A6FDA0(44498336)

我之前展示的代码 – 仅检索“List”元素,所以这里是更新:

 Process[] proc = Process.GetProcessesByName("programname"); AutomationElement window = AutomationElement.FromHandle(proc [0].MainWindowHandle); //getting the header PropertyCondition xEllist3 = new PropertyCondition(AutomationElement.ClassNameProperty, "CustomHeaderClass", PropertyConditionFlags.IgnoreCase); AutomationElement headerEl = XElAE.FindFirst(TreeScope.Children, xEllist3); //getting the list PropertyCondition xEllist2 = new PropertyCondition(AutomationElement.ClassNameProperty, "CustomListClass", PropertyConditionFlags.IgnoreCase); AutomationElement targetElement = window.FindFirst(TreeScope.Children, xEllist2); 

在进一步思考后,我试图获得所有列名:

 AutomationElementCollection headerLines = headerEl.FindAll(TreeScope.Children, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.HeaderItem)); string headertest = headerLines[0].GetCurrentPropertyValue(AutomationElement.NameProperty) as string; textBox2.AppendText("Header 1: " + headertest + Environment.NewLine); 

不幸的是,在调试模式下,“headerLines”中的元素计数为0,因此程序会抛出错误。

编辑2:感谢下面的答案 – 我安装了非托管UI自动化,它比默认的UIA具有更好的可能性。 http://uiacomwrapper.codeplex.com/如何使用旧模式从未知控件类型中获取数据?

 if((bool)datagrid.GetCurrentPropertyValue(AutomationElementIdentifiers.IsLegacyIAccessiblePatternAvailableProperty)) { var pattern = ((LegacyIAccessiblePattern)datagrid.GetCurrentPattern(LegacyIAccessiblePattern.Pattern)); var state = pattern.Current.State; } 

编辑3. IUIA自动化方法(截至目前不工作)

  _automation = new CUIAutomation(); cacheRequest = _automation.CreateCacheRequest(); cacheRequest.AddPattern(UiaConstants.UIA_LegacyIAccessiblePatternId); cacheRequest.AddProperty(UiaConstants.UIA_LegacyIAccessibleNamePropertyId); cacheRequest.TreeFilter = _automation.ContentViewCondition; trueCondition = _automation.CreateTrueCondition(); Process[] ps = Process.GetProcessesByName("program"); IntPtr hwnd = ps[0].MainWindowHandle; IUIAutomationElement elementMailAppWindow = _automation.ElementFromHandle(hwnd); List ls = new List(); ls = GetChildWindows(hwnd); foreach (var child in ls) { IUIAutomationElement iuiae = _automation.ElementFromHandle(child); if (iuiae.CurrentClassName == "CustomListClass") { var outerArayOfStuff = iuiae.FindAllBuildCache(interop.UIAutomationCore.TreeScope.TreeScope_Children, trueCondition, cacheRequest.Clone()); var outerArayOfStuff2 = iuiae.FindAll(interop.UIAutomationCore.TreeScope.TreeScope_Children, trueCondition); var countOuter = outerArayOfStuff.Length; var countOuter2 = outerArayOfStuff2.Length; var uiAutomationElement = outerArayOfStuff.GetElement(0); // error var uiAutomationElement2 = outerArayOfStuff2.GetElement(0); // error //... //I've erased what's followed next because the code isn't working even now.. } } 

由于这个问题,代码已经实现:

使用C#从另一个应用程序的SysListView32中的数据网格中读取单元格项

作为结果:

  • countOuter和countOuter2个长度= 0
  • 无法选择元素(列表中的行)
  • 不可能获得任何价值
  • 什么都没有用

您可能想尝试使用核心UI自动化类。 它要求您导入dll以在C#中使用它。 将此添加到您的预构建事件(或只执行一次等):

 "%PROGRAMFILES%\Microsoft SDKs\Windows\v7.0A\bin\tlbimp.exe" %windir%\system32\UIAutomationCore.dll /out:..\interop.UIAutomationCore.dll" 

然后,您可以使用IUIAutomationLegacyIAccessiblePattern。

从以下位置获取调用所需的常量:

C:\ Program Files \ Microsoft SDKs \ Windows \ v7.1 \ Include \ UIAutomationClient.h

我可以通过这种方式阅读Infragistics Ultragrids。

如果这太痛苦了,请尝试使用MSAA。 在转换为所有UIA Core: MSSA示例代码之前,我使用此项目作为MSAA的起点

—–于6/25/12编辑——

我肯定会说找到合适的’标识符’是使用MS UIAutomation的最痛苦的部分。 对我有用的是创建一个简单的表单应用程序,我可以将其用作“位置记录器”。 基本上,您只需要两件事:

  • 即使您离开窗体的窗口也能保持焦点的方法保持焦点

  • 使用鼠标所在的x,y坐标调用ElementFromPoint()。 CUIAutomation类中有一个实现。

我使用CTRL按钮告诉我的应用程序抓取鼠标坐标(System.Windows.Forms.Cursor.Position)。 然后我从该点获取元素并递归获取元素的父级,直到我到达桌面。

  var desktop = auto.GetRootElement(); var walker = GetRawTreeWalker(); while (true) { element = walker.GetParentElement(element); if (auto.CompareElements(desktop, element) == 1){ break;} } 

—–编辑于6/26/12 —–

一旦你可以递归地找到自动化标识符和/或名称,你可以在这里轻松修改代码: http : //blog.functionalfun.net/2009/06/introduction-to-ui-automation-with.html与之一起使用核心UI自动化类。 这将允许您在递归时构建一个字符串,该字符串可用于标识嵌套在具有XPath样式语法的应用程序中的控件。