【问题标题】:UIAutomation Click button without making window take focus and GetCurrentPattern() returning unsupported patternUIAutomation 单击按钮而不使窗口获得焦点并且 GetCurrentPattern() 返回不支持的模式
【发布时间】:2014-03-10 01:30:48
【问题描述】:

我有一个窗口的句柄,我想做的是单击它的名为“加载设置”的按钮。我有 2 个问题。

  • 我的第一个问题是当我在某个 InvokePattern 上调用 Invoke 时,它​​会使窗口成为焦点,这对我的应用程序来说是不可取的。
  • 我的第二个问题是可见的,并记录在我的以下代码末尾的 cmets 中:

    AutomationElement aeBot = AutomationElement.FromHandle(mbotSettingList.ElementAt(i).getWindowHandle());
    AutomationElement aeButtonLoadSettings = aeBot.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.NameProperty, "Load Settings"));
    InvokePattern ipClickLoadSettings = (InvokePattern)aeButtonLoadSettings.GetCurrentPattern(InvokePattern.Pattern);
    Thread invokeLoadSettingsThread = new Thread(ipClickLoadSettings.Invoke);
    InvokePattern ipClickOpen = null;
    AutomationElement aeOpenDialogEdit = null;
    AutomationElement aeButtonOpen = null;
    AutomationElementCollection aeDialogs = null;
    AutomationElement aeOpenDialog = null;
    ValuePattern vpOpenDialogEdit = null;
    
    //Using a thread to invoke the Load Settings button click because as a result of clicking Load Settings a dialog is opened and invoke doesnt return for nealy 10 seconds
    invokeLoadSettingsThread.Start();
    //We probably wont join() this thread because it goes on for far longer than we expect to be in this function
    
    //Get a collection of the Dialog windows that are direct children of the main window we have a handle to
    aeDialogs = aeBot.FindAll(TreeScope.Children, new PropertyCondition(AutomationElement.ClassNameProperty, "#32770"));
    
    while (aeDialogs.Count == 0)
    {
        //This while loop is to continue to check for the Open file dialog as it may take a little time to open
        aeDialogs = aeBot.FindAll(TreeScope.Children, new PropertyCondition(AutomationElement.ClassNameProperty, "#32770"));
        Thread.Sleep(250);
    }
    
    for (int j = 0; j < aeDialogs.Count; j++)
    {
        //There is usually only 1 child dialog window, but just make sure we have the correct one
        if (aeDialogs[j].Current.Name == "Open")
        {
            Debug.WriteLine("Found open dialog!");
            aeOpenDialog = aeDialogs[j];
            break;
        }
    }
    
    //Inside the Open window, the first Edit window is the one where the file name/path should be entered
    aeOpenDialogEdit = aeOpenDialog.FindFirst(TreeScope.Descendants, new PropertyCondition(AutomationElement.ClassNameProperty, "Edit"));
    
    //Set the value of the file name/path to the string variable "loadSettingsString"
    vpOpenDialogEdit = (ValuePattern)aeOpenDialogEdit.GetCurrentPattern(ValuePattern.Pattern); 
    vpOpenDialogEdit.SetValue(loadSettingsString);
    
    //******************************************PROBLEM BEGINING BELOW******************************************
    
    //Using multiple methods, we can successfully get a successful AutomationElement for the "Open" button in the Open file dialog
    aeButtonOpen = aeOpenDialog.FindFirst(TreeScope.Subtree, new PropertyCondition(AutomationElement.NameProperty, "Open"));
    
    //aeButtonOpen = aeOpenDialog.FindFirst(TreeScope.Subtree, new PropertyCondition(AutomationElement.NameProperty, "Cancel"));
    //Something to consider: If we assigned aeButtonOpen to the AutomationElement we find be looking for "Cancel" rather than "Open"
    
    Debug.WriteLine(aeButtonOpen.Current.Name + " button found!");
    //Prints "Open button found!"
    //If aeButtonOpen were assigned to "Cancel", this would print "Cancel button found!"
    
    ipClickOpen = (InvokePattern)aeButtonOpen.GetCurrentPattern(InvokePattern.Pattern);
    //GetCurrentPattern has returned null
    //If aeButtonOpen were assigned to "Cancel", this would NOT be null
    
    ipClickOpen.Invoke();
    //Invoke() on a null results in "Unsupported Pattern" exception
    //If aeButtonOpen were assigned to "Cancel", this would work and the Open file dialog would then be exited just as if cancel were clicked
    

【问题讨论】:

  • 可能的问题是我现在看到“打开”按钮实际上是一个拆分按钮,如果确实如此,我不确定这对我的问题有何影响。
  • 您确实需要使用 UIA 验证来查看您要查找的元素。 msdn.microsoft.com/en-us/library/ms742545(v=vs.110).aspx 详细说明了拆分按钮在树中的外观。您可能需要选择菜单项(请参阅 SelectionItem 模式),然后在按钮元素上使用 Invoke 模式。

标签: c# .net ui-automation openfiledialog microsoft-ui-automation


【解决方案1】:

使用UIAVerify 查看应用程序的 UIA 树。查看您的代码,我怀疑您没有检索您认为的元素。如果 'Open' 元素是一个按钮,它应该支持 Invoke 模式。

或者,您正在打开一个对话框,然后立即搜索该对话框的子元素。您可能会在此处遇到可靠性问题,其中仍在为该对话框创建 UIA 树。要检查这一点,请添加一秒钟的睡眠时间,看看是否能解决您的问题。如果是这种情况,请查看 UIA 结构更改事件。这些事件将让您根据 UIA 树中的更改同步您的 UIA 测试代码。

【讨论】:

  • 至于你的问题:焦点。除非您定义自己的 Accessible Peer 并实现它的调用模式,否则无法防止设置焦点,这样您就不会在调用 Invoke 时设置焦点。我建议在调用调用之前找到任何具有焦点的元素,并在调用调用后再次赋予它焦点。如果您能告诉我为什么不希望被测应用程序获得焦点,我可能会想出一个更好的主意。
  • 不希望被测应用程序获得焦点的目的是该应用程序的典型用户将在某个游戏中处于全屏模式,并且一旦他们按下某个键盘击键该应用程序我正在创建应该去“点击”另一个“正在测试”的应用程序上的某些按钮。
  • 这个其他应用程序是干什么用的?保存游戏回放?
  • 它控制游戏中的角色,它是一个机器人。
猜你喜欢
  • 1970-01-01
  • 2012-07-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多