我有一个 TabControl
,它的样式和模板化方式是选项卡标题和选项卡内容由一条线分隔,但当前选定的选项卡打破了这条线(见图 1)。
这就像一个魅力,除了两件事。
第一个问题:在某些缩放状态下(不幸的是在默认状态下也是 100%)有一条非常细的线将选项卡标题与内容分开(见图 2;分隔高度线是 2px)。
它从何而来,我该如何摆脱它?
由于当前选定的选项卡稍后可能会出现左、上和右边框,我不能只增加负边距,因为左右边框在内容中是可见的。
第二个问题:如果我将选项卡标题放在 ScrollViewer
中以便能够水平滚动选项卡(以防选项卡太多),负 Margin
被剪裁并显示分隔线。
当然,ScrollViewer
的样式和模板化方式不使用内容下方的水平滚动条。
如何在 ScrollViewer
中使用负 Margin
?
我在下面的代码中注释掉了 ScrollViewer
。请删除注释指示器并删除 ScrollViewer
内 TabPanel
上的 Margin
以查看实际问题。
这是我的样式、模板和代码,以备不时之需:
<Style x:Key="TabControlStyle" TargetType="{x:Type TabControl}">
<Setter Property="Background" Value="LightGoldenrodYellow" />
<Setter Property="BorderBrush" Value="Gray" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabControl}">
<Grid SnapsToDevicePixels="True"
Background="{TemplateBinding Background}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Border x:Name="Content"
Grid.Row="1" Grid.Column="0"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="0,2,0,0"
Background="White">
<ContentPresenter x:Name="PART_SelectedContentHost"
ContentSource="SelectedContent"
Margin="{TemplateBinding Padding}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</Border>
<!--<ScrollViewer Grid.Row="0" Grid.Column="0" Margin="5,5,5,0">-->
<TabPanel x:Name="PART_ScrollContentPresenter"
Grid.Row="0" Grid.Column="0"
Margin="5,5,5,0"
IsItemsHost="True" />
<!--</ScrollViewer>-->
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="TabItemStyle" TargetType="{x:Type TabItem}">
<Setter Property="Background" Value="LightGray" />
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="BorderThickness" Value="1,1,1,0" />
<Setter Property="BorderBrush" Value="Gray" />
<Setter Property="MinWidth" Value="50" />
<Setter Property="Margin" Value="0,0,5,0" />
<Setter Property="Padding" Value="0" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Grid SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
Margin="{TemplateBinding Margin}">
<Border x:Name="Border"
Background="{TemplateBinding Background}"
BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="{TemplateBinding Background}">
<TextBlock x:Name="TabTitle"
Margin="16,6"
Text="{TemplateBinding Header}"
HorizontalAlignment="Center"
VerticalAlignment="Center"
TextWrapping="NoWrap"
TextTrimming="CharacterEllipsis" />
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="White" TargetName="Border" />
<Setter Property="BorderBrush" Value="Gray" TargetName="Border" />
<Setter Property="Margin" Value="0,0,2,-2" />
<Setter Property="Padding" Value="0,-2,0,0" />
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsMouseOver" Value="True" />
<Condition Property="IsSelected" Value="False" />
</MultiTrigger.Conditions>
<Setter Property="Background" Value="Gray" TargetName="Border" />
<Setter Property="BorderBrush" Value="Gray" TargetName="Border" />
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication"
Title="MainWindow"
Height="350" Width="525">
<Window.LayoutTransform>
<ScaleTransform ScaleX="1" ScaleY="1" />
</Window.LayoutTransform>
<TabControl Style="{StaticResource TabControlStyle}"
ItemContainerStyle="{StaticResource TabItemStyle}">
<TabItem Header="Tab 1" />
<TabItem Header="Tab Two" />
<TabItem Header="Tab III" />
</TabControl>
</Window>
感谢您的宝贵时间和帮助。
最佳答案
关于您的第一个问题,您可以通过将边框与内容分开来增加负边距:
<Grid SnapsToDevicePixels="True" Background="{TemplateBinding Background}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<!--SeparatorLine will be rendered on bottom-->
<Border x:Name="SeparatorLine"
Grid.Row="1" Grid.Column="0"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="0,2,0,0">
</Border>
<!--Tabs will be rendered on top of the SeparatorLine-->
<TabPanel x:Name="PART_ScrollContentPresenter"
Grid.Row="0" Grid.Column="0"
Margin="5,5,5,0"
IsItemsHost="True" />
<!--Content will be rendered on top. Content.Margin should equal the SeparatorLine.BorderThickness-->
<Border x:Name="Content"
Grid.Row="1" Grid.Column="0"
Margin="0,2,0,0"
Background="White">
<ContentPresenter x:Name="PART_SelectedContentHost"
ContentSource="SelectedContent"
Margin="{TemplateBinding Padding}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</Border>
</Grid>
现在您可以在 TabItem
中随意使用大于内容边框大小的负边距。
第二个问题也可以用负边距解决...据我所知,无论您多么想要它,您都不会获得允许任何内容溢出的默认 Scrollviewer。参见 WPF clipping even when no clipping is desired - how to turn it off?就该主题进行一些讨论。
您可以做的是以负边距增加滚动查看器的大小,这样实际的项目将留在支持的区域内:
<ScrollViewer Grid.Row="0" Grid.Column="0" Margin="5,5,5,-3" VerticalScrollBarVisibility="Disabled">
<TabPanel x:Name="PART_ScrollContentPresenter"
Grid.Row="0" Grid.Column="0"
Margin="0,0,0,3"
IsItemsHost="True" />
</ScrollViewer>
此示例将允许 TabItem
上的负底部边距最多为 3 px。
关于WPF:负边距在 ScrollViewer 中被截断,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46316534/