web-dev-qa-db-fra.com

Procédure d'extension des en-têtes d'élément d'onglet WPF à la largeur du contrôle parent

XAML existe-t-il un moyen de faire en sorte que les en-têtes d'élément d'onglets s'étendent sur la largeur du contrôle d'onglets?

Par exemple, j'ai trois onglets: rouge, bleu et vert. Si j'ai un contrôle de tabulation dont la largeur est définie sur auto, les en-têtes de tabulation ne rempliront qu'une partie de l'espace situé au-dessus du contenu de la tabulation, mais je souhaite qu'ils remplissent tout l'espace. Pour mon exemple à trois onglets, le rouge devrait occuper le premier tiers du contrôle, le bleu devrait occuper le tiers central et le vert le dernier tiers.

J'ai une idée de comment faire cela dans un code sur lequel je travaille maintenant, mais je suis intéressé à le faire de la manière la plus simple possible.

26
Ben Doerr

J'ai pris l'exemple de Jordan et y ai apporté des modifications. Cette version devrait fonctionner pour n'importe quel nombre d'onglets:

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();
        }
    }
}

Même espace de nom dans le xaml:

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

Et cela fera en sorte que tous les onglets l'utilisent:

<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

Tout le monde semble utiliser la route du convertisseur, mais c'est aussi simple que d'utiliser une variable UniformGrid avec Rows définie sur 1 dans le modèle TabControl à la place de TabPanel. Bien sûr, vous devrez le reformater, mais ce n’est pas si grave.

18
Charlie

J'ai pu faire cela en utilisant un convertisseur comme celui-ci:

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

Puis en ajoutant l'espace de noms à mon xaml:

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

Pour que tous les objets TabItems soient utilisés, utilisez le convertisseur:

<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 est le x: nom de l'élément parent. Je veux que les onglets représentent 1/4 de, si cela a du sens.

6
Jordan H.

Cela est possible en liant la largeur à ActualWidth du contrôle d'onglet parent, comme indiqué ci-dessous.

Je l'ai enveloppé dans un style à appliquer à toutes les pages à onglet. 

<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

Je suis un gars de la vieille école. et préférez que ce type de fonctionnalité soit encapsulé dans le code du contrôle lui-même. Mon contrôle dérivé ressemble à ceci:

    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;
        }            
    }       
}

et mon XAML ressemble à

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

Quelqu'un peut-il expliquer pourquoi tout le monde préfère le contrôle de style au lieu de dériver.

2
Alex G

Je suivis la suggestion de Charlie et continuai sur une nouvelle voie. Voici une implémentation simple de TabControl qui divise l’espace disponible en parts égales entre ses TabItems, en utilisant UniformGrid:

XAML de contrôle

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

Code-Behind du contrôle

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;
      }
    }
  }
}

C'est tout. Vous pouvez maintenant ajouter TabItems à ce contrôle et ils ajusteront automatiquement leur largeur. Nul besoin de spécifier Grid.Column pour ces TabItems non plus, ils fonctionnent correctement sans lui, même au moment de la conception.

1
dotNET

Voici une solution indolore qui utilise uniquement des modèles:

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

J'espère que j'ai inclus toutes les couleurs et que cela fonctionnera pour vous. Ahh ... Snap! Mon effet de désaturation! Mon projet de démarrage WPF vous pouvez récupérer cet effet à partir de là si vous le souhaitez (il est plus facile de plop d'effet dans le déclencheur que de tout recolorer, comme dans les rehauts). Oui, c'est beaucoup de code, mais j'ai simplement modifié ItemsContainer pour une meilleure apparence, remplacé le contrôle d'en-tête standard par UniformGrid et défini les lignes ou les colonnes sur 1 selon TabStripPlacement. Maintenant, je peux réduire ce code ou le cacher quelque part. :)

1
zORg Alex

J'ai résolu ce problème en créant un convertisseur spécial:

    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();
    }
    }

Et je calcule la valeur d'un élément d'onglet dans l'élément Tag du TabControl, pour éviter de le calculer séparément pour chaque onglet. Voici l'exemple de code (notez que dans mon cas, j'avais besoin d'un ScrollViewer horizontal, car j'ai plusieurs éléments de tabulation et une largeur minimale):

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

Je peux dire que cela fonctionne comme un charme dans mon cas:) J'espère que quelqu'un le trouvera utile!

P.S. Je n'avais pas besoin/ne voulais d'aucun style dans mon cas.

1
XMight

J'utilise la solution suivante: Dans la fenêtre principale, j'utilise un événement redimensionné de la fenêtre et sur un événement initialisé tabcontrol pour définir la largeur de chaque onglet. Le nombre '5' correspond à mon nombre d'onglets. 

    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

Je ne sais pas si cela fonctionnera pour les onglets, mais chaque fois que j'ai besoin d'étirer quoi que ce soit pour remplir un conteneur, j'ai utilisé un ViewBox . Est-ce le genre de chose que vous recherchez?

0
Matthew Steeples

En plus de la solution acceptée de Ryan Versaw qui donne des largeurs d’en-tête tabItem égales, j’ai trouvé le moyen suivant de le rendre dépendant de la longueur de chaque en-tête.

Nous obtenons d’abord la chaîne de chaque en-tête tabItem en ajoutant cette ligne à la liaison multiple xaml. Ainsi cela devient:

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

Et un peu plus de code dans le convertisseur (values ​​[] obtient également l'en-tête 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;
    }

Je soupçonne qu’il pourrait exister un moyen plus efficace d’obtenir la chaîne AllHeaders de tous les en-têtes, mais cela fonctionne très bien tel quel ...

0
tombobadil