WPF:负边距在 ScrollViewer 中被截断

标签 wpf

我有一个 TabControl,它的样式和模板化方式是选项卡标题和选项卡内容由一条线分隔,但当前选定的选项卡打破了这条线(见图 1)。 enter image description here

这就像一个魅力,除了两件事。

第一个问题:在某些缩放状态下(不幸的是在默认状态下也是 100%)有一条非常细的线将选项卡标题与内容分开(见图 2;分隔高度线是 2px)。 enter image description here

它从何而来,我该如何摆脱它?

由于当前选定的选项卡稍后可能会出现左、上和右边框,我不能只增加负边距,因为左右边框在内容中是可见的。


第二个问题:如果我将选项卡标题放在 ScrollViewer 中以便能够水平滚动选项卡(以防选项卡太多),负 Margin 被剪裁并显示分隔线。 当然,ScrollViewer 的样式和模板化方式不使用内容下方的水平滚动条。

如何在 ScrollViewer 中使用负 Margin

我在下面的代码中注释掉了 ScrollViewer。请删除注释指示器并删除 ScrollViewerTabPanel 上的 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/

相关文章:

wpf - 如何让 WPF TextBlock 在多行上显示我的文本?

c# - 如何将字段绑定(bind)到用户控件

c# - 在 Visual Studio 外部运行时从 WPF 窗口中删除图标

c# - 用户是通过 UI 更改了该值,还是通过依赖属性更改了该值?

wpf - 事件在 WPF 中不起作用

wpf - 在 ListView 中显示分组项目的总和

c# - 如何为通用 Windows 应用程序设置固定窗口大小

wpf - 设置网格列的宽度/高度时, 'Auto' 和 '*' 有什么不同?

c# - Prism 6 中的 ViewModelLocator 不工作

wpf - 当您第一次进入单元格时,如何使 WPF Datagrid 选择一个单元格