Reputation: 6073
I need to execute a Command when a WPF TabItem Header is clicked.
Since Button has a Command, I figured I would put the Button in the TabItem Header.
I would like the Button to take up the entire contents of the TabItem Header, but no matter what I've tried, I haven't been able to get it to do so.
Here is my simple XAML Window:
TestWindow.xaml
<Window x:Class="ActivePDFMonitor.TestWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="TestWindow" Height="300" Width="300">
<Grid>
<TabControl>
<TabItem Header="Tab 1">
<TextBlock Text="Hello, world"/>
</TabItem>
<TabItem>
<TabItem.HeaderTemplate>
<DataTemplate>
<Button Content="+" Background="Green"></Button>
</DataTemplate>
</TabItem.HeaderTemplate>
<TextBlock Text="Tab 2 contents"/>
</TabItem>
</TabControl>
</Grid>
</Window>
Here's what I've tried that hasn't worked
Setting Button attributes HorizontalAlignment="Stretch"
, VerticalAlignment="Stretch"
,
HorizontalContentAlignment="Stretch"
, VerticalContentAlignment="Stretch"
- no visual effect
Wrapping other Panels (WrapPanel, DockPanel) around Button - no visual effect
Wrap Button in a <Viewbox>
- for some reason this made the Button take up the ENTIRE window.
I guess I don't need a button, if there is some way I could attach a Command to the entire TabItem Header (that would be a possible workaround solution).
However, I definitely do not want to use TabControl's SelectionChanged to trigger the adding of a new Tab (went down that road and found it to be brittle since SelectionChanged is unpredictable).
I've been banging my head on this, it seems like it should be simple. Any ideas or insight would be greatly appreciated.
Upvotes: 2
Views: 6254
Reputation: 22251
WPF's TabPanel
control doesn't swing that way. You will need to re-template TabControl
to use a different panel. DockPanel
produces the effect you are requesting:
<Window x:Class="Test.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<SolidColorBrush x:Key="TabItem.Selected.Background" Color="#FFFFFF"/>
<SolidColorBrush x:Key="TabItem.Selected.Border" Color="#ACACAC"/>
<Style x:Key="TabControlStyle1" TargetType="{x:Type TabControl}">
<Setter Property="Padding" Value="2"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Background" Value="{StaticResource TabItem.Selected.Background}"/>
<Setter Property="BorderBrush" Value="{StaticResource TabItem.Selected.Border}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabControl}">
<Grid x:Name="templateRoot" ClipToBounds="true" SnapsToDevicePixels="true" KeyboardNavigation.TabNavigation="Local">
<Grid.RowDefinitions>
<RowDefinition x:Name="RowDefinition0" Height="Auto"/>
<RowDefinition x:Name="RowDefinition1" Height="*"/>
</Grid.RowDefinitions>
<!-- here is the edit -->
<DockPanel x:Name="headerPanel" Background="Transparent" Grid.Column="0" IsItemsHost="true" Margin="2,2,2,0" Grid.Row="0" KeyboardNavigation.TabIndex="1" Panel.ZIndex="1" />
<Border x:Name="contentPanel" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Grid.Column="0" KeyboardNavigation.DirectionalNavigation="Contained" Grid.Row="1" KeyboardNavigation.TabIndex="2" KeyboardNavigation.TabNavigation="Local">
<ContentPresenter x:Name="PART_SelectedContentHost" ContentSource="SelectedContent" Margin="{TemplateBinding Padding}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="TextElement.Foreground" TargetName="templateRoot" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<TabControl Style="{DynamicResource TabControlStyle1}">
<TabItem Header="Tab 1" DockPanel.Dock="Left">
<TextBlock Text="Hello, world"/>
</TabItem>
<TabItem Header="Tab 2" DockPanel.Dock="Left">
<TextBlock Text="Hello, world"/>
</TabItem>
<TabItem Header="Foo bar" />
</TabControl>
</Grid>
</Window>
If you want to have a button in the header, without the TabItem
wrapper, you can re-template a TabItem
. You do still need to handle the case where the TabItem
is selected via keyboard or otherwise.
<TabItem>
<TabItem.Template>
<ControlTemplate>
<Button>hello</Button>
</ControlTemplate>
</TabItem.Template>
</TabItem>
Upvotes: 4