簡體   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