使用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样式语法的应用程序中的控件。