使用C#和UI自动化抢未知控制型的内容(using C# and UI Automation to

2019-07-30 01:43发布

在图像下面有一个区域,其具有一个未知的(定制)类。 这不是一个网格或表。

我需要能够:

  • 在此区域内选择行
  • 抓住从每一个小区的值

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

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);

我已经试图威胁这个区域作为一个文本框,一个网格,作为一个组合框,但没有解决我的问题至今。 没有任何人有任何意见如何从这个区域中获取数据,并通过行迭代?

编辑:对不起,我犯了一个错误的假设。 实际上,报头(列1,列2,列3)和该区域的“下半部”是不同的控制类型 !!

由于Wininspector我能够挖掘有关这些控制类型的详细信息:

  • 报头具有以下性质:HeaderControl 0x056407DC(90441692)的Atom:#43288 0xFFFFFFFF的(-1)
  • 和下半部有以下:ListControl的0x056408A4(90441892)的Atom:#43288 0x02A6FDA0(44498336)

那我之前展示的代码 - 检索“列表”元素只,所以这里是更新:

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. IUIAutoamtion办法(非工作截至目前)

        _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<IntPtr> ls = new List<IntPtr>();

        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
  • 不可能选择元件(从列表中的行)
  • 不可能得到任何价值
  • 没有什么工作

Answer 1:

您可能需要使用核心UI自动化类尝试。 它要求你输入在C#中使用它的dll。 添加到您的预生成事件(或做它只有一次,等):

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

然后,您可以使用IUIAutomationLegacyIAccessiblePattern。

获取你需要从调用的常量:

C:\ Program Files文件\微软的SDK \的Windows \ V7.1 \包含\ UIAutomationClient.h

我能看懂的Infragistics Ultragrids这种方式。

如果这是太痛苦了,请尝试使用MSAA。 我用这个项目作为与MSAA起点转换成所有UIA核心之前: MSSA示例代码

-----编辑在12年6月25日------

我肯定会说,找到适当的“标识符”是使用MS UIAutomation东西最痛苦的部分。 什么帮助了我非常多的创建,我可以为“位置记录”用一个简单的表单应用程序。 从本质上讲,所有你需要的是两件事情:

  • 一种方法来保持专注,甚至,当你关闭你的窗体的窗口的控股焦点

  • 到ElementFromPoint()的调用使用x,y坐标,其中所述小鼠是。 有这样的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;}
        }

-----编辑于12年6月26日-----

一旦你可以递归找到自动化标识符和/或名称,可以比较容易地在这里修改代码: http://blog.functionalfun.net/2009/06/introduction-to-ui-automation-with.html要与使用核心UI自动化类。 这将允许你建立一个字符串,你递归可用于识别嵌套在使用XPath风格的语法的应用程序的控制。



文章来源: using C# and UI Automation to grab contents of unknown control-type