WPF Flexible TabControl标头

Urb*_*Esc 3 wpf xaml tabcontrol

我希望有一个TabControl多重TabItems.这些TabItems各有一个标题文本.这些文本的长度可能有很大差异(如5个字符长和15个字符长).

我希望TabControl仅将标题排成一行.

所有选项卡标题应使用相同的宽度,并且当有足够的可用空间时,我希望它们使用所有可用空间,最多为a MaxWidth,对所有项目都相同.

因此,如果我想对7个项目使用100的vMaxWidth`,则标签标题的宽度最大为700.如果有更多可用空间,则应忽略它.

如果可用空间较少,我希望在项目之间平均分配该空间.如果文本被切断,我想使用TextWrapping.

我现在尝试了多种解决这个问题的方法,这是我目前的设置:

<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>
Run Code Online (Sandbox Code Playgroud)

而且 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>
Run Code Online (Sandbox Code Playgroud)

当你调整默认值时,我正在使用a StackPanel而不是a TabPanel来摆脱"堆叠" TabControl.但是,我无法满足其他要求.我尝试将MaxWidth(而不是固定宽度)应用于TabItem标题,但这当然不起作用,因为项目缩小到其最小所需大小.

Sph*_*xxx 5

步骤1(第一次尝试):将标题放在一行中,并为每个标题赋予相同的宽度.

这可以通过使用UniformGrid而不是标准TabPanel 来实现,并将其行数锁定为1.这是您的TabControl样式的精简版本:

<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>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto" />
                        <RowDefinition Height="*" />
                    </Grid.RowDefinitions>

                    <Border>
                        <UniformGrid x:Name="HeaderPanel" IsItemsHost="True" 
                                     Rows="1" />
                    </Border>

                    <Border x:Name="Border" Grid.Row="1" 
                            BorderThickness="{TemplateBinding BorderThickness}"
                            Background="{TemplateBinding Background}"
                            BorderBrush="{TemplateBinding BorderBrush}">
                        <ContentPresenter x:Name="PART_SelectedContentHost" ContentSource="SelectedContent" />
                    </Border>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
Run Code Online (Sandbox Code Playgroud)

第2步:将标头限制为a MaxWidth并应用文本换行.

MaxWidth可以在设定TabItem的风格,连同HeaderTemplate其包装文本(您仍然可以使用您的自定义ControlTemplate链接样式的TabItem的部分):

<Style x:Key="Style-TabItem-Main" TargetType="{x:Type TabItem}">
    <Setter Property="MaxWidth" Value="100" />
    <!--https://social.msdn.microsoft.com/forums/vstudio/en-US/df4f7fc3-f0ec-4ed1-a022-a32650e49cb3/how-to-wrap-header-text-in-tabcontrol-->
    <Setter Property="HeaderTemplate" >
        <Setter.Value>
            <DataTemplate>
                <TextBlock Text="{Binding}" TextWrapping="Wrap" />
            </DataTemplate>
        </Setter.Value>
    </Setter>
    <Setter Property="Template">
        ...
    </Setter>
</Style>
Run Code Online (Sandbox Code Playgroud)


故障排除:现在,如果你MaxWidth步骤2中应用,你可能想要UniformGrid在TabControl太宽的时候左对齐..

<UniformGrid x:Name="HeaderPanel" IsItemsHost="True" 
             Rows="1" HorizontalAlignment="Left" />
Run Code Online (Sandbox Code Playgroud)

..但是当你尚未达到MaxWidth时你不希望这样,并且项目应该在TabControl的整个宽度上延伸(也就是步骤1).因此我们需要一种方法来切换,HorizontalAlignment具体取决于是否已达到项目的MaxWidth(如果已设置).

第1步(重访):让我们尝试制作自己的UniformGrid:

public class UniformTabPanel : UniformGrid
{
    public UniformTabPanel()
    {
        this.IsItemsHost = true;
        this.Rows = 1;

        //Default, so not really needed..
        this.HorizontalAlignment = HorizontalAlignment.Stretch;
    }

    protected override Size MeasureOverride(Size constraint)
    {
        var totalMaxWidth = this.Children.OfType<TabItem>().Sum(tab => tab.MaxWidth);
        if (!double.IsInfinity(totalMaxWidth))
        {
            this.HorizontalAlignment = (constraint.Width > totalMaxWidth) 
                                                ? HorizontalAlignment.Left 
                                                : HorizontalAlignment.Stretch;
        }

        return base.MeasureOverride(constraint);
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,我们可以UniformGrid在我们的TabControl风格中替换这个新面板:

                ...
                    <Border>
                        <mycontrols:UniformTabPanel x:Name="HeaderPanel" />
                    </Border>
                ...
Run Code Online (Sandbox Code Playgroud)

...并且TabControl应该像已经完成的那样运行.