簡體   English   中英

如何使用 UI 自動化從 ListView 或類似控件中獲取文本?

[英]How to get text out of a ListView or similar control using UI Automation?

我正在嘗試從外部應用程序中抓取類似 ListView 的控件。 現在我正在使用System.Windows.Automation 使用 AutoIt v3,我提取了有關我想從中抓取文本的確切控件的以下信息:

>>>> Control <<<<
Class:  WindowsForms10.Window.8.app.0.34f5582_r6_ad1
Instance:   20
ClassnameNN:    WindowsForms10.Window.8.app.0.34f5582_r6_ad120
Name:   
Advanced (Class):   [CLASS:WindowsForms10.Window.8.app.0.34f5582_r6_ad1; INSTANCE:20]
ID: 1510520
Text:   
Position:   182, 164
Size:   1411, 639
ControlClick Coords:    300, 202
Style:  0x56010000
ExStyle:    0x00000000
Handle: 0x0000000000170C78

現在,我注意到ID = 1510520並且通過使用它我將能夠獲得控制權

AutomationElement element = AutomationElement.FromHandle(1510520);

該控件看起來像一個 ListView 或類似的,但我不能用它做任何其他事情。

LisrView 類似控件

我現在如何獲取此控件的內容?

更新:
感謝 Jimi 的推薦,Windows 10 SDK 中的 inspect.exe 效果最好! 我能夠深入到 DataGridView。

在此處輸入圖片說明

我假設您可以找到包含從中提取數據的 DataGridView 的 Window。 GeDataGridViewDataTable()方法需要那個窗口的句柄。

讓我們分解這些方法:

要在其句柄已知時獲取感興趣的窗口的 AutomationElement,我們可以使用window = AutomationElement.FromHandle([Window Handle])

▶ 這里我使用AndCodition,因為您可能有 ProcessID 和 Window Title,因此您可以使用AutomationElement.ProcessIdPropertyAutomationElement.NameProperty作為條件,而不是使用AutomationElement.ControlTypePropertyAutomationElement.NativeWindowHandleProperty進行過濾。

如果找到 Window,則TreeScope.SubTree范圍中的第一個子元素(該窗口中的所有 UI 元素)將被解析以查找 Table ( ControlType.Table ) 類型的第一個元素。

▶ 當然,那個 Window 可能承載多個 DataGridView:在這種情況下,我們可以使用FindAll()而不是FindFirst() ,然后使用其他條件(列數,標題的文本,標題的內容FindFirst()確定哪個是哪個單元格、位置、大小、父容器等)。

當找到感興趣的 DataGridView 時,我們可以提取其 Cells 的內容。
這是第二種方法, GetDataGridViewRowsCollection()

  • 第一個OrCondition過濾掉 DataGridView 滾動條和網格的其他可能的子控件(自定義可能包括一些)。
  • 之后,我們檢查 DGV 是否有 Header:如果有,第一個子 Row 元素名稱是Top Row 然后,我們可以使用標題文本來命名將存儲提取的數據的 DataTable 的列。 否則,只需添加一些默認名稱。
  • 然后,對於每個 Row 元素,我們枚舉它的子元素,代表 Cells。 我添加了一個NotCondition過濾器來排除 Row Header Cell, ControlType.Header ,如果有的話。
  • 然后我們迭代 Cell 的集合,使用GetCurrentPropertyValue()方法提取它們的值,將 Property Type 設置為ValuePattern.ValueProperty ,將這些值添加到一個 List 中,該 List 將提供DataTable.Rows.Add()param數組參數。

private DataTable GeDataGridViewDataTable(IntPtr windowHwnd)
{
    var condition = new AndCondition(
        new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Window),
        new PropertyCondition(AutomationElement.NativeWindowHandleProperty, windowHwnd.ToInt32())
    );
    var window = AutomationElement.RootElement.FindFirst(TreeScope.Children, condition);
    if (window == null) return null;
    var dgv = window.FindFirst(TreeScope.Subtree, 
        new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Table));

    if (dgv == null) return null;
    var dt = GetDataGridViewRowsCollection(dgv);
    return dt;
}

private DataTable GetDataGridViewRowsCollection(AutomationElement dgv)
{
    var dt = new DataTable();

    // Skips ScrollBars and other child elements
    var condition = new OrCondition(
        new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Custom),
        new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Header)
    );

    var rows = dgv.FindAll(TreeScope.Children, condition).OfType<AutomationElement>().ToList();
    bool hasColumnHeader = (rows[0].Current.Name == "Top Row");

    // First element is the Header (if there's one)
    var dgvHeaderColumns = rows[0].FindAll(TreeScope.Children, Condition.TrueCondition);
        
    // Skip the Top/Left header
    for (int i = 1; i < dgvHeaderColumns.Count; i++) {
        dt.Columns.Add(hasColumnHeader ? dgvHeaderColumns[i].Current.Name : "Column"+i);
    }

    // Skips the Row Header, if any
    var notCondition = new NotCondition(new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Header));
    foreach (AutomationElement row in rows) {
        var cells = row.FindAll(TreeScope.Children, notCondition);
        var values = new List<object>();
        foreach (AutomationElement cell in cells) {
            values.Add(cell.GetCurrentPropertyValue(ValuePattern.ValueProperty));
        }
        dt.Rows.Add(values.ToArray());
    }
    return dt;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM