Summary
In my WPF application, I needed a TabControl with buttons on the left, so I defined a ControlTemplate with the layout I wanted and it worked fine.
However, my tester's automated testing tool can't see any of the content of the tabs, including the currently selected tab.
Question: How can I keep my TabControl testable by the automated testing tools, while still defining the ControlTemplate?
Details
I'm developing a WPF application using WPF 3.5
My tester is using an automated test tool called QTP
He says he can test anything you can see with UISpy.exe
- When I use a straight TabControl with no Template applied, UISpy can see the content of the currently selected tab.
- However, when I use a ContentTemplate to change the layout (code shown below), UISpy can still see the tab headers... but it cannot see the content.
Sample WPF application (Xaml):
<Window x:Class="TabControlTest.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Tab Control Test"
Height="300"
Width="300">
<Window.Resources>
<ControlTemplate x:Key="ButtonsOnLeftTabLayout"
TargetType="{x:Type TabControl}">
<DockPanel>
<StackPanel DockPanel.Dock="Left"
IsItemsHost="True" />
<ContentPresenter Content="{TemplateBinding SelectedContent}" />
</DockPanel>
</ControlTemplate>
</Window.Resources>
<TabControl Template="{StaticResource ButtonsOnLeftTabLayout}">
<TabItem Header="Tab 1">
<StackPanel>
<Button HorizontalAlignment="Center">Button 1</Button>
</StackPanel>
</TabItem>
<TabItem Header="Tab 2">
<StackPanel>
<Button HorizontalAlignment="Center">Button 2</Button>
</StackPanel>
</TabItem>
</TabControl>
</Window>
What my search has found so far:
- A bunch of stuff about having to write a custom TabControl with a custom AutomationPeer (e.g. MSFT answer to forum question UI Automation: accessing control in a ControlTemplate, blog posting Custom Controls and UI Automation). But my every instinct says that's crazy overkill, "there must be a simpler way!"
- Some suggestions about giving the ContentPresenter a Name, or x:Name, or AutomationProperties.AutomationId -- none of which have any effect
(After search I finally found answer but it took longer than I thought it should have, and the AutomationPeer early findings were indeed incorrect, so I'm writing this as a SO question and self-answer, in case it helps anyone else in future)