Philip Tenn
Philip Tenn

Reputation: 6073

WPF TabItem Header - force Button to take up entire Header space

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:

enter image description here

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

  1. Setting Button attributes HorizontalAlignment="Stretch", VerticalAlignment="Stretch", HorizontalContentAlignment="Stretch", VerticalContentAlignment="Stretch" - no visual effect

  2. Wrapping other Panels (WrapPanel, DockPanel) around Button - no visual effect

  3. 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

Answers (1)

Mitch
Mitch

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:

Tabcontrol using a dockpanel

<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.

Button in a tabitem template

        <TabItem>
            <TabItem.Template>
                <ControlTemplate>
                    <Button>hello</Button>
                </ControlTemplate>
            </TabItem.Template>
        </TabItem>

Upvotes: 4

Related Questions