使用UI自动化选择组合框项目

10

如何选择 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

9个回答

27

这比它需要的要复杂100倍,但我最终使其工作了。 WPF ComboBox 的一个大问题是,就自动化而言,它似乎没有任何 ListItems,除非 ComboBox 已被展开

以下代码使用 ExpandCollapse 模式瞬间展开列表,然后将其折叠起来,然后它可以在 ComboBox 上使用 FindFirst 来获取要选择的 ListItem,然后使用 SelectionItem 模式进行选择。

对于原始问题,选择-1表示未选择任何项。没有此方法,但您可以简单地使用 FindAll 获取 ListItem 集合,依次获取每个 ListItem 的 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;
    }

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/zh-cn/library/ms752305(v=vs.110).aspx


1
你能在代码中留下一些注释来描述你的代码是做什么的吗? - Shawn
1
SelectComboboxItem 扩展方法必须在静态类中才能正常工作。 - davinceleecode

3

我认为我可以分享一种简单的方法,从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;
    }

元素是ComboBox或项目容器,项目是容器中项目的字符串名称或文字值。一旦您拥有该项目,您可以执行以下操作来选择它:

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

希望这能帮到其他人。我从MSDN的自动化文档中得出了这个模式,链接在此:MSDN - 自动化和缓存子元素

不确定为什么,但对于我的项目,如果选择的元素是当前选定的元素,则select.Select()会抛出异常。- 如果这有所区别,那么目标是Win32。 - Roger Willcocks
使用缓存请求使其变得复杂。 - Iqra.

1

虽然变化不大,但有几点需要注意:

  1. 无需使用折叠模式,调用展开函数即可。
  2. 我使用 treescope.subtree 替代了 children。

代码示例如下:

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

1

或者如果您更喜欢英文MSDN,可以访问http://msdn.microsoft.com/en-us/library/system.windows.automation.selectionitempattern_members%28v=vs.90%29.aspx。 - paytools-steve

1
我认为这可能是一个简单通用的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();
}

0

对我来说,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;
        }

0
<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(子项)->ListItems(子项)[每个ComboBox都有一个ListBox作为子项,而ListBox有所有ListItems作为子项]。

每个ListItem都有SelectedItemPattern,调用它即可选择。

后来我发现“Shaz”有更好的编码,我投票支持他的代码最佳。

** 评论:要进行UIAAutomation,必须将应用程序的AutomationElements映射到TreeView中,这样一切都变得简单易懂。


0

我在 WindowsForms comboBox 中使用了这段代码

用法

comboBox.SetSelectedComboBoxItem("ValueYouWantToSelect");

将这个添加到您的项目中:

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


    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接