【问题标题】:UI Automation - Retrieving data from a SysListView32 (or any Listview)UI 自动化 - 从 SysListView32(或任何 Listview)中检索数据
【发布时间】:2020-07-28 23:39:09
【问题描述】:

我正在尝试使用下面的代码从 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

【问题讨论】:

    标签: vb.net listview ui-automation inspector automationelement


    【解决方案1】:

    如果SysListView32的当前视图状态不是LV_VIEW_DETAILS,则可能无法提供请求的信息,所以我们应该暂时(如果当前视图状态不同),使用其AutomationElement的MultipleViewPattern来验证视图状态并如有必要,使用MultipleViewPattern.SetCurrentView() 方法进行更改。

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

    然后使用FindAll() 的AutomationElement 方法查找ControlType.DataItemControlType.ListItem 类型的所有子元素(使用OrCondition)。

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

    使用项目的GridItemPattern 检索列表中每个项目的位置,以访问项目的Row 属性。

    最后,如果我们不得不改变它,我们会恢复之前的视图状态。


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

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

    如果您不需要 ListViewItem 对象,您可以只存储由 itemsText 对象表示的List(Of String),而不是在这里创建 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,请按标题内容、直接父级 ControlTypeClassName 或任何其他允许将其单独列出的内容进行过滤。

    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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-03-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-07
      • 1970-01-01
      • 2015-12-14
      相关资源
      最近更新 更多