7

我正在使用Microsoft UI 自动化(即AutomationElement)对我的应用程序运行自动化验收测试。这进展顺利,但我遇到了似乎没有暴露于自动化框架的情况。

我有一个ItemsControl(尽管我可以使用它的派生控件之一,例如ListBox),并且我正在使用CollectionViewSource对项目进行分组。这是一个完整的窗口来演示:

<Window x:Class="GroupAutomation.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Orchestra">
    <Window.Resources>

        <!-- Take some simple data -->
        <XmlDataProvider x:Key="SampleData" XPath="Orchestra/Instrument">
            <x:XData>
                <Orchestra xmlns="">
                    <Instrument Name="Flute" Category="Woodwind" />
                    <Instrument Name="Trombone" Category="Brass" />
                    <Instrument Name="French horn" Category="Brass" />
                </Orchestra>
            </x:XData>
        </XmlDataProvider>

        <!-- Add grouping -->
        <CollectionViewSource Source="{Binding Source={StaticResource SampleData}}" x:Key="GroupedView">
            <CollectionViewSource.GroupDescriptions>
                <PropertyGroupDescription PropertyName="@Category" />
            </CollectionViewSource.GroupDescriptions>
        </CollectionViewSource>
    </Window.Resources>

    <!-- Show it in an ItemsControl -->
    <ItemsControl ItemsSource="{Binding Source={StaticResource GroupedView}}" HorizontalAlignment="Left" Margin="4">
        <ItemsControl.GroupStyle>
            <GroupStyle>
                <GroupStyle.HeaderTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding Path=Name}" FontWeight="Bold" />
                    </DataTemplate>
                </GroupStyle.HeaderTemplate>
            </GroupStyle>
        </ItemsControl.GroupStyle>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Border Padding="4" Margin="4" Background="#FFDEDEDE">
                    <StackPanel>
                        <Label Content="{Binding XPath=@Name}" />
                        <Button Content="Play" />
                    </StackPanel>
                </Border>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</Window>

这会生成一个窗口,其中包含分组到其类别中的项目,并且每个项目都有一个我想使用 UI 自动化单击的按钮:

带有列表的窗口的屏幕截图
(来源:brizzly.com

但是,如果我查看UISpy.exe(或使用 导航AutomationElement),我只会看到组(即使在原始视图中):

UISpy
(来源:brizzly.com

如您所见,这些组在那里,但它们不包含任何项目,因此无处可寻按钮。我已经在 WPF 3.5 SP1 和 WPF 4.0 中尝试过这个并得到相同的结果。

是否可以在分组的项目上使用 UI 自动化,如果可以,如何?

4

4 回答 4

7

我遇到了这个问题并设法通过从http://www.colinsalmcorner.com/post/genericautomationpeer--helping-the-coded-ui-framework-find-your-custom-controls实现“GenericAutomationPeer”来解决它和为 s 添加一个特殊情况GroupItem

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Automation;
using System.Windows.Automation.Peers;
using System.Windows.Media;
using System.Xml;

namespace ClassLibrary1
{
    public class MyItemsControl : ItemsControl
    {
        protected override AutomationPeer OnCreateAutomationPeer()
        {
            return new GenericAutomationPeer(this);
        }
    }

    public class GenericAutomationPeer : UIElementAutomationPeer
    {
        public GenericAutomationPeer(UIElement owner) : base(owner)
        {
        }

        protected override List<AutomationPeer> GetChildrenCore()
        {
            var list = base.GetChildrenCore();
            list.AddRange(GetChildPeers(Owner));
            return list;
        }

        private List<AutomationPeer> GetChildPeers(UIElement element)
        {
            var list = new List<AutomationPeer>();
            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(element); i++)
            {
                var child = VisualTreeHelper.GetChild(element, i) as UIElement;
                if (child != null)
                {
                    AutomationPeer childPeer;
                    if (child is GroupItem)
                    {
                        childPeer = new GenericAutomationPeer(child);
                    }
                    else
                    {
                        childPeer = UIElementAutomationPeer.CreatePeerForElement(child);
                    }
                    if (childPeer != null)
                    {
                        list.Add(childPeer);
                    }
                    else
                    {
                        list.AddRange(GetChildPeers(child));
                    }
                }
            }
            return list;
        }
    }

}

我希望这可以帮助任何仍在寻找答案的人!

于 2016-08-02T04:32:40.203 回答
3

我不是 100% 确定按钮,但是sTextBlock内部的控件不会放入 UI 自动化树中。显然,这是避免 1000 个不必要的文本块的优化。DataTemplate

您可以通过子类化 TextBlock 来解决它。这是我的:

public class AutomatableTextBlock : TextBlock
{
    protected override AutomationPeer OnCreateAutomationPeer()
    {
        return new AutomatableTextBlockAutomationPeer(this);
    }

    class AutomatableTextBlockAutomationPeer : TextBlockAutomationPeer
    {
        public AutomatableTextBlockAutomationPeer(TextBlock owner)
            : base(owner)
        { }

        protected override bool IsControlElementCore()
        { return true; }
    }
}

注意:UI 自动化也不公开各种其他控件,例如Canvas, Panel,您可以让它们显示为类似的子类。

这么说,我不确定为什么Button没有出现.... Hrmmm

于 2010-05-17T03:00:05.590 回答
1

I ended up solving this in my application by using TreeWalker.RawViewWalker to manually navigate the tree after using AutomationElement.FindFirst to find the template. FindFirst seems to reliably exclude all the information you want when automating somebody else's application. RawViewWalker seems to work when the elements show up in "Inspect Objects", but not in UISpy or your application.

于 2011-11-17T19:13:46.130 回答
1

您使用什么工具来编写自动化脚本?我原以为可以选择钻入 WPF 的逻辑/视觉树,而不是依赖 Win32 树(如 UISpy 所示)。

如果您使用Snoop查看同一应用程序,您将看到完整的可视化和逻辑树。

于 2010-05-05T12:49:22.080 回答