Meg*_*ind 9 c# wpf ui-automation
我是NordVPN的用户并且没有任何问题地使用它.现在,对于某些要求,我需要设置一些属性,如协议(复选框)和单击其他应用程序中的按钮.
但该应用程序的该区域看起来像一个自定义控件,UIAutomation无法向下钻取.
该自定义控件中的元素没有任何自动化ID.
因此,我需要知道如何使用UIAutomation和White Framework遍历wpf应用程序中的用户控件,例如应用程序窗口的其他部分.
到目前为止我尝试过的是
使用TreeWalker(无法读取所有元素)
并尝试从其位置AutomationElement.FromPoint()获取元素,但它再次提供了我无法遍历的整个自定义控件(从其边界确定).
关于如何从UIAutomation钻取自定义控件的任何建议.
对于记录,snoop可以读取元素,但VisualUIAVerify.exe不是.
编辑 1 - 澄清: 对我来说,如果没有能力唯一地识别它们以实现自动化,则控件在自动化 API 中不可见。身份识别因素可以是姓名、身份证、兄弟姐妹或父母等任何内容。
正如预期的那样,自动化 ID 的缺失导致控件在 UI 自动化树 API 中不可见。
为了解决这个问题,并知道它们在 Snoop 应用程序中可见 - 您可以使用底层逻辑(Snoop 使用)以编程方式自动化这些控件。
下载SnoopUI 的二进制文件,并将它们添加到您的项目中。确保将编译选项保留为“无”并复制到输出目录。
下一步将添加一个辅助方法,在本例中,该方法使用这些二进制文件将带有自动化逻辑的 dll 注入到目标应用程序(即 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 + "\"");
    }
}
将自动化 dll 注入应用程序后,使用和进行访问Visual Tree非常简单。DispatcherPresentationSources
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;
        }
访问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;
}
一旦您有权访问控件,现在就可以直接操作它们的属性,或者访问它们相应的自动化对等点和提供程序来自动化这些控件。
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 存储库。
| 归档时间: | 
 | 
| 查看次数: | 762 次 | 
| 最近记录: |