UI Automation - получение данных из SysListView32 (или любого ListView) - PullRequest
1 голос
/ 15 апреля 2020

Я пытаюсь получить данные из объекта SysListView32 с кодом ниже, но он возвращает пустую строку.

Элементы, которые мне нужно получить, выделены красным, а также другие элементы, содержащиеся в других элементах ControlType.ListItem, согласно печати инспектора.

Может кто-нибудь проверить, что не так с моим кодом?

Inspector

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

1 Ответ

1 голос
/ 16 апреля 2020

SysListView32 может не предоставлять запрашиваемую информацию, если его текущее состояние просмотра не LV_VIEW_DETAILS, поэтому мы должны временно (если текущее состояние просмотра отличается), использовать MultipleViewPattern его элемента AutomationElement для проверки состояния просмотра и изменения его при необходимости с использованием метода MultipleViewPattern.SetCurrentView () .

Метод SetCurrentView() использует те же значения элемента управления Win32.

Затем используйте метод AutomationElement FindAll () , чтобы найти все дочерние элементы типа ControlType.DataItem или ControlType.ListItem (используя OrCondition ).

Для каждого из них получить все дочерние элементы типа ControlType.Edit и ControlType.Text (используя другой OrCondition).

Положение каждого элемента в списке извлекается с использованием GridItemPattern элемента для доступа к свойству Row элемента.

Наконец, мы восстанавливаем предыдущее состояние просмотра, если нам нужно было его изменить.


Код в примере заполняет Dictionary(Of Integer, ListViewItem) (sysListViewItems), содержащий все элементы, извлеченные из SysListView32.

  • Целочисленный ключ представляет позицию элемента в исходном ListView
  • ListViewItem - это объект. Net, сгенерированный из массива значений (в виде строк), извлеченного из каждого вещь.

Если вам не нужны объекты ListViewItem, вы можете просто сохранить List(Of String), представленный объектом itemsText, вместо создания ListViewItem здесь:

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

Дескриптор SysListView32 также может быть получен путем перечисления дочерних элементов его окна верхнего уровня с помощью ClassName.
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, выполните фильтрацию по содержимому заголовка, прямому родительскому элементу ControlType или ClassName или чему-либо еще, что позволяет выделить его.

Для автоматизации пользовательского интерфейса требуется ссылка на сборки UIAutomationClient и UIAutomationTypes.


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
...