it-swarm.com.ru

Как растянуть заголовки элемента вкладки WPF до ширины родительского элемента управления

Есть ли способ в XAML, чтобы заголовки элементов вкладок растягивались по ширине элемента управления вкладками?

Например, у меня есть три вкладки: красная, синяя и зеленая. Если у меня есть элемент управления вкладкой с его шириной, установленной на auto, заголовки вкладок будут заполнять только часть пространства над содержимым вкладок, но я хочу, чтобы они заполняли все пространство. Для моего примера с тремя вкладками красный цвет должен занимать первую треть элемента управления, синий должен занимать центральную треть, а зеленый - последнюю треть.

У меня есть идея, как сделать это в коде, над которым я сейчас работаю, но я заинтересован в том, чтобы сделать это как можно проще.

26
Ben Doerr

Я взял пример Джордана и внес в него некоторые изменения. Эта версия должна работать для любого количества вкладок:

namespace WpfApplication1.Converters
{
    public class TabSizeConverter : IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType, object parameter,
            System.Globalization.CultureInfo culture)
        {
            TabControl tabControl = values[0] as TabControl;
            double width = tabControl.ActualWidth / tabControl.Items.Count;
            //Subtract 1, otherwise we could overflow to two rows.
            return (width <= 1) ? 0 : (width - 1);
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter,
            System.Globalization.CultureInfo culture)
        {
            throw new NotSupportedException();
        }
    }
}

То же пространство имен в xaml:

xmlns:local="clr-namespace:WpfApplication1.Converters"

И это заставит все вкладки использовать его:

<Window.Resources>
    <local:TabSizeConverter x:Key="tabSizeConverter" />
    <Style TargetType="{x:Type TabItem}">
        <Setter Property="Width">
            <Setter.Value>
                <MultiBinding Converter="{StaticResource tabSizeConverter}">
                    <Binding RelativeSource="{RelativeSource Mode=FindAncestor,
            AncestorType={x:Type TabControl}}" />
                    <Binding RelativeSource="{RelativeSource Mode=FindAncestor,
            AncestorType={x:Type TabControl}}" Path="ActualWidth" />
                </MultiBinding>
            </Setter.Value>
        </Setter>
    </Style>
</Window.Resources>
45
Ryan Versaw

Кажется, что все идут по пути конвертации, но на самом деле это так же просто, как использовать UniformGrid с Rows, установленным в 1 в шаблоне TabControl, вместо TabPanel. Конечно, вам придется повторно шаблонировать его, но это не так уж плохо.

18
Charlie

Я смог сделать это с помощью конвертера следующим образом:

namespace WpfApplication1.Converters
{
    public class SizeConverter : IValueConverter
    {
        #region IValueConverter Members

        public object Convert(object value, Type targetType, object parameter,
            System.Globalization.CultureInfo culture)
        {
            double width = Double.Parse(value.ToString());
            //Subtract 1, otherwise we could overflow to two rows.
            return .25 * width - 1;
        }

        public object ConvertBack(object value, Type targetType, object parameter,
            System.Globalization.CultureInfo culture)
        {
            throw new NotSupportedException();
        }

        #endregion
    }
}

Затем добавьте пространство имен в мой xaml:

xmlns:local="clr-namespace:WpfApplication1.Converters"

Затем, заставляя все TabItems использовать конвертер:

<Window.Resources>
        <local:SizeConverter x:Key="sizeConverter" />
        <Style TargetType="{x:Type TabItem}">
            <Setter Property="Width" Value="{Binding ElementName=x_Grid, Path=ActualWidth, Converter={StaticResource sizeConverter}}" />
        </Style>
    </Window.Resources>

x_Grid - это x: имя родительского элемента, для которого вкладки должны быть 1/4, если это имеет смысл.

6
Jordan H.

Это возможно, привязав ширину к ActualWidth родительского элемента управления вкладками, как показано ниже.

Я обернул его в стиле, чтобы применить ко всем страницам вкладок. 

<Grid>
      <Grid.Resources>
        <Style TargetType="TabItem">
            <Setter Property="Width" Value="{Binding    
                     Path=ActualWidth,    
                     RelativeSource={RelativeSource    
                    Mode=FindAncestor,    
                    AncestorType={x:Type TabControl}}}"/>
        </Style>
    </Grid.Resources>

<TabControl>
    <TabItem Header="Page3"/>
    <TabItem Header="Page2"/>
    <TabItem Header="Page3"/>            
