如果SysListView32的当前视图状态不是LV_VIEW_DETAILS,则可能无法提供请求的信息,所以我们应该暂时(如果当前视图状态不同),使用其AutomationElement的MultipleViewPattern来验证视图状态并如有必要,使用MultipleViewPattern.SetCurrentView() 方法进行更改。
SetCurrentView() 方法使用 Win32 控件的相同值。
然后使用FindAll() 的AutomationElement 方法查找ControlType.DataItem 或ControlType.ListItem 类型的所有子元素(使用OrCondition)。
对于它们中的每一个,获取ControlType.Edit 和ControlType.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,请按标题内容、直接父级 ControlType 或 ClassName 或任何其他允许将其单独列出的内容进行过滤。
UI 自动化需要引用 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