我试图从外部应用程序中抓取一个类似于控件的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或者类似于它,但是我不能用它做任何其他的事情。
现在我如何才能获得此控件的内容?
更新:
感谢Jimi的推荐,Windows10SDK中的inspect.exe工作得最好!我能够钻到DataGridView。
发布于 2020-10-16 16:01:15
我假设您可以找到包含从其中提取数据的DataGridView的窗口。GeDataGridViewDataTable()
方法需要该窗口的句柄。
让我们分解一下这些方法:
要获得感兴趣窗口的AutomationElement (当其句柄已知时),我们只需使用window =
AutomationElement.FromHandle([Window Handle])
即可。
这里我使用的是AndCodition,因为您可能有ProcessID和窗口标题,所以您可以使用AutomationElement.ProcessIdProperty
和AutomationElement.NameProperty
作为条件,而不是使用AutomationElement.ControlTypeProperty
和AutomationElement.NativeWindowHandleProperty
进行过滤。
如果找到该窗口,则解析TreeScope.SubTree
作用域中的第一个子元素(该窗口中的所有UI元素)以找到表类型的第一个元素(ControlType.Table)。
当然,该窗口可能承载多个DataGridView:在本例中,我们可以使用FindAll()
而不是FindFirst()
,然后确定使用其他条件(列数、标题文本、单元格内容、位置、大小、父容器等)是什么。
当发现感兴趣的DataGridView时,我们可以提取其细胞的内容。
接下来是第二个方法,GetDataGridViewRowsCollection()
Top Row
.然后,我们可以使用头文本来命名DataTable的列,这些列将存储提取的数据。否则,只需添加一些默认名称。ControlType.Header
,过滤器来排除行标头单元格(如果有的话)。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;
}
https://stackoverflow.com/questions/64388120
复制相似问题