</TabControl> 
</Grid>
3
John

Я парень в старом стиле. и предпочитают этот вид функциональности для инкапсуляции в код самого элемента управления. Мой производный элемент управления выглядит следующим образом:

    public class CustomTabControl :TabControl
{
    protected override void OnRenderSizeChanged(System.Windows.SizeChangedInfo sizeInfo)
    {
        foreach (TabItem item in this.Items)
        {
            double newW = (this.ActualWidth / Items.Count) - 1;
            if (newW < 0) newW = 0;

            item.Width = newW;
        }            
    }       
}

и мой XAML выглядит

</infrastructure:CustomTabControl>
     <TabItem />
     <TabItem />
</infrustracture:CustomControl>

Может кто-нибудь объяснить, почему все предпочитают управление стилем, а не производное.

2
Alex G

Я последовал предложению Чарли и пошел по шаблону. Вот простая реализация TabControl, которая делит доступное пространство поровну между своими TabItems, используя UniformGrid:

XAML управления

<TabControl x:Class="YourNamespace.Views.BigTabsTabControl"
             xmlns="http://schemas.Microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.Microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.Microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:YourNamespace.Views"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300"
            Padding="2" HorizontalContentAlignment="Center" VerticalContentAlignment="Center"
            BorderThickness="1" Foreground="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}">

    <TabControl.Resources>
        <SolidColorBrush x:Key="TabItem.Selected.Background" Color="#FFFFFF"/>
        <SolidColorBrush x:Key="TabItem.Selected.Border" Color="#ACACAC"/>
    </TabControl.Resources>

    <TabControl.Style>
        <Style TargetType="{x:Type TabControl}">
            <Setter Property="Background" Value="{StaticResource TabItem.Selected.Background}"/>
            <Setter Property="BorderBrush" Value="{StaticResource TabItem.Selected.Border}"/>
        </Style>
    </TabControl.Style>

    <TabControl.Template>
        <ControlTemplate TargetType="{x:Type TabControl}">
            <Grid x:Name="templateRoot" ClipToBounds="true" SnapsToDevicePixels="true" KeyboardNavigation.TabNavigation="Local">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition x:Name="ColumnDefinition0"/>
                    <ColumnDefinition x:Name="ColumnDefinition1" Width="0"/>
                </Grid.ColumnDefinitions>
                <Grid.RowDefinitions>
                    <RowDefinition x:Name="RowDefinition0" Height="Auto"/>
                    <RowDefinition x:Name="RowDefinition1" Height="*"/>
                </Grid.RowDefinitions>

                <UniformGrid x:Name="headerPanel" Background="Transparent" Grid.Column="0" IsItemsHost="true" 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="TabStripPlacement" Value="Bottom">
                    <Setter Property="Grid.Row" TargetName="headerPanel" Value="1"/>
                    <Setter Property="Grid.Row" TargetName="contentPanel" Value="0"/>
                    <Setter Property="Height" TargetName="RowDefinition0" Value="*"/>
                    <Setter Property="Height" TargetName="RowDefinition1" Value="Auto"/>
                    <Setter Property="Margin" TargetName="headerPanel" Value="2,0,2,2"/>
                </Trigger>
                <Trigger Property="TabStripPlacement" Value="Left">
                    <Setter Property="Grid.Row" TargetName="headerPanel" Value="0"/>
                    <Setter Property="Grid.Row" TargetName="contentPanel" Value="0"/>
                    <Setter Property="Grid.Column" TargetName="headerPanel" Value="0"/>
                    <Setter Property="Grid.Column" TargetName="contentPanel" Value="1"/>
                    <Setter Property="Width" TargetName="ColumnDefinition0" Value="Auto"/>
                    <Setter Property="Width" TargetName="ColumnDefinition1" Value="*"/>
                    <Setter Property="Height" TargetName="RowDefinition0" Value="*"/>
                    <Setter Property="Height" TargetName="RowDefinition1" Value="0"/>
                    <Setter Property="Margin" TargetName="headerPanel" Value="2,2,0,2"/>
                </Trigger>
                <Trigger Property="TabStripPlacement" Value="Right">
                    <Setter Property="Grid.Row" TargetName="headerPanel" Value="0"/>
                    <Setter Property="Grid.Row" TargetName="contentPanel" Value="0"/>
                    <Setter Property="Grid.Column" TargetName="headerPanel" Value="1"/>
                    <Setter Property="Grid.Column" TargetName="contentPanel" Value="0"/>
                    <Setter Property="Width" TargetName="ColumnDefinition0" Value="*"/>
                    <Setter Property="Width" TargetName="ColumnDefinition1" Value="Auto"/>
                    <Setter Property="Height" TargetName="RowDefinition0" Value="*"/>
                    <Setter Property="Height" TargetName="RowDefinition1" Value="0"/>
                    <Setter Property="Margin" TargetName="headerPanel" Value="0,2,2,2"/>
                </Trigger>
                <Trigger Property="IsEnabled" Value="false">
                    <Setter Property="TextElement.Foreground" TargetName="templateRoot" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
                </Trigger>
            </ControlTemplate.Triggers>
        </ControlTemplate>
    </TabControl.Template>
</TabControl>

Код контроля позади

using System.Windows.Controls;
using System.Windows.Controls.Primitives;

namespace YourNamespace.Views
{
  /// <summary>
  /// A TabControl with large tabs. 
  /// </summary>
  public partial class BigTabsTabControl : TabControl
  {
    public BigTabsTabControl()
    {
      InitializeComponent();
    }

    public override void OnApplyTemplate()
    {
      base.OnApplyTemplate();

      if (this.Template != null)
      {
        UniformGrid X = this.Template.FindName("headerPanel", this) as UniformGrid;
        if (X != null) X.Columns = this.Items.Count;
      }
    }
  }
}

Вот и все. Теперь вы можете добавить TabItems к этому элементу управления, и они автоматически настроят свою ширину. Нет необходимости указывать Grid.Column для этих TabItems, они прекрасно работают без него даже во время разработки.

1
dotNET

Вот безболезненное решение, которое использует только шаблоны:

<Window x:Class="Window1"
        xmlns="http://schemas.Microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.Microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.Microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:EffectLibrary="clr-namespace:EffectLibrary;Assembly=EffectLibrary"
        mc:Ignorable="d"
        Title="Window1" Height="300" Width="300">
    <TabControl Style="{DynamicResource TabControlStyle}" ItemContainerStyle="{DynamicResource TabItemStyle}" BorderBrush="{DynamicResource Pallete.Primary}" Foreground="{DynamicResource Pallete.Primary}" Background="Transparent" Margin="0" d:LayoutOverrides="Height">
        <TabControl.Resources>
            <Style x:Key="TabControlStyle" TargetType="{x:Type TabControl}">
                <Setter Property="Padding" Value="0"/>
                <Setter Property="HorizontalContentAlignment" Value="Center"/>
                <Setter Property="VerticalContentAlignment" Value="Center"/>
                <Setter Property="Background" Value="Transparent"/>
                <Setter Property="BorderBrush" Value="#093A5F"/>
                <Setter Property="BorderThickness" Value="1"/>
                <Setter Property="Foreground" Value="#001423"/>
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type TabControl}">
                            <Border x:Name="Bg" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}">
                                <Grid x:Name="templateRoot" ClipToBounds="true" SnapsToDevicePixels="true" KeyboardNavigation.TabNavigation="Local">
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition x:Name="ColumnDefinition0"/>
                                        <ColumnDefinition x:Name="ColumnDefinition1" Width="0"/>
                                    </Grid.ColumnDefinitions>
                                    <Grid.RowDefinitions>
                                        <RowDefinition x:Name="RowDefinition0" Height="Auto"/>
                                        <RowDefinition x:Name="RowDefinition1" Height="*"/>
                                    </Grid.RowDefinitions>
                                    <UniformGrid x:Name="headerPanel" IsItemsHost="True" Margin="0">
                                        <UniformGrid.Style>
                                            <Style TargetType="{x:Type UniformGrid}">
                                                <Setter Property="Rows" Value="1"/>
                                                <Style.Triggers>
                                                    <DataTrigger Binding="{Binding TabStripPlacement, RelativeSource={RelativeSource TemplatedParent}}" Value="Right">
                                                        <Setter Property="Columns" Value="1"/>
                                                        <Setter Property="Rows" Value="0"/>
                                                    </DataTrigger>
                                                    <DataTrigger Binding="{Binding TabStripPlacement, RelativeSource={RelativeSource TemplatedParent}}" Value="Left">
                                                        <Setter Property="Columns" Value="1"/>
                                                        <Setter Property="Rows" Value="0"/>
                                                    </DataTrigger>
                                                </Style.Triggers>
                                            </Style>
                                        </UniformGrid.Style>
                                    </UniformGrid>
                                    <Border x:Name="contentPanel" Grid.Column="0" KeyboardNavigation.DirectionalNavigation="Contained" Grid.Row="1" KeyboardNavigation.TabIndex="2" KeyboardNavigation.TabNavigation="Local" BorderThickness="0,1,0,0" BorderBrush="{TemplateBinding BorderBrush}">
                                        <ContentPresenter x:Name="PART_SelectedContentHost" ContentSource="SelectedContent" Margin="{TemplateBinding Padding}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                                    </Border>
                                </Grid>
                            </Border>
                            <ControlTemplate.Triggers>
                                <Trigger Property="TabStripPlacement" Value="Bottom">
                                    <Setter Property="Grid.Row" TargetName="headerPanel" Value="1"/>
                                    <Setter Property="Grid.Row" TargetName="contentPanel" Value="0"/>
                                    <Setter Property="Height" TargetName="RowDefinition0" Value="*"/>
                                    <Setter Property="Height" TargetName="RowDefinition1" Value="Auto"/>
                                </Trigger>
                                <Trigger Property="TabStripPlacement" Value="Left">
                                    <Setter Property="Grid.Row" TargetName="headerPanel" Value="0"/>
                                    <Setter Property="Grid.Row" TargetName="contentPanel" Value="0"/>
                                    <Setter Property="Grid.Column" TargetName="headerPanel" Value="0"/>
                                    <Setter Property="Grid.Column" TargetName="contentPanel" Value="1"/>
                                    <Setter Property="Width" TargetName="ColumnDefinition0" Value="Auto"/>
                                    <Setter Property="Width" TargetName="ColumnDefinition1" Value="*"/>
                                    <Setter Property="Height" TargetName="RowDefinition0" Value="*"/>
                                    <Setter Property="Height" TargetName="RowDefinition1" Value="0"/>
                                </Trigger>
                                <Trigger Property="TabStripPlacement" Value="Right">
                                    <Setter Property="Grid.Row" TargetName="headerPanel" Value="0"/>
                                    <Setter Property="Grid.Row" TargetName="contentPanel" Value="0"/>
                                    <Setter Property="Grid.Column" TargetName="headerPanel" Value="1"/>
                                    <Setter Property="Grid.Column" TargetName="contentPanel" Value="0"/>
                                    <Setter Property="Width" TargetName="ColumnDefinition0" Value="*"/>
                                    <Setter Property="Width" TargetName="ColumnDefinition1" Value="Auto"/>
                                    <Setter Property="Height" TargetName="RowDefinition0" Value="*"/>
                                    <Setter Property="Height" TargetName="RowDefinition1" Value="0"/>
                                </Trigger>
                                <Trigger Property="IsEnabled" Value="false">
                                    <Setter Property="Effect" TargetName="templateRoot">
                                        <Setter.Value>
                                            <EffectLibrary:DesaturateEffect DesaturationFactor=".25"/>
                                        </Setter.Value>
                                    </Setter>
                                </Trigger>
                            </ControlTemplate.Triggers>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
            <Style x:Key="TabItemStyle" TargetType="{x:Type TabItem}">
                <Setter Property="FocusVisualStyle" Value="{StaticResource FocusVisual}"/>
                <Setter Property="Foreground" Value="{Binding Foreground, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TabControl}}}"/>
                <Setter Property="Background" Value="{Binding Background, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TabControl}}}"/>
                <Setter Property="BorderBrush" Value="{Binding BorderBrush, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TabControl}}}"/>
                <Setter Property="Margin" Value="0"/>
                <Setter Property="Padding" Value="0,5"/>
                <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
                <Setter Property="VerticalContentAlignment" Value="Stretch"/>
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type TabItem}">
                            <Grid x:Name="templateRoot" SnapsToDevicePixels="true"  Background="{TemplateBinding Background}">
                                <Border x:Name="mainBorder" BorderBrush="{TemplateBinding BorderBrush}">
                                    <Border x:Name="highlightBorder"/>
                                </Border>
                                <ContentPresenter x:Name="contentPresenter" ContentSource="Header" Focusable="False" HorizontalAlignment="{Binding HorizontalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{Binding VerticalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
                            </Grid>
                            <ControlTemplate.Triggers>
                                <Trigger Property="IsEnabled" Value="false">
                                    <Setter Property="Effect" TargetName="templateRoot">
                                        <Setter.Value>
                                            <EffectLibrary:DesaturateEffect DesaturationFactor=".25"/>
                                        </Setter.Value>
                                    </Setter>
                                </Trigger>
                                <DataTrigger Binding="{Binding IsSelected, RelativeSource={RelativeSource Self}}" Value="true">
                                    <Setter TargetName="highlightBorder" Property="Background" Value="#0B79CE"/>
                                </DataTrigger>
                                <DataTrigger Binding="{Binding TabStripPlacement, RelativeSource={RelativeSource AncestorType={x:Type TabControl}}}" Value="Top">
                                    <Setter TargetName="mainBorder" Property="BorderThickness" Value="0,0,1,0"/>
                                    <Setter TargetName="highlightBorder" Property="Height" Value="2"/>
                                    <Setter TargetName="highlightBorder" Property="VerticalAlignment" Value="Bottom"/>
                                </DataTrigger>
                                <DataTrigger Binding="{Binding TabStripPlacement, RelativeSource={RelativeSource AncestorType={x:Type TabControl}}}" Value="Bottom">
                                    <Setter TargetName="mainBorder" Property="BorderThickness" Value="0,0,1,0"/>
                                    <Setter TargetName="highlightBorder" Property="Height" Value="2"/>
                                    <Setter TargetName="highlightBorder" Property="VerticalAlignment" Value="Top"/>
                                </DataTrigger>
                                <DataTrigger Binding="{Binding TabStripPlacement, RelativeSource={RelativeSource AncestorType={x:Type TabControl}}}" Value="Left">
                                    <Setter TargetName="mainBorder" Property="BorderThickness" Value="0,0,0,1"/>
                                    <Setter TargetName="highlightBorder" Property="Width" Value="2"/>
                                    <Setter TargetName="highlightBorder" Property="HorizontalAlignment" Value="Right"/>
                                </DataTrigger>
                                <DataTrigger Binding="{Binding TabStripPlacement, RelativeSource={RelativeSource AncestorType={x:Type TabControl}}}" Value="Right">
                                    <Setter TargetName="mainBorder" Property="BorderThickness" Value="0,0,0,1"/>
                                    <Setter TargetName="highlightBorder" Property="Width" Value="2"/>
                                    <Setter TargetName="highlightBorder" Property="HorizontalAlignment" Value="Left"/>
                                </DataTrigger>
                            </ControlTemplate.Triggers>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </TabControl.Resources>
        <TabItem Header="Years">
            <ListBox Background="{DynamicResource Pallete.Primary.Brightest}" Foreground="{DynamicResource Pallete.Primary}">
                <TextBlock Text="2015"/>
                <TextBlock Text="2016"/>
                <TextBlock Text="2017"/>
            </ListBox>
        </TabItem>
        <TabItem Header="Tables">
            <ListBox  Background="{DynamicResource Pallete.Primary.Brightest}" Foreground="{DynamicResource Pallete.Primary}">
                <TextBlock Text="Table1..."/>
                <TextBlock Text="Table2..."/>
                <TextBlock Text="Table3..."/>
            </ListBox>
        </TabItem>
    </TabControl>
</Window>

Надеюсь, я включил все цвета, и это будет работать для вас. Ааа ... Щелк! Мой эффект десатурации! Мой стартовый проект WPF вы можете получить этот эффект оттуда, если хотите (эффект проще отобразить в триггере, чем перекрасить все то же самое с бликами) . Да, это много кода , но я просто изменил ItemsContainer, чтобы он выглядел лучше, и заменил стандартный элемент управления Header на UniformGrid и установил Rows или Columns в 1 в зависимости от TabStripPlacement. Теперь я могу свернуть этот код или спрятать его где-нибудь. :)

1
zORg Alex

Я решил эту проблему, создав специальный конвертер:

    public class TabItemWidthAdjustmentConverter : IValueConverter
    {
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        Double lTabControlWidth = value is Double ? (Double)value : 50; // 50 just to see something, in case of error
        Int32 lTabsCount = (parameter != null && parameter is String) ? Int32.Parse((String)parameter) : 1;
        return lTabControlWidth / lTabsCount;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
    }

И я вычисляю значение одного элемента вкладки в элементе Tag элемента TabControl, чтобы избежать его расчета для каждой вкладки в отдельности. Вот пример кода (обратите внимание, что в моем случае мне нужен горизонтальный ScrollViewer, потому что у меня есть несколько элементов вкладок, и с минимальной шириной):

