繁体   English   中英

WPF UIAutomation让孩子控制用户控制

[英]WPF UIAutomation Getting child control of user control

我是NordVPN的用户,使用它没有任何问题。 现在,对于某些要求,我需要设置一些属性,如协议(复选框)和单击其他应用程序中的按钮。

但该应用程序的该区域看起来像一个自定义控件,UIAutomation无法向下钻取。

该自定义控件中的元素没有任何自动化ID。

因此,我需要知道如何使用UIAutomation和White Framework遍历wpf应用程序中的用户控件,例如应用程序窗口的其他部分。

到目前为止我尝试过的是

  1. 使用TreeWalker(无法读取所有元素)

  2. 并尝试从其位置AutomationElement.FromPoint()获取元素,但它再次提供了我无法遍历的整个自定义控件(从其边界确定)。

关于如何从UIAutomation钻取自定义控件的任何建议。

在此输入图像描述

对于记录,snoop可以读取元素,但VisualUIAVerify.exe不是。

编辑1 - 澄清:对我来说,控制在自动化API中是不可见的 - 如果没有能力唯一地识别它们以自动化。 识别因子可以是name,id,sibling或parent之类的任何内容。


正如所料,缺少自动化ID导致控件在UI自动化树API中不可见。

为了解决这个问题,并且知道它们在Snoop应用程序中可见 - 您可以使用底层逻辑(Snoop使用)来以编程方式自动化这些控件。

脚步

  1. 下载SnoopUI二进制文件 ,并将它们添加到您的项目中。 确保将编译选项保持为“无”并将其复制到输出目录。

    在此输入图像描述

  2. 下一步将添加一个辅助方法,在这种情况下,使用这些二进制文件将自动化逻辑注入到目标应用程序(即NordVPN)中。 将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. 在应用程序中注入自动化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. 访问VisualTree很容易,但识别控件并不那么简单,因为没有可以唯一标识这些控件的自动化ID或名称。 但幸运的是,当他们使用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. 一旦您可以访问控件,现在可以直接操作其属性,或访问相应的自动化对等项,以及提供程序来自动执行这些控件。

     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(); } 

已在Github存储库上载了完整的工作示例。

在此输入图像描述

暂无
暂无

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

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