WPF多行TabControl而不重新排列行

Posted

技术标签:

【中文标题】WPF多行TabControl而不重新排列行【英文标题】:WPF multi-line TabControl without rearranging rows 【发布时间】:2011-07-29 04:07:36 【问题描述】:

当水平尺寸太小时,带有默认 TabPanel 的 WPF TabControl 将选项卡项排列成多行。然后tab选择改变了这些行的顺序,所以选中的tab项总是在第一行。

我发现了几篇关于如何用另一个项目控件替换 TabPanel 的文章,这样它们就可以滚动标签而不是多行行为。

我想保留多行(不滚动),但禁用行的重新排列。创建选项卡后,无论选择如何更改,它们都应保持在原位。这可能吗?

【问题讨论】:

这可能是可能的,但请注意,如果您在上面一行中选择一个选项卡并且行不切换,那么您有一个与选项卡断开连接的选项卡标题(这可能很尴尬)。那真的是你想要的吗?? 你可能是对的,但我也自定义了它的外观,在这种特殊情况下,断开连接不是问题。 这里也是个问题,可惜没有解决方案。多行选项卡的行切换会阻止眼睛记住它们的模式,并且通过拖动来重新排序变得困难。它会引起人们的注意,一旦被认可可能会令人沮丧。 【参考方案1】:

您是否尝试过用类似的方式覆盖默认样式?即:使用 wrappanel 而不是 TabPanel?

<Style x:Key="x:Type TabControl" TargetType="x:Type TabControl">        
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="x:Type TabControl">                    
                <Grid TabNavigation="Local" SnapsToDevicePixels="true" ClipToBounds="true">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Name="ColumnDefinition0" />
                        <ColumnDefinition Name="ColumnDefinition1" Width="0" />
                    </Grid.ColumnDefinitions>
                    <Grid.RowDefinitions>
                        <RowDefinition Name="RowDefinition0" Height="Auto" />
                        <RowDefinition Name="RowDefinition1" Height="*" />
                    </Grid.RowDefinitions>
                    <WrapPanel Name="HeaderPanel" ZIndex="1" TabIndex="1" Column="0" Row="0" Margin="2,2,2,0" IsItemsHost="true" />
                    <Border Name="ContentPanel" Background="TemplateBinding Background" BorderThickness="TemplateBinding BorderThickness" BorderBrush="TemplateBinding BorderBrush" TabNavigation="Local" DirectionalNavigation="Contained" TabIndex="2" Column="0" Row="1">
                        <ContentPresenter Name="PART_SelectedContentHost" SnapsToDevicePixels="TemplateBinding SnapsToDevicePixels" Margin="TemplateBinding Padding" ContentSource="SelectedContent" />
                    </Border>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

【讨论】:

【参考方案2】:

我找到的唯一解决方案是修改框架的 TabPanel 类,使其int GetActiveRow(int[] solution) 方法始终返回 0。虽然这解决了问题,但我不确定以这种方式使用框架的源是否合法。

【讨论】:

【参考方案3】:

我认为 vigoo 的回答不完整。 int GetActiveRow(int[] solution)System.Windows.Controls.Primitives namespace 内部 TabPanel 类的私有方法。因此,您必须从 WPF 源代码(可在WPF source github 获得)创建 TabPanel 类的副本,并将其放置在新的命名空间中。

// Returns the row which contain the child with IsSelected==true
    private int GetActiveRow(int[] solution)
    
        // Prevent Tabs from re-ordering when selecting a tab
        return 0;
        /*int activeRow = 0;
        int childIndex = 0;
        if (solution.Length > 0)
        
            foreach (UIElement child in InternalChildren)
            
                if (child.Visibility == Visibility.Collapsed)
                    continue;

                bool isActiveTab = (bool)child.GetValue(Selector.IsSelectedProperty);

                if (isActiveTab)
                
                    return activeRow;
                

                if (activeRow < solution.Length && solution[activeRow] == childIndex)
                
                    activeRow++;
                

                childIndex++;
            
        

        // If the is no selected element and aligment is Top  - then the active row is the last row 
        if (TabStripPlacement == Dock.Top)
        
            activeRow = _numRows - 1;
        

        return activeRow;*/
    

然后为 TabControl 创建一个模板,并在模板中引用您的新 TabPanel(我在这里称之为overrides:TabPanel)。不要忘记在 ResourceDictionary(或定义新样式的任何位置)xmlns:overrides="clr-namespace:MyNamespace.WPF.Overrides" 中添加对新 TabPanel 类的引用。

<Style x:Key="staticTabs"
       TargetType="x:Type TabControl">
    <Setter Property="Padding" Value="2" />
    <Setter Property="HorizontalContentAlignment" Value="Center" />
    <Setter Property="VerticalContentAlignment" Value="Center" />
    <Setter Property="Background" Value="StaticResource TabItem.Selected.Background" />
    <Setter Property="BorderBrush" Value="StaticResource TabItem.Selected.Border" />
    <Setter Property="BorderThickness" Value="1" />
    <Setter Property="Foreground" Value="DynamicResource x:Static SystemColors.ControlTextBrushKey" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="x:Type TabControl">
                <Grid x:Name="templateRoot"
                      ClipToBounds="true"
                      KeyboardNavigation.TabNavigation="Local"
                      SnapsToDevicePixels="true">
                    <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>
                    <overrides:TabPanel x:Name="headerPanel"
                              Grid.Row="0"
                              Grid.Column="0"
                              Margin="2,2,2,0"
                              Panel.ZIndex="1"
                              Background="Transparent"
                              Grid.IsSharedSizeScope="True"
                              IsItemsHost="true"
                              KeyboardNavigation.TabIndex="1" />
                    <Border x:Name="contentPanel"
                            Grid.Row="1"
                            Grid.Column="0"
                            Background="TemplateBinding Background"
                            BorderBrush="TemplateBinding BorderBrush"
                            BorderThickness="TemplateBinding BorderThickness"
                            KeyboardNavigation.DirectionalNavigation="Contained"
                            KeyboardNavigation.TabIndex="2"
                            KeyboardNavigation.TabNavigation="Local">
                        <ContentPresenter x:Name="PART_SelectedContentHost"
                                          Margin="TemplateBinding Padding"
                                          ContentSource="SelectedContent"
                                          SnapsToDevicePixels="TemplateBinding SnapsToDevicePixels" />
                    </Border>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

最后,您的 Tab 控件将引用这个新模板:

<TabControl Style="StaticResource staticTabs" />

【讨论】:

以上是关于WPF多行TabControl而不重新排列行的主要内容,如果未能解决你的问题,请参考以下文章

在C#生成的winform中加tab,求解!!!

WPF SelectedIndex 设置 TabControl 的问题

重新排序 WPF TabControl 中的选项卡

C# WPF TabControl用法指南(精品)

WPF TabControl Unload俩次的解决方案

WPF的页面导航