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而不重新排列行的主要内容,如果未能解决你的问题,请参考以下文章