注册UIAutomation结构更改事件

时间:2015-02-13 21:54:08

标签: c# wpf events

我正在开发一个监视给定应用程序的自动化事件的应用程序。目前,我正在研究我开发的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的所有后代,以便在添加事件处理程序之前,我可以遍历整个子树?

1 个答案:

答案 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];
}

我不建议人们以这种方式获取根元素,因为如果应用程序有多个窗口,您将获得多个结果,但这是根据特定的测试需求量身定制的。