WPF自定义TabItem模板后标签朝向与TabStripPlacement不匹配
WPF TabItem自定义模板后标签朝向不匹配TabStripPlacement的解决方法
问题复现
当前用于修改TabItem普通态、选中态背景样式的代码如下:
<TabControl.ItemContainerStyle> <Style TargetType="{x:Type TabItem}"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type TabItem}"> <Grid> <Border Name="Border" Margin="0,0,-4,0" Background="Transparent" BorderBrush="Silver" BorderThickness="1,1,1,1"> <ContentPresenter x:Name="ContentSite" VerticalAlignment="Center" HorizontalAlignment="Center" ContentSource="Header" Margin="12,2,12,2" RecognizesAccessKey="True"/> </Border> </Grid> <ControlTemplate.Triggers> <Trigger Property="IsSelected" Value="True"> <Setter Property="Panel.ZIndex" Value="100" /> <Setter TargetName="Border" Property="Background" Value="Transparent" /> <Setter TargetName="Border" Property="BorderThickness" Value="1,1,1,0" /> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style> </TabControl.ItemContainerStyle>
将TabControl的TabStripPlacement属性设置为Bottom时,TabPanel虽然停靠到控件底部,但TabItem样式仍和顶部停靠时一致,异常效果如下:
问题根因
WPF原生TabItem的默认ControlTemplate内置了针对父级TabControlTabStripPlacement属性(支持Top/Bottom/Left/Right四个枚举值)的适配逻辑,会根据标签停靠位置自动调整边框厚度、边距、内容朝向。重写ControlTemplate时丢失了这部分适配逻辑,所有场景下都只应用了标签停靠在顶部的样式规则,就会出现停靠位置和视觉效果不匹配的问题。
修复方法
在自定义ControlTemplate的触发器集合中,补充TabStripPlacement属性对应的适配规则,根据不同停靠位置调整边框、边距,左右停靠时添加旋转变换即可。
补全适配逻辑后的完整模板代码如下:
<TabControl.ItemContainerStyle> <Style TargetType="{x:Type TabItem}"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type TabItem}"> <Grid> <Border Name="Border" Margin="0,0,-4,0" Background="Transparent" BorderBrush="Silver" BorderThickness="1,1,1,1"> <ContentPresenter x:Name="ContentSite" VerticalAlignment="Center" HorizontalAlignment="Center" ContentSource="Header" Margin="12,2,12,2" RecognizesAccessKey="True"/> </Border> </Grid> <ControlTemplate.Triggers> <!-- 非选中状态默认样式 --> <Trigger Property="IsSelected" Value="False"> <Setter TargetName="Border" Property="Background" Value="Transparent"/> <Setter TargetName="Border" Property="BorderThickness" Value="1,1,1,1"/> </Trigger> <!-- 顶部停靠选中样式 --> <MultiTrigger> <MultiTrigger.Conditions> <Condition Property="IsSelected" Value="True"/> <Condition Property="TabStripPlacement" Value="Top"/> </MultiTrigger.Conditions> <Setter Property="Panel.ZIndex" Value="100"/> <Setter TargetName="Border" Property="Margin" Value="0,0,-4,0"/> <Setter TargetName="Border" Property="BorderThickness" Value="1,1,1,0"/> </MultiTrigger> <!-- 底部停靠选中样式 --> <MultiTrigger> <MultiTrigger.Conditions> <Condition Property="IsSelected" Value="True"/> <Condition Property="TabStripPlacement" Value="Bottom"/> </MultiTrigger.Conditions> <Setter Property="Panel.ZIndex" Value="100"/> <Setter TargetName="Border" Property="Margin" Value="0,-4,0,0"/> <Setter TargetName="Border" Property="BorderThickness" Value="1,0,1,1"/> </MultiTrigger> <!-- 左侧停靠通用样式 --> <Trigger Property="TabStripPlacement" Value="Left"> <Setter TargetName="ContentSite" Property="LayoutTransform"> <Setter.Value> <RotateTransform Angle="-270"/> </Setter.Value> </Setter> <Setter TargetName="Border" Property="Margin" Value="0,0,-4,0"/> </Trigger> <!-- 左侧停靠选中样式 --> <MultiTrigger> <MultiTrigger.Conditions> <Condition Property="IsSelected" Value="True"/> <Condition Property="TabStripPlacement" Value="Left"/> </MultiTrigger.Conditions> <Setter Property="Panel.ZIndex" Value="100"/> <Setter TargetName="Border" Property="BorderThickness" Value="1,1,0,1"/> </MultiTrigger> <!-- 右侧停靠通用样式 --> <Trigger Property="TabStripPlacement" Value="Right"> <Setter TargetName="ContentSite" Property="LayoutTransform"> <Setter.Value> <RotateTransform Angle="270"/> </Setter.Value> </Setter> <Setter TargetName="Border" Property="Margin" Value="-4,0,0,0"/> </Trigger> <!-- 右侧停靠选中样式 --> <MultiTrigger> <MultiTrigger.Conditions> <Condition Property="IsSelected" Value="True"/> <Condition Property="TabStripPlacement" Value="Right"/> </MultiTrigger.Conditions> <Setter Property="Panel.ZIndex" Value="100"/> <Setter TargetName="Border" Property="BorderThickness" Value="0,1,1,1"/> </MultiTrigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style> </TabControl.ItemContainerStyle>
适配规则说明
- Top(默认值):选中状态下隐藏下边框,标签右侧做-4像素偏移实现和相邻标签的重叠效果
- Bottom:选中状态下隐藏上边框,标签顶部做-4像素偏移,和下方内容区无缝衔接
- Left:选中状态下隐藏右边框,标签内容旋转-270度实现垂直显示
- Right:选中状态下隐藏左边框,标签内容旋转270度实现垂直显示,标签左侧做-4像素偏移
内容的提问来源于stack exchange,提问作者Chris Navarro
相关产品推荐
相关产品推荐

