UI 自动化 - 从 SysListView32(或任何列表视图)检索数据

UI Automation - Retrieving data from a SysListView32 (or any Listview)

我正在尝试使用以下代码从 SysListView32 对象中检索数据,但返回的是空字符串。

根据 Inspector 的打印,我需要检索的元素是那些以红色突出显示的元素,以及包含在其他 ControlType.ListItem 元素中的其他元素。

有人可以检查一下我的代码有什么问题吗?

Msgbox("Position the mouse cursor on the screen and press ENTER.")

Dim pt As POINTAPI
GetCursorPos(pt)

Dim hwnd As IntPtr = WindowFromPoint(pt)

Dim hwnd As IntPtr = 67202
Dim el As AutomationElement = AutomationElement.FromHandle(hwnd)
Dim walker As TreeWalker = TreeWalker.ContentViewWalker
Dim i As Integer = 0
Dim child As AutomationElement = walker.GetFirstChild(el)

While child IsNot Nothing
    '
    Dim k As Integer = 0
    Dim child2 As AutomationElement = walker.GetFirstChild(child)

    While child2 IsNot Nothing
        Console.WriteLine(child2.Current.ToString)
        child2 = walker.GetNextSibling(child2)
    End While

    child = walker.GetNextSibling(child)
End While

如果 SysListView32 的当前视图状态不是 LV_VIEW_DETAILS, so we should temporarily (if the current view state is different), use the MultipleViewPattern of its AutomationElement to verify the view state and change it if necessary using the MultipleViewPattern.SetCurrentView() 方法,则它可能无法提供请求的信息。

SetCurrentView() 方法使用与 Win32 控件相同的值。

然后使用 AutomationElement FindAll() method of the to find all child elements of type ControlType.DataItem or ControlType.ListItem (using an OrCondition)。

对于它们中的每一个,获取类型为 ControlType.EditControlType.Text 的所有 child 项(使用另一个 OrCondition)。

使用项目的 GridItemPattern, to access the Item's Row 属性 检索列表中每个项目的位置。

最后,如果必须更改它,我们将恢复以前的视图状态。


例子中的代码,填充了一个Dictionary(Of Integer, ListViewItem)(sysListViewItems),包含了所有的Items从 SysListView32 中提取。

  • Integer Key表示一个Item在原始ListView中的位置
  • ListViewItem 是一个 .Net object 从每个项目中提取的值数组(作为字符串)生成的。

如果不需要ListViewItem objects,可以只存储List(Of String),用itemsText表示object,而不是在此处创建 ListViewItem:

sysListViewItems.Add(gridPattern.Current.Row, New ListViewItem(itemsText.ToArray())).  

SysListView32 的句柄也可以通过 ClassName.
枚举其顶级 Window 的 children 获得 AutomationElement.RootElement 提供当前桌面元素:

Dim parentWindow = AutomationElement.RootElement.FindFirst(
    TreeScope.Children, New PropertyCondition(AutomationElement.NameProperty, "[Window Caption]"))
Dim sysListView32 = parentWindow.FindAll(
    TreeScope.Subtree, New PropertyCondition(AutomationElement.ClassNameProperty, "SysListView32"))

如果发现多个SysListView32,按Header内容过滤,直接parentControlTypeClassName或任何其他允许挑出的内容。

UI 自动化需要引用 UIAutomationClientUIAutomationTypes 程序集。


Imports System.Windows.Automation

Dim sysListViewHandle = [GetSysListView32Handle()]

Dim sysListViewElement = AutomationElement.FromHandle(sysListViewHandle)
If sysListViewElement Is Nothing Then Return

Dim sysListViewItems = New Dictionary(Of Integer, ListViewItem)()
Dim mulView As MultipleViewPattern = Nothing
Dim pattern As Object = Nothing
Dim currentView As Integer = -1

If sysListViewElement.TryGetCurrentPattern(MultipleViewPattern.Pattern, pattern) Then
    mulView = DirectCast(pattern, MultipleViewPattern)
    currentView = mulView.Current.CurrentView
    If currentView <> ListViewWState.LV_VIEW_DETAILS Then
        mulView.SetCurrentView(ListViewWState.LV_VIEW_DETAILS)
    End If
End If

Dim childItemsCondition = New OrCondition(
    New PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.DataItem),
    New PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.ListItem))

Dim childItems = sysListViewElement.FindAll(TreeScope.Children, childItemsCondition)
If childItems.Count = 0 Then Return

Dim subItemsCondition = New OrCondition(
    New PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Edit),
    New PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Text))

For Each item As AutomationElement In childItems
    Dim itemsText = New List(Of String)()
    Dim subItems = item.FindAll(TreeScope.Children, subItemsCondition)
    For Each subItem As AutomationElement In subItems
        itemsText.Add(subItem.Current.Name)
    Next
    Dim gridPattern = DirectCast(subItems(0).GetCurrentPattern(GridItemPattern.Pattern), GridItemPattern)
    sysListViewItems.Add(gridPattern.Current.Row, New ListViewItem(itemsText.ToArray()))
Next

If mulView IsNot Nothing Then
    mulView.SetCurrentView(currentView)
End If

Friend Enum ListViewWState
    LV_VIEW_ICON = &H0
    LV_VIEW_DETAILS = &H1
    LV_VIEW_SMALLICON = &H2
    LV_VIEW_LIST = &H3
    LV_VIEW_TILE = &H4
End Enum