简体   繁体   English

WPF UIAutomation让孩子控制用户控制

[英]WPF UIAutomation Getting child control of user control

I am a user of NordVPN and using it without any issue. 我是NordVPN的用户,使用它没有任何问题。 Now for some requirements I need to set some of its properties like protocol (checkbox) and clicking on buttons from some other application. 现在,对于某些要求,我需要设置一些属性,如协议(复选框)和单击其他应用程序中的按钮。

But that area of the application looks like a custom control and UIAutomation is not able to drill down into it. 但该应用程序的该区域看起来像一个自定义控件,UIAutomation无法向下钻取。

Elements inside that custom control does not have any automation id. 该自定义控件中的元素没有任何自动化ID。

So I need to know how we could traverse through user controls in wpf applications like other parts of application window using UIAutomation and White Framework. 因此,我需要知道如何使用UIAutomation和White Framework遍历wpf应用程序中的用户控件,例如应用程序窗口的其他部分。

What I have tried so far is 到目前为止我尝试过的是

  1. using TreeWalker (not able to read all elements) 使用TreeWalker(无法读取所有元素)

  2. And try to get the element from its location AutomationElement.FromPoint(), but it gives the whole custom control (determine from its bounds) again on which I can't traverse yet. 并尝试从其位置AutomationElement.FromPoint()获取元素,但它再次提供了我无法遍历的整个自定义控件(从其边界确定)。

Any suggestion on how could I drill into custom control from UIAutomation. 关于如何从UIAutomation钻取自定义控件的任何建议。

在此输入图像描述

For the record, snoop can read the elements but VisualUIAVerify.exe is not. 对于记录,snoop可以读取元素,但VisualUIAVerify.exe不是。

EDIT 1 - Clarification: For me a control is not visible in automation API - if there is no ability to uniquely identify them to automate on. 编辑1 - 澄清:对我来说,控制在自动化API中是不可见的 - 如果没有能力唯一地识别它们以自动化。 The identification factor can be anything from name, id, sibling, or parent. 识别因子可以是name,id,sibling或parent之类的任何内容。


As expected, the absence of automation-ids have resulted in the controls to be not visible in UI Automation tree APIs. 正如所料,缺少自动化ID导致控件在UI自动化树API中不可见。

In order to work around that, and knowing that they are visible in Snoop application - you can use the underlying logic (that Snoop uses) to programmitically automate these controls. 为了解决这个问题,并且知道它们在Snoop应用程序中可见 - 您可以使用底层逻辑(Snoop使用)来以编程方式自动化这些控件。

Steps 脚步

  1. Download the binaries for SnoopUI , and add them to your project. 下载SnoopUI二进制文件 ,并将它们添加到您的项目中。 Make sure to keep the compile option as 'None' and are copied to output directory. 确保将编译选项保持为“无”并将其复制到输出目录。

    在此输入图像描述

  2. Next step would be add a helper method, that uses these binaries to inject your dll with automation logic into target application (which is NordVPN) in this case. 下一步将添加一个辅助方法,在这种情况下,使用这些二进制文件将自动化逻辑注入到目标应用程序(即NordVPN)中。 Once the dll is injected into target process, the ManagedInjector also invokes the method that is sent as parameter. 将dll注入目标进程后, ManagedInjector还会调用作为参数发送的方法。

     public class Helper { public static void Inject(IntPtr windowHandle, Assembly assembly, string className, string methodName) { var location = Assembly.GetEntryAssembly().Location; var directory = Path.GetDirectoryName(location); var file = Path.Combine(directory, "HelperDlls", "ManagedInjectorLauncher" + "64-4.0" + ".exe"); Debug.WriteLine(file + " " + windowHandle + " \\"" + assembly.Location + "\\" \\"" + className + "\\" \\"" + methodName + "\\""); Process.Start(file, windowHandle + " \\"" + assembly.Location + "\\" \\"" + className + "\\" \\"" + methodName + "\\""); } } 
  3. After the automation dll is injected in the application, the access to Visual Tree is pretty simple using Dispatcher and PresentationSources . 在应用程序中注入自动化dll后,使用DispatcherPresentationSources访问Visual Tree非常简单。

     public class Setup { public static bool Start() { Dispatcher dispatcher; if (Application.Current == null) dispatcher = Dispatcher.CurrentDispatcher; else dispatcher = Application.Current.Dispatcher; dispatcher.Invoke(AutomateApp); return true; } public static void AutomateApp() { Window root = null; foreach (PresentationSource presentationSource in PresentationSource.CurrentSources) { root = presentationSource.RootVisual as Window; if (root == null) continue; if ("NordVPN ".Equals(root.Title)) break; } 
  4. Getting access to VisualTree is easy, but identifying the controls is not that simple, as there are no automation-id(s), or name(s) that can uniquely identify these controls. 访问VisualTree很容易,但识别控件并不那么简单,因为没有可以唯一标识这些控件的自动化ID或名称。 But fortunately, as they are using MVVM, it is possible to identify them using the binding(s) attached with them. 但幸运的是,当他们使用MVVM时,可以使用附加的绑定来识别它们。

     public static T GetChildWithPath<T>(this DependencyObject depObj, DependencyProperty property = null, string pathName = null) where T : DependencyObject { T toReturn = null; for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++) { var child = VisualTreeHelper.GetChild(depObj, i); bool pathNameMatch = (child is T) && child.IsPathNameMatch<T>(property, pathName); if (pathNameMatch) { toReturn = child as T; break; } else toReturn = GetChildWithPath<T>(child, property, pathName); if (toReturn != null) break; } return toReturn; } 
  5. Once you have access to the controls, it is now possible to either manipulate their properties directly, or access their corresponding automation peers, and providers to automate these controls. 一旦您可以访问控件,现在可以直接操作其属性,或访问相应的自动化对等项,以及提供程序来自动执行这些控件。

     var checkBoxNames = new[] { "CyberSec", "AutomaticUpdates", "AutoConnect", "StartOnStartup", "KillSwitch", "ShowNotifications", "StartMinimized", "ShowServerList", "ShowMap", "UseCustomDns", "ObfuscatedServersOnly" }; foreach(var path in checkBoxNames) { var chkBox = settingsView.GetChildWithPath<CheckBox>(CheckBox.IsCheckedProperty, path); if(chkBox != null && chkBox.IsEnabled) chkBox.SimulateClick(); } 

A complete working sample has been uploaded at Github repository . 已在Github存储库上载了完整的工作示例。

在此输入图像描述

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM