I want to have a TabControl
with multiple TabItems
. These TabItems
each have a header text. These texts may vary a lot in length (like 5 chars long and 15 chars long).
I want the TabControl
to align the headers in one row only.
All tab headers should use the same width, and when there is enough space available, i want them the to use all the space available, up to a MaxWidth
, that is the same for all items.
So if i want to use vMaxWidth` of 100 for 7 items, the tab header should be max 700 in width. If there is more space available, it should be ignored.
If there is less space available, i want that space to be distributed equally between the items. If the text gets cut off, i want to use TextWrapping
.
I have tried multiple approaches to this problem now, this is my current setup:
<Style x:Key="Style-TabControl-Main" TargetType="{x:Type TabControl}">
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabControl}">
<Grid KeyboardNavigation.TabNavigation="Local">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Border BorderThickness="0,0,0,1" Margin="13,0,0,0" BorderBrush="{StaticResource Brush-White}">
<StackPanel Panel.ZIndex="1" x:Name="HeaderPanel" IsItemsHost="True" KeyboardNavigation.TabIndex="1" Background="Transparent"
Orientation="Horizontal"/>
</Border>
<Border x:Name="Border"
Grid.Row="1" Grid.ColumnSpan="2"
KeyboardNavigation.TabNavigation="Local"
KeyboardNavigation.DirectionalNavigation="Contained"
KeyboardNavigation.TabIndex="2"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}">
<ContentPresenter x:Name="PART_SelectedContentHost" ContentSource="SelectedContent" />
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
And the TabItem
Style
<Style x:Key="Style-TabItem-Main" TargetType="{x:Type TabItem}">
<Setter Property="Height" Value="31"/>
<Setter Property="Width" Value="180" />
<Setter Property="Foreground" Value="{DynamicResource Brush-BrightRegular-Foreground}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Border x:Name="Border" Cursor="Hand"
Margin="2,0,0,0"
BorderThickness="1,1,1,0"
CornerRadius="4,4,0,0"
BorderBrush="{DynamicResource Brush-BrightRegular-Background}"
Background="{DynamicResource Brush-White}">
<ContentPresenter x:Name="Content" VerticalAlignment="Center" HorizontalAlignment="Stretch" ContentSource="Header" RecognizesAccessKey="True"
TextBlock.TextAlignment="Center" TextBlock.FontSize="16" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Foreground" Value="{DynamicResource Brush-White}"/>
<Setter TargetName="Border" Property="Background" Value="{DynamicResource Brush-DefaultDark-Background}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I am using a StackPanel
instead of a TabPanel
to get rid of the "stacking", that occurs, when you resize a default TabControl
. However, i cannot get the rest of my requirements to work. I tried applying a MaxWidth
(instead of fixed width) to the TabItem
headers, but that of course doesn't work, because the item than shrinks to its minimum required size.
Best Answer
Step 1 (first attempt): Put headers in a single row, and give each header the same width.
This can be achieved by using a
UniformGrid
instead of the standard TabPanel, and lock its row count to 1. Here is a stripped-down version of yourTabControl
style:Step 2: Restrict headers to a
MaxWidth
and apply text wrapping.The
MaxWidth
can be set in theTabItem
style, along with aHeaderTemplate
which wraps text (you can still use your customControlTemplate
here to style the TabItem parts):Troubleshooting: Now, if you apply the
MaxWidth
in Step 2, you'll probably want to left-align theUniformGrid
when the TabControl gets too wide....but you don't want that when the MaxWidth hasn't been reached yet, and the items should stretch across the entire width of the TabControl (aka Step 1). So we need a way to switch that
HorizontalAlignment
depending on whether the items' MaxWidth (if set) has been reached.Step 1 (revisited): Let's try to make our own UniformGrid:
Now, we can replace the
UniformGrid
in ourTabControl
style this new panel:...and the TabControl should function as expeced.