我正在开发一个监视给定应用程序的自动化事件的应用程序。目前,我正在研究我开发的WPF应用程序上的结构更改事件。
public void MonitorStructureChangedEvents(AutomationElement element)
{
Automation.AddStructureChangedEventHandler(element, TreeScope.Subtree, OnStructureChanged);
}
在这种情况下,element
是应用程序的根AutomationElement
(其主窗口)。有问题的WPF应用程序只是一个Window
,带有网格视图和各种控件(文本框,复选框,按钮等)。它是我专门为测试UIAutomation事件而开发的测试应用程序。
我正在使用单元测试项目来测试这些事件,我正在ClassInitialize
装饰方法中启动应用程序。在应用程序启动之前我没有注册StructureChanged
事件,而是通过我的TestMethod
中的WMI找到它。该应用程序作为一个新进程生成。
但是,在注册结构更改事件时,我会收到应用程序主窗口中所有元素的结构更改事件,即使WPF应用程序实际上是空闲的。我在主窗口中有按钮来添加和删除控件以测试StructureChanged
事件,它确实有效,但我不确定为什么当我最初注册时,所有元素都会触发一个结构更改事件。
编辑:进一步测试后,我注意到,只要点击应用程序窗口或将鼠标悬停在按钮上,就会触发这些事件。然后,它会为应用程序中的每个元素触发一次结构更改事件。完成后,如果我将鼠标悬停在某个按钮上,或者单击该应用程序(即使在点击其他应用程序或桌面后),它也不再触发结构更改事件
Edit2:经过进一步测试后,我相信我找出了问题的原因,但还没有解决方案。当我尝试TreeWalker.RawViewWalker.GetFirstChild(rootApplicationElement)
时,我收到一个空值。似乎我获得的AutomationElement
没有缓存的孩子。一旦我在元素上添加StructureChanged
事件处理程序,TreeWalker
方法就可以了,我得到一个有效的元素。看来,当我在此之后激活窗口时,就会意识到它现在拥有所有这些新的子元素。有没有办法缓存rootApplicationElement
的所有后代,以便在添加事件处理程序之前,我可以遍历整个子树?
答案 0 :(得分:0)
我能够使用以下方法解决问题
CacheRequest request = new CacheRequest();
request.TreeScope = TreeScope.Element | TreeScope.Descendants;
using (request.Activate())
{
rootApplicationElement = AutomationElement.RootElement.FindAll(TreeScope.Children,
new PropertyCondition(AutomationElementIdentifiers.ProcessIdProperty, ApplicationInstance.ProcessId))[0];
}
我不建议人们以这种方式获取根元素,因为如果应用程序有多个窗口,您将获得多个结果,但这是根据特定的测试需求量身定制的。