Andrew
Andrew

Reputation: 5083

TabItem headers: Content doesn't stretch if the actual tab header does

I have a TabControl and am attempting to get the headers to look nice. I have the following XAML:

(In Resources.xaml:)

<DataTemplate x:Key="ClosableTabItemTemplate">
    <DockPanel LastChildFill="True" MinWidth="200" Height="20" HorizontalAlignment="Stretch" behaviors:MouseClickBehavior.ClickCommand="{Binding Path=CloseCommand}">
        <Image Source="{Binding Path=Image}" Height="16" VerticalAlignment="Center" />
        <Button Background="Transparent"
                  BorderBrush="Transparent"
                  Command="{Binding Path=CloseCommand}"
                  Content="X"
                  Cursor="Hand"
                  DockPanel.Dock="Right"
                  Focusable="False" 
                  FontSize="9"
                  FontWeight="Bold"
                  Margin="3,0,0,0"
                  Padding="0"
                  VerticalAlignment="Center"
                  VerticalContentAlignment="Center"
                  Width="16" Height="16" />
        <TextBlock Text="{Binding Path=Header}" DockPanel.Dock="Left" VerticalAlignment="Center" />
    </DockPanel>
</DataTemplate>

(In MainWindow.xaml:)

<TabControl Grid.Column="1"
            ItemsSource="{Binding Path=Tabs}"
            ItemTemplate="{DynamicResource ClosableTabItemTemplate}" />

Here is a visual example of my problem:

I like the actual width of the tabs for now, but the fact that my dockpanel for the header isn't filling up all the space is bothersome. Same thing happens if I use a Grid, too (presumably any container control).

Upvotes: 7

Views: 4948

Answers (3)

Alex Humphrey
Alex Humphrey

Reputation: 6209

ContentPresenter.HorizontalAlignment in the default style for TabItem is bound to ItemsControl.HorizontalContentAlignment. Here it is, taken from Aero.NormalColor.xaml:

<ContentPresenter Name="Content"
                  ContentSource="Header"
                  SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
                  HorizontalAlignment="{Binding Path=HorizontalContentAlignment,RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"
                  VerticalAlignment="{Binding Path=VerticalContentAlignment,RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"
                  RecognizesAccessKey="True"/>

Setting TabControl.HorizontalContentAlignment to Stretch fixes the issue for me.

<TabControl HorizontalContentAlignment="Stretch" />

Upvotes: 8

Todd L
Todd L

Reputation: 91

I ran into the same visual issue with closable tabs and resolved it by extending both the TabControl (to be used later in XAML) and TabItem classes. I overrode GetContainerForItemOverride() in the former, and OnApplyTemplate() in the latter. I created a DependencyObject extension method to find the ContentPresenter element of the TabItem and set its HorizontalAlignment property to HorizontalAlignment.Stretch:

public class MyTabControl : TabControl
{
    protected override DependencyObject GetContainerForItemOverride()
    {
        return new MyTabItem();
    }
}

public class MyTabItem : TabItem
{
    public override void OnApplyTemplate()
    {
        base.OnApplyTemplate();

        var content = this.GetFirstDescendantOfType<ContentPresenter>();
        if (content != null)
        {
            content.HorizontalAlignment = HorizontalAlignment.Stretch;
        }
    }
}

public static class DependencyObjectExtensions
{
    public static T GetFirstDescendantOfType<T>(this DependencyObject parent) where T : DependencyObject
    {
        if (parent == null)
        {
            return null;
        }
        else
        {
            var children = parent.GetChildren();
            T descendant = children.FirstOrDefault(child => child is T) as T;

            if (descendant == null)
            {
                foreach (var child in children)
                {
                    if ((descendant = child.GetFirstDescendantOfType<T>()) != null) break;
                }
            }

            return descendant;
        }
    }

    public static IEnumerable<DependencyObject> GetChildren(this DependencyObject parent)
    {
        var children = new List<DependencyObject>();

        for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++)
        {
            children.Add(VisualTreeHelper.GetChild(parent, i));
        }

        return children;
    }
}

My XAML appears as the following:

(In MainWindowResources.xaml):

<DataTemplate x:Key="ClosableTabItemTemplate">
    <DockPanel>
        <Button Command="{Binding Path=CloseCommand}"
                Content="X"
                Cursor="Hand"
                DockPanel.Dock="Right"
                Focusable="False"
                FontFamily="Courier"
                FontSize="9"
                FontWeight="Bold"
                Margin="8,1,0,0"
                Padding="0"
                VerticalContentAlignment="Bottom"
                Width="16"
                Height="16"
                ToolTip="Close" />
        <TextBlock Text="{Binding Path=DisplayName}"
                   HorizontalAlignment="Center"
                   VerticalAlignment="Center" />
    </DockPanel>
</DataTemplate>

(In MainWindow.xaml): Note the use of the custom MyTabControl control

<MyTabControl IsSynchronizedWithCurrentItem="True"
              ItemsSource="{Binding Path=ClosableViewModels}"
              ItemTemplate="{StaticResource ClosableTabItemTemplate}"
              Margin="4" />

Upvotes: 3

Rachel
Rachel

Reputation: 132548

Try overwritting the ItemContainerStyle.Template instead of the ContentTemplate

I did something like this in the past, although I overwrote the entire TabControl template so it's a bit hard to see what I was doing. My code looked like this:

<ControlTemplate x:Key="CurvedTabItemTemplate" TargetType="{x:Type TabItem}">
    <DockPanel Width="200">
        <ContentPresenter x:Name="ContentSite" ContentSource="Header" RecognizesAccessKey="True" />
    </DockPanel>
</ControlTemplate>

<Style x:Key="CurvedTabItemStyle" TargetType="{x:Type TabItem}">
    <Setter Property="Template" Value="{StaticResource CurvedTabItemTemplate}" />
</Style>

<TabControl Grid.Column="1" ItemsSource="{Binding Path=Tabs}" 
            ContentTemplate="{DynamicResource ClosableTabItemTemplate}"
            ItemContainerStyle="{DynamicResource CurvedTabItemStyle}" />

Upvotes: 2

Related Questions