<TabControl Name="tabControl" VerticalAlignment="Stretch" SelectionChanged="TabControl_SelectionChanged" 
                    Tag="{Binding RelativeSource={RelativeSource Self}, Path=ActualWidth, Converter={StaticResource tabItemWidthAdjustmentConverter}, ConverterParameter=15}"><!-- Here 15 because I have 15 tabs -->
            <TabControl.Template>
                <ControlTemplate TargetType="TabControl">
                    <StackPanel>
                        <ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Disabled">
                            <TabPanel x:Name="HeaderPanel"
                                      Panel.ZIndex="1"
                                      KeyboardNavigation.TabIndex="1"
                                      IsItemsHost="True"/>
                        </ScrollViewer>
                        <ContentPresenter x:Name="PART_SelectedContentHost" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
                                          Margin="{TemplateBinding Padding}"
                                          ContentSource="SelectedContent"/>
                    </StackPanel>
                </ControlTemplate>
            </TabControl.Template>
            <TabItem Header="Tab1" MinWidth="115" VerticalAlignment="Stretch" Width="{Binding ElementName=tabControl, Path=Tag}">
                <ContentControl ContentTemplate="{StaticResource My_TemplateTab1}">
                    <ContentPresenter />
                </ContentControl>
            </TabItem>
            <TabItem Header="Tab2" MinWidth="115" Height="50" Width="{Binding ElementName=tabControl, Path=Tag}">
                <ContentControl ContentTemplate="{StaticResource My_TemplateTab2}">
                    <ContentPresenter />
                </ContentControl>
            </TabItem>
            <!-- Here another 13 tabs which I skipped -->
            </TabControl>

