【问题标题】:selecting combobox item using ui automation使用 ui 自动化选择组合框项目
【发布时间】:2025-11-29 01:55:01
【问题描述】:

如何选择 ComboBox 的 SelectedIndex = -1?

我写了一个代码来自动化测试:

AutomationElement aeBuildMachine = null;
int count = 0;
do
{
    Console.WriteLine("\nLooking for Build Machine Combo Box");
    aeBuildMachine = aeTabitemmain.FindFirst(TreeScope.Descendants, new PropertyCondition(AutomationElement.ClassNameProperty, "ListBoxItem"));
    if (aeBuildMachine == null)
          throw new Exception("No Build Machine Combo Box");
    else
          Console.WriteLine("Found Build Machine Combo Box");
    ++count;
 }
while (aeBuildMachine == null && count < 50);

Console.WriteLine("Selecting Build machine from combobox...");
SelectionItemPattern spBuildmachine = (SelectionItemPattern)aeBuildMachine.GetCurrentPattern(SelectionItemPattern.Pattern);

如何使用这个SelectionItemPattern

【问题讨论】:

    标签: c# wpf


    【解决方案1】:

    这比它需要的复杂程度大约 100 倍,但我终于让它工作了。 WPF ComboBox 的一个大问题是,就自动化而言,它似乎没有任何 ListItem直到 ComboBox 展开

    下面的代码使用 ExpandCollapse 模式暂时下拉列表然后折叠它,然后它可以使用 ComboBox 上的 FindFirst 来获取要选择的 ListItem,然后使用 SelectionItem 模式来选择它。

    对于原始问题,选择 -1 表示未选择任何项目。对此没有任何方法,但您可以简单地使用 FindAll 获取 ListItems 的集合,依次获取每个 ListItems 的 SelectionItem 模式并调用其 RemoveFromSelection 方法。

        public static void SetSelectedComboBoxItem(AutomationElement comboBox, string item)
        {
            AutomationPattern automationPatternFromElement = GetSpecifiedPattern(comboBox, "ExpandCollapsePatternIdentifiers.Pattern");
    
            ExpandCollapsePattern expandCollapsePattern = comboBox.GetCurrentPattern(automationPatternFromElement) as ExpandCollapsePattern;
    
            expandCollapsePattern.Expand();
            expandCollapsePattern.Collapse();
    
            AutomationElement listItem = comboBox.FindFirst(TreeScope.Subtree, new PropertyCondition(AutomationElement.NameProperty, item));
    
            automationPatternFromElement = GetSpecifiedPattern(listItem, "SelectionItemPatternIdentifiers.Pattern");
    
            SelectionItemPattern selectionItemPattern = listItem.GetCurrentPattern(automationPatternFromElement) as SelectionItemPattern;
    
            selectionItemPattern.Select();
        }
    
        private static AutomationPattern GetSpecifiedPattern(AutomationElement element, string patternName)
        {
            AutomationPattern[] supportedPattern = element.GetSupportedPatterns();
    
            foreach (AutomationPattern pattern in supportedPattern)
            {
                if (pattern.ProgrammaticName == patternName)
                    return pattern;
            }
    
            return null;
        }
    

    【讨论】:

      【解决方案2】:

      我想我会分享这个作为从 ComboBox 或其他项目容器中选择任何项目的简单方法:

      protected AutomationElement GetItem(AutomationElement element, string item)
          {
              AutomationElement elementList;
              CacheRequest cacheRequest = new CacheRequest();
              cacheRequest.Add(AutomationElement.NameProperty);
              cacheRequest.TreeScope = TreeScope.Element | TreeScope.Children;
      
              elementList = element.GetUpdatedCache(cacheRequest);
      
              foreach (AutomationElement child in elementList.CachedChildren)
                  if (child.Cached.Name == item)
                      return child;
      
              return null;
          }
      

      element 是 ComboBox 或 item 容器,item 是容器中 item 的字符串名称或字面值。获得项目后,您可以执行以下操作来选择它:

      protected void Select(AutomationElement element)
          {
              SelectionItemPattern select = (SelectionItemPattern)element.GetCurrentPattern(SelectionItemPattern.Pattern);
              select.Select();
          }
      

      希望这对其他人有所帮助。我从有关自动化的 MSDN 文档中派生出这种模式,可在此处找到:

      MSDN - Automation and Cached Children

      【讨论】:

      • 不知道为什么,但是对于我的项目,如果 select 是当前选择的元素,select.Select() 会抛出异常。 - Win32 目标,如果有影响的话
      • 使用缓存请求让事情变得复杂。
      【解决方案3】:

      这对我有用。

          /// <summary>
          /// Extension method to select item from comboxbox
          /// </summary>
          /// <param name="comboBox">Combobox Element</param>
          /// <param name="item">Item to select</param>
          /// <returns></returns>
          public static bool SelectComboboxItem(this AutomationElement comboBox, string item)
          {
              if (comboBox == null) return false;
              // Get the list box within the combobox
              AutomationElement listBox = comboBox.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.List));
              if (listBox == null) return false;
              // Search for item within the listbox
              AutomationElement listItem = listBox.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.NameProperty, item));
              if (listItem == null) return false;
              // Check if listbox item has SelectionItemPattern
              object objPattern;
              if (true == listItem.TryGetCurrentPattern(SelectionItemPatternIdentifiers.Pattern, out objPattern))
              {
                  SelectionItemPattern selectionItemPattern = objPattern as SelectionItemPattern;
                  selectionItemPattern.Select(); // Invoke Selection
                  return true;
              }
              return false;
          }
      

      用法

              AutomationElement paymentCombobox = element.FindFirst(
                  TreeScope.Children,
                  new PropertyCondition(AutomationElement.NameProperty, "cbPayment")
              );
              paymentCombobox.SelectComboboxItem("Cash");
      

      资源https://msdn.microsoft.com/en-us/library/ms752305(v=vs.110).aspx

      【讨论】:

      • 你能在代码中留下一些cmets来描述你的代码是做什么的吗?
      • SelectComboboxItem 扩展方法必须在静态类中才能工作
      【解决方案4】:

      http://msdn.microsoft.com/de-de/library/system.windows.automation.selectionitempattern_members(v=VS.85).aspx

      这就是我所理解的问题的答案。

      但是..这真的是你的问题吗?

      无论如何,您可以从一个选择中添加或删除 SelectableItems - 我想 - 属于其父项,其他一些事情也是如此,例如检查它们是否被选中。

      【讨论】:

      【解决方案5】:

      我认为这对于简单的通用 ComobBox 值设置器来说可能是最简单的方法,只要 ComboBox 中的列表项没有重复项,这种方法就可以了。

      private void SetCombobValueByUIA( AutomationElement ctrl, string newValue )
      { 
          ExpandCollapsePattern exPat = ctrl.GetCurrentPattern(ExpandCollapsePattern.Pattern) 
                                                                    as ExpandCollapsePattern;
      
          if( exPat== null )
          {
              throw new ApplicationException( "Bad Control type..." );
          }
      
          exPat.Expand();
      
          AutomationElement itemToSelect = ctrl.FindFirst(TreeScope.Descendants, new
                                PropertyCondition(AutomationElement.NameProperty,newValue));
      
          SelectionItemPattern sPat = itemToSelect.GetCurrentPattern(
                                                    SelectionItemPattern.Pattern)  as SelectionItemPattern ; 
          sPat. Select();
      }
      

      【讨论】:

        【解决方案6】:

        没有大的变化,但只有少数需要注意,

        1. 无需使用折叠模式,调用 expand 即可解决问题。
        2. 使用 treescope.subtree 对我有用,而不是对孩子有用。

        代码示例是这样的,

        public static void SelectValueInComboBox(string comboBox, string value)
        {
            var comboBoxElement = HelperMethods.FindElementFromAutomationID(comboBox);
            if (comboBoxElement == null)
                throw new Exception("Combo Box not found");
        
            ExpandCollapsePattern expandPattern = (ExpandCollapsePattern)comboBoxElement.GetCurrentPattern(ExpandCollapsePattern.Pattern);
        
            AutomationElement comboboxItem = comboBoxElement.FindFirst(TreeScope.Subtree, new PropertyCondition(AutomationElement.NameProperty, value));
        
            SelectionItemPattern selectPattern = (SelectionItemPattern)comboboxItem.GetCurrentPattern(SelectionItemPattern.Pattern);
            selectPattern.Select();
        }
        

        【讨论】:

          【解决方案7】:

          对我来说,gotmug 的回答要求激活 CacheRequest。我将其作为扩展方法实现

           public static bool SelectDropDownItem(this AutomationElement comboBoxElement, string item)
                  {
                      bool itemFound = false;
                      AutomationElement elementList;
                      CacheRequest cacheRequest = new CacheRequest();
                      cacheRequest.Add(AutomationElement.NameProperty);
                      cacheRequest.TreeScope = TreeScope.Element | TreeScope.Children;
          
                      using (cacheRequest.Activate())
                      {
                          // Load the list element and cache the specified properties for its descendants.
                          Condition cond = new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.List);
                          elementList = comboBoxElement.FindFirst(TreeScope.Children, cond);
                      }
          
                      //Loop thru and find the actual ListItem
                      foreach (AutomationElement child in elementList.CachedChildren)
                          if (child.Cached.Name == item)
                          {
                              SelectionItemPattern select = (SelectionItemPattern)child.GetCurrentPattern(SelectionItemPattern.Pattern);
                              select.Select();
                              itemFound = true;
                              break;
                          }
                      return itemFound;
                  }
          

          【讨论】:

            【解决方案8】:
            <pre>
              public static void SetComboBox(AutomationElement ComboxBox, string SelectedValue)
                    {
                        AutomationElement ListBox = ComboxBox.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.AutomationIdProperty, "ListBox"));
                        AutomationElement SelectedItem = ListBox.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.NameProperty, SelectedValue));
                        ((SelectionItemPattern)SelectedItem.GetCurrentPattern(SelectionItemPattern.Pattern)).Select();
                    }
            

            使用说明: 1)复制并粘贴到实用程序类 2) 找到你的 ComboBox AutomationElement 3) Utility.SetCombox(ComboxAutomationElement, "SelectedText")

            理解:

            ComboBox的树形结构如下:

            ComboBox->ListBox(children)->ListItems(children)【每个combobox都有一个ListBox作为children,ListBox有所有ListItems作为children】。

            每个ListItem都有SelectedItemPattern,调用你想选择的。

            后来我发现“Shaz”的编码更好,我将他评为最佳编码。

            ** 注释:要进行 UIAAutomation,您必须将应用程序的 AutomationElements 映射到 TreeView,这使一切变得简单易懂。

            【讨论】:

              【解决方案9】:

              我在 WindowsForms comboBox

              中使用了这段代码

              用法

              comboBox.SetSelectedComboBoxItem("ValueYouWantToSelect");
              

              将此Class 添加到您的项目中:

              public static class AutomationElementExtensions
                  { 
                      public static void InvokeControl(this AutomationElement element)
                      {
                          InvokePattern invokePattern = null;
              
                          try
                          {
                              invokePattern =
                                  element.GetCurrentPattern(InvokePattern.Pattern)
                                  as InvokePattern;
                          }
                          catch (ElementNotEnabledException)
                          {
                              // Object is not enabled
                              return;
                          }
                          catch (InvalidOperationException)
                          {
                              // object doesn't support the InvokePattern control pattern
                              return;
                          }
              
                          invokePattern.Invoke();
                          Thread.Sleep(500);
                      } 
              
              
                      public static void SetSelectedComboBoxItem(this AutomationElement comboBox, string item)
                      {
                          AutomationPattern automationPatternFromElement = GetSpecifiedPattern(comboBox, "ExpandCollapsePatternIdentifiers.Pattern");
              
                          ExpandCollapsePattern expandCollapsePattern = comboBox.GetCurrentPattern(automationPatternFromElement) as ExpandCollapsePattern;
              
                          expandCollapsePattern.Expand();
              
              
              
                          AutomationElement listItem = comboBox.FindFirst(TreeScope.Subtree, new PropertyCondition(AutomationElement.NameProperty, item));
              
                          InvokeControl(listItem); 
                      }
              
                      private static AutomationPattern GetSpecifiedPattern(AutomationElement element, string patternName)
                      {
                          AutomationPattern[] supportedPattern = element.GetSupportedPatterns();
              
                          foreach (AutomationPattern pattern in supportedPattern)
                          {
                              if (pattern.ProgrammaticName == patternName)
                                  return pattern;
                          }
              
                          return null;
                      }
              
              
                  }
              

              【讨论】: