Domanda

Setting the scene

I have a simple Microsoft WPF application that consists of a (data driven) GroupBox containing a Group of Cats and a group of Dogs. Both the Cat and Dog groups contain two group items each. When I run the application all appears fine, I can see the groups and their content on the screen.

Running the application produces the following window:

Application Output

However, when I create a UIAutomation test I can’t find any AutomationElements for the group items, just the groups; only the Cat and Dog Groups can be accessed using either the AutomationElement route, or seen in UISpy.exe as per the image below:

UISpy show no children for the groups

The child components for the individual Cat and Dog group items are not present and I need to be able to retrieve them as AutomationElements in my test code:

    [TestMethod]
    public void MyTest()
    {
        Condition controlTypeCondition = new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Group);
        var foreGroundWindow = GetForegroundWindow();
        var collection = foreGroundWindow.FindAll(TreeScope.Descendants, controlTypeCondition);
        foreach (AutomationElement element in collection)
        {
            logger.Debug("Name: " + element.Current.Name);
            var children = element.FindAll(TreeScope.Children, Condition.TrueCondition);
            logger.Debug("Number of children: " + children.Count);
        }
    }

The above currently outputs:

Name: Cat

Number of children: 0

Name: Dog

Number of children: 0

Reproducing the Issue

To reproduce this issue, create a new WPF application in Visual Studio (called WpfApplication1) and replace the contents of the MainWindow.xaml with the following:

<Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    Title="MainWindow" Height="350" Width="525">

<Window.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
        </ResourceDictionary.MergedDictionaries>
        <XmlDataProvider x:Key="data">
            <x:XData>
                <Animals xmlns="">
                    <Animal name="Felix" Species="Cat" />
                    <Animal name="Garfield" Species="Cat" />
                    <Animal name="Rex" Species="Dog" />
                    <Animal name="Rover" Species="Dog" />
                </Animals>
            </x:XData>
       </XmlDataProvider>
        <CollectionViewSource x:Key="AnimalsBySpecies" Source="{Binding Source={StaticResource data}, XPath=Animals/Animal}">
            <CollectionViewSource.GroupDescriptions>
                <PropertyGroupDescription PropertyName="@Species" />
            </CollectionViewSource.GroupDescriptions>
        </CollectionViewSource>
    </ResourceDictionary>
</Window.Resources>

<ItemsControl ItemsSource="{Binding Source={StaticResource AnimalsBySpecies}}">
    <ItemsControl.GroupStyle>
        <GroupStyle>
            <GroupStyle.ContainerStyle>
                <Style TargetType="{x:Type GroupItem}">
                    <Setter Property="Template">
                        <Setter.Value>
                            <ControlTemplate TargetType="{x:Type GroupItem}">
                                <GroupBox Header="{Binding Name}">
                                    <ItemsPresenter />
                                </GroupBox>
                            </ControlTemplate>
                        </Setter.Value>
                    </Setter>
                </Style>
            </GroupStyle.ContainerStyle>
        </GroupStyle>
    </ItemsControl.GroupStyle>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding XPath=@name}" />
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>
</Window>

In reality my code doesn't look exactly like this as it is an MVVM application. But for brevity I have simplified that down into a single XAML file which reproduces the same issue. The key point to note is that the group contents are populated from a XAML Binding.

So how can I get to the content using UIAutomation?

Any help greatly appreciated!

È stato utile?

Soluzione

Try using the the native-code UI Automation API, instead of the managed API that's part of the .Net framework. This newer API supports additional accessibility, and is recommended by Microsoft. Here's some more information, be sure to read the links in the original post.

In addition, UISpy is deprecated and no longer recommended. Instead, use UIA Verify tool which, in addition to being much more stable and faster than UISpy, also works with the Windows Automation API described above and thus may expose more information about the controls you're interested at.

Altri suggerimenti

UISpy is not a good tool to inspect WPF windows or elements. I would suggest using Snoop.

However, this question seems similar and the solution given there may solve your problem.

This is a well-known issue where TextBlock's that are inside data templates are not visible in the Control or Content views of the automation tree. This is an optimization made by WPF. There are three possible resolutions.

One is to use .NET 4.5 where, I believe, this was changed so that TextBlock's will now be included.

Another is to make sure you use the Raw view. This is easy in UI Spy (go to View > Raw View) however it somewhat cumbersome in automated tests as you cannot use normal FindFirst or FindAll conditions. You have to use TreeWalker.RawViewWalker to manually inspect the automation tree.

Finally, you can subclass the TextBlock control and override the OnCreateAutomationPeer method to return a custom AutomationPeer implementation with IsControlElement returning true. This outlined in this answer.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top