Я могу сказать, что это работает как шарм в моем случае:) Надеюсь, кто-то найдет это полезным!

Постскриптум Мне не нужно/не нужно никакого стиля в моем случае.

1
XMight

Я использую следующее решение: В главном окне я использую событие измененного размера окна и событие инициализации tabcontrol, чтобы установить ширину каждой вкладки. Число «5» соответствует моему количеству вкладок. 

    private void tabchanger_Initialized(object sender, EventArgs e)
    {
        foreach (TabItem item in tabchanger.Items)
        {
            double newW = (tabchanger.ActualWidth / 5) - 1;
            if (newW < 0) newW = 0;

            item.Width = newW;
        }

    }

    private void Window_SizeChanged(object sender, SizeChangedEventArgs e)
    {
        foreach (TabItem item in tabchanger.Items)
        {
            double newW = (tabchanger.ActualWidth / 5) - 1;
            if (newW < 0) newW = 0;

            item.Width = newW;
        }
    }
0
hyphestos

Я не знаю, будет ли это работать для вкладок, но всякий раз, когда мне нужно было растянуть что-либо, чтобы заполнить контейнер, я использовал ViewBox . Это то, что вы ищете?

0
Matthew Steeples

В дополнение к общепринятому решению Райана Версау, которое дает одинаковую ширину заголовка tabItem, я нашел следующий способ сделать его зависимым от длины каждого заголовка.

Сначала мы получаем строку каждого заголовка tabItem, добавляя эту строку в мультисвязь xaml. Таким образом, это становится:

<MultiBinding Converter="{StaticResource tabSizeConverter}">
           <Binding RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type TabControl}}" />
           <Binding RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type TabControl}}" Path="ActualWidth" />
           <Binding Path="Header" RelativeSource="{RelativeSource Self}"/>
</MultiBinding>

И еще немного кода в конвертере (values ​​[] получает также заголовок tabItem):

public object Convert(object[] values, Type targetType, object parameter,
        System.Globalization.CultureInfo culture)
    {
        TabControl tabControl = values[0] as TabControl;

        string AllHeaders = "";
        for (int i = 0; i < tabControl.Items.Count; i++)
        {
            int index = tabControl.Items[i].ToString().IndexOf("Header:") + "Header:".Length;
            string currentHeader = tabControl.Items[i].ToString().Substring(index);
            currentHeader = currentHeader.Substring(0, currentHeader.Length - " Content:".Length);
            AllHeaders += currentHeader;
        }

        //Normalize width according to header length
        double width = values[2].ToString().Length * tabControl.ActualWidth / AllHeaders.Length;

        //Subtract 1, otherwise we could overflow to two rows.
        var retVal = (width <= 1) ? 0 : (width - 1);
        return retVal;
    }

Я подозреваю, что может быть более эффективный способ получить строку AllHeaders всех заголовков, но она работает нормально, как есть ...

0
tombobadil