如何在WPF中修改DataGrid垂直滚动条的位置?

时间:2014-02-04 22:13:20

标签: c# wpf datagrid scrollbar

已解决: 请使用XAML代码,屏幕截图和说明查看下面我自己的答案。

标题这一点有点困难,所以让我解释一下我的问题。我有一个具有已定义高度的数据网格,因此会出现滚动条。我想将垂直滚动条包含到排除标题的区域。虽然它只滚动数据行而不是标题,但在视觉上它覆盖了右边的整个数据网格区域。问题在于滚动条区域出现两个框(一个在上方和下方)。我不确定如何摆脱它们或如何将滚动条包含到数据网格的主体。

enter image description here

我唯一能够弄清楚(而且我不喜欢它的外观)是将DataGrid的背景设置为透明。结果如下:

enter image description here

如您所见,滚动条令人讨厌。然后,如果背景是透明的,那么水平滚动条和最后一行之间也存在间隙的问题:

enter image description here

还有一个解决方案可以摆脱这两个盒子的数据网格的背景颜色,使它们更加突出:

http://social.msdn.microsoft.com/Forums/vstudio/en-US/9fc4252b-38b1-4369-8d76-b6c5ae1e4df5/how-to-remove-the-blank-space-above-the-verticalscroolbar-of-datagrid-in-wpf?forum=wpf

类似的解决方案可以在这里找到: Annoying Square Where Scrollbars Meet

然而,它并没有摆脱滚动条在侧面笨拙地伸出的问题。

我测试的是将标题与正文分开并将正文放入垂直ScrollViewer,然后将标题和正文放入水平ScrollViewer中,以便它们可以水平滚动。但是,正如您想象的那样,这并不好用,因为您必须向右滚动才能看到垂直滚动条。我确定有一种方法可以使它在右边保持冻结状态,但我还没有想到它。另一个问题是标题宽度必须与该列中任何单元格的最大可能宽度相匹配,或者所有内容都将关闭。这是向右滚动时显示的结果:

enter image description here

我是控制模板的新手,所以我无法弄清楚这是否可行,因为我无法找到合适的组件:

如果我给垂直滚动条左边的一个负边距(比如-6,0,0,0)和一个类似大小的填充到单元格块的右边(0,0,6,0),垂直滚动条技术上应该向左移动。我会继续尝试并尝试解决这个问题,除非有人给我答案(这会很棒)。

编辑#1:

好吧,我取得了一些进展,并且能够将滚动条的边距设置为(-17,0,0,0)。 17似乎是滚动条的宽度。它的宽度似乎有一个特定的键:

http://msdn.microsoft.com/en-us/library/system.windows.systemparameters.verticalscrollbarwidthkey(v=vs.110).aspx

但我无法找到一种方法将其作为XAML中边距的负偏移值插入。在代码隐藏中做这件事并不难......但我宁愿把它全部保留在XAML中。无论如何,这里是进度和XAML代码部分的屏幕截图:

enter image description here

此处的XAML代码部分:

    <Style TargetType="{x:Type DataGrid}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type DataGrid}">
                    <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="True">
                        <ScrollViewer x:Name="DG_ScrollViewer" Focusable="false">
                            <ScrollViewer.Template>
                                <ControlTemplate TargetType="{x:Type ScrollViewer}">
                                    <Grid>
                                        <Grid.ColumnDefinitions>
                                            <ColumnDefinition Width="Auto"/>
                                            <ColumnDefinition Width="*"/>
                                            <ColumnDefinition Width="Auto"/>
                                        </Grid.ColumnDefinitions>
                                        <Grid.RowDefinitions>
                                            <RowDefinition Height="Auto"/>
                                            <RowDefinition Height="*"/>
                                            <RowDefinition Height="Auto"/>
                                        </Grid.RowDefinitions>
                                        <Button Command="{x:Static DataGrid.SelectAllCommand}" Focusable="false" Style="{DynamicResource {ComponentResourceKey ResourceId=DataGridSelectAllButtonStyle, TypeInTargetAssembly={x:Type DataGrid}}}" Visibility="{Binding HeadersVisibility, ConverterParameter={x:Static DataGridHeadersVisibility.All}, Converter={x:Static DataGrid.HeadersVisibilityConverter}, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" Width="{Binding CellsPanelHorizontalOffset, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"/>
                                        <DataGridColumnHeadersPresenter x:Name="PART_ColumnHeadersPresenter" Grid.Column="1" Visibility="{Binding HeadersVisibility, ConverterParameter={x:Static DataGridHeadersVisibility.Column}, Converter={x:Static DataGrid.HeadersVisibilityConverter}, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"/>
                                        <ScrollContentPresenter Margin="0,0,17,0" x:Name="PART_ScrollContentPresenter" CanContentScroll="{TemplateBinding CanContentScroll}" Grid.ColumnSpan="2" Grid.Row="1"/>
                                        <ScrollBar Margin="-17,0,0,0" x:Name="PART_VerticalScrollBar" Grid.Column="2" Maximum="{TemplateBinding ScrollableHeight}" Orientation="Vertical" Grid.Row="1" Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}" Value="{Binding VerticalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" ViewportSize="{TemplateBinding ViewportHeight}"/>
                                        <Grid Grid.Column="1" Grid.Row="2">
                                            <Grid.ColumnDefinitions>
                                                <ColumnDefinition Width="{Binding NonFrozenColumnsViewportHorizontalOffset, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"/>
                                                <ColumnDefinition Width="*"/>
                                            </Grid.ColumnDefinitions>
                                            <ScrollBar x:Name="PART_HorizontalScrollBar" Grid.Column="1" Maximum="{TemplateBinding ScrollableWidth}" Orientation="Horizontal" Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}" Value="{Binding HorizontalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" ViewportSize="{TemplateBinding ViewportWidth}"/>
                                        </Grid>
                                    </Grid>
                                </ControlTemplate>
                            </ScrollViewer.Template>
                            <ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                        </ScrollViewer>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

使更改成为可能的重要部分是在我设置Margin =&#34; -17,0,0,0&#34;的代码片段的中途。对于ScrollBar。

我目前的问题是我无法确定哪个组件向左偏移17(通过添加边距或填充)。到目前为止,我一直在弄乱所有人并且没有运气。我会在得到它后立即更新,除非有人在我之前说出来。就目前而言,滚动条将覆盖最后一列中的任何内容,直到我修复偏移量。

编辑#2:

请参阅上面更新的XAML代码。我做的是添加保证金=&#34; 0,0,17,0&#34;到ScrollContentPresenter。

我可以完全接受的一个副作用效果是,也可以抵消标题,但是在你向右滚动之前你不会看到它。它仅影响最后一列的标题,因为ScrollContentPresenter也将其偏移...奇怪的是,因为有一个DataGridColumnHeadersPresenter,但它独立工作......所以,我将继续处理它。不幸的是,ScrollContentPresenter没有填充,这就像魅力一样。所以,现在我必须弄清楚如何填充它,而不是设置边距,或找出不同的方法。

类似的方法是将水平ScrollBar(即第二个网格中的那个)的边距设置为0,0,-17,0。它将它向右移动17个单位。然后,将DataGridColumnHeaderPresenter的边距设置为0,0,-17,0。它会向右移动17个单位。

编辑#3:

对于任何感兴趣的人来说,这是另一种方法:

enter image description here

将垂直ScrollBar的边距设置为0,-22,0,-17。 -22是我标题的高度,因此请将其调整为您的标题。此方法拉伸滚动条以覆盖两个白框。

编辑#4:

我找到了解决方案。请参阅我对XAML代码的答案,截图和解释。

3 个答案:

答案 0 :(得分:6)

所以,上面我已经玩过几种方法,但是没有一种方法可以达到我想要的完美外观和填充效果。所以,这是我非常满意的解决方案。我希望它能帮助别人。我使用Blend来浏览模板代码的每一行,这是我的目的的最佳组合。

最终结果:

enter image description here

原谅凌乱的标题,我故意掩盖它们。如您所见,垂直滚动条在标题和位于底部的水平滚动条之间很好地排列。这是通过将垂直ScrollBar(位于模板的第一个网格中)的边距设置为左侧的-17来完成的。 Margin="-17,0,0,0"。然后,我将位于模板代码中垂直滚动条正上方的ScrollContentProperty边距设置为右侧的17 Margin="0,0,17,0,以确保垂直滚动条不包含任何内容。当我们滚动到最右边时,这使我们的标题有17个单位的空白空间,这是因为ScrollContentPresenter上的17个边距也影响了标题。为了解决这个问题,我为DataGridColumnHeader创建了一个样式,并将其边距设置为右侧的-17 Margin="0,0,-17,0",确保它渗透到空白区域。为了确保最后一个列标题文本没有悬停在垂直滚动条上,使其在视觉上没有吸引力,我在右侧添加了一个17的填充Padding="0,0,17,0"

以下是DataGridDataGridColumnHeader的XAML代码,可以实现这一目标:

<强>数据网格:

    <Style TargetType="{x:Type DataGrid}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type DataGrid}">
                    <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="True">
                        <ScrollViewer x:Name="DG_ScrollViewer" Focusable="false">
                            <ScrollViewer.Template>
                                <ControlTemplate TargetType="{x:Type ScrollViewer}">
                                    <Grid>
                                        <Grid.ColumnDefinitions>
                                            <ColumnDefinition Width="Auto"/>
                                            <ColumnDefinition Width="*"/>
                                            <ColumnDefinition Width="Auto"/>
                                        </Grid.ColumnDefinitions>
                                        <Grid.RowDefinitions>
                                            <RowDefinition Height="Auto"/>
                                            <RowDefinition Height="*"/>
                                            <RowDefinition Height="Auto"/>
                                        </Grid.RowDefinitions>
                                        <Button Command="{x:Static DataGrid.SelectAllCommand}" Focusable="false" Style="{DynamicResource {ComponentResourceKey ResourceId=DataGridSelectAllButtonStyle, TypeInTargetAssembly={x:Type DataGrid}}}" Visibility="{Binding HeadersVisibility, ConverterParameter={x:Static DataGridHeadersVisibility.All}, Converter={x:Static DataGrid.HeadersVisibilityConverter}, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" Width="{Binding CellsPanelHorizontalOffset, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"/>
                                        <DataGridColumnHeadersPresenter x:Name="PART_ColumnHeadersPresenter" Grid.Column="1" Visibility="{Binding HeadersVisibility, ConverterParameter={x:Static DataGridHeadersVisibility.Column}, Converter={x:Static DataGrid.HeadersVisibilityConverter}, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"/>
                                        <!--This is the scroll content presenter that gets shifted to the left 17 units so that scrollbar doesn't cover it-->
                                        <ScrollContentPresenter Margin="0,0,17,0" x:Name="PART_ScrollContentPresenter" CanContentScroll="{TemplateBinding CanContentScroll}" Grid.ColumnSpan="2" Grid.Row="1"/>
                                        <!--This is the vertical scrollbar. Margin is used to shift it to the left 17 units over the content-->
                                        <ScrollBar Margin="-17,0,0,0" x:Name="PART_VerticalScrollBar" Grid.Column="2" Maximum="{TemplateBinding ScrollableHeight}" Orientation="Vertical" Grid.Row="1" Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}" Value="{Binding VerticalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" ViewportSize="{TemplateBinding ViewportHeight}"/>
                                        <Grid Grid.Column="1" Grid.Row="2">
                                            <Grid.ColumnDefinitions>
                                                <ColumnDefinition Width="{Binding NonFrozenColumnsViewportHorizontalOffset, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"/>
                                                <ColumnDefinition Width="*"/>
                                            </Grid.ColumnDefinitions>
                                            <ScrollBar x:Name="PART_HorizontalScrollBar" Grid.Column="1" Maximum="{TemplateBinding ScrollableWidth}" Orientation="Horizontal" Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}" Value="{Binding HorizontalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" ViewportSize="{TemplateBinding ViewportWidth}"/>
                                        </Grid>
                                    </Grid>
                                </ControlTemplate>
                            </ScrollViewer.Template>
                            <ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                        </ScrollViewer>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

<强> DataGridColumnHeader:

    <Style TargetType="{x:Type DataGridColumnHeader}">
        <Setter Property="Height" Value="22"/>
        <!--Padding to shift header text of the last column to the left 17 units-->
        <Setter Property="Padding" Value="0,0,17,0"/>
        <!--Margin to shift the entire header to the right 17 units to fill the void-->
        <Setter Property="Margin" Value="0,0,-17,0"/>
    </Style>

类似的方法是将水平滚动条的边距设置为-17,Margin="0,0,-17,0",将DataGridColumnHeader的填充设置为17,Padding="0,0,17,0",并将其边距设置为-17,{{1} }。这实现了相同的结果。

答案 1 :(得分:1)

设置更好的解决方案 Grid.Row =&#34; 0&#34; Grid.RowSpan =&#34; 2&#34; 名称=&#34; PART_VerticalScrollBar&#34;

答案 2 :(得分:0)

DataGrid在此处将控件网格划分为3行3列的问题。这样:


                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="Auto"/>
                                <ColumnDefinition Width="*"/>
                                <ColumnDefinition Width="Auto"/>
                            </Grid.ColumnDefinitions>
                            <Grid.RowDefinitions>
                                <RowDefinition Height="Auto"/>
                                <RowDefinition Height="*"/>
                                <RowDefinition Height="Auto"/>
                            </Grid.RowDefinitions>

滚动条位于第二行的第三列。


<ScrollBar x:Name="PART_VerticalScrollBar" Grid.Column="2" Maximum="{TemplateBinding ScrollableHeight}" Orientation="Vertical" Grid.Row="1" Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}" Value="{Binding VerticalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" ViewportSize="{TemplateBinding ViewportHeight}"/>

由于第三行的高度是自动的,并且在第三列的第一行中没有放置任何内容,因此滚动条占用了整个空间。

我采用了默认模板,并在第三列第一行内放置了白色边框。 解决方案:

    <ControlTemplate x:Key="DataGridControlTemplate1" TargetType="{x:Type DataGrid}">
        <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="True">
            <ScrollViewer x:Name="DG_ScrollViewer" Focusable="False">
                <ScrollViewer.Template>
                    <ControlTemplate TargetType="{x:Type ScrollViewer}">
                        <Grid>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="Auto"/>
                                <ColumnDefinition Width="*"/>
                                <ColumnDefinition Width="Auto"/>
                            </Grid.ColumnDefinitions>
                            <Grid.RowDefinitions>
                                <RowDefinition Height="Auto"/>
                                <RowDefinition Height="*"/>
                                <RowDefinition Height="Auto"/>
                            </Grid.RowDefinitions>
                            <Button Command="ApplicationCommands.SelectAll" Focusable="False" Style="{DynamicResource {ComponentResourceKey ResourceId=DataGridSelectAllButtonStyle, TypeInTargetAssembly={x:Type DataGrid}}}" Width="{Binding CellsPanelHorizontalOffset, RelativeSource={RelativeSource FindAncestor, AncestorLevel=1, AncestorType={x:Type DataGrid}}}">
                                <Button.Visibility>
                                    <Binding Path="HeadersVisibility" RelativeSource="{RelativeSource FindAncestor, AncestorLevel=1, AncestorType={x:Type DataGrid}}">
                                        <Binding.ConverterParameter>
                                            <DataGridHeadersVisibility>All</DataGridHeadersVisibility>
                                        </Binding.ConverterParameter>
                                    </Binding>
                                </Button.Visibility>
                            </Button>
                            <DataGridColumnHeadersPresenter x:Name="PART_ColumnHeadersPresenter" Grid.Column="1">
                                <DataGridColumnHeadersPresenter.Visibility>
                                    <Binding Path="HeadersVisibility" RelativeSource="{RelativeSource FindAncestor, AncestorLevel=1, AncestorType={x:Type DataGrid}}">
                                        <Binding.ConverterParameter>
                                            <DataGridHeadersVisibility>Column</DataGridHeadersVisibility>
                                        </Binding.ConverterParameter>
                                    </Binding>
                                </DataGridColumnHeadersPresenter.Visibility>
                            </DataGridColumnHeadersPresenter>
                            <Border Background="White" BorderThickness="0" Grid.Column="2" />
                            <ScrollContentPresenter x:Name="PART_ScrollContentPresenter" CanContentScroll="{TemplateBinding CanContentScroll}" CanHorizontallyScroll="False" Grid.ColumnSpan="2" CanVerticallyScroll="False" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" ContentStringFormat="{TemplateBinding ContentStringFormat}" Grid.Row="1"/>
                            <ScrollBar x:Name="PART_VerticalScrollBar" Grid.Column="2" Maximum="{TemplateBinding ScrollableHeight}" Orientation="Vertical" Grid.Row="1" Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}" Value="{Binding VerticalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" ViewportSize="{TemplateBinding ViewportHeight}"/>
                            <Grid Grid.Column="1" Grid.Row="2">
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="{Binding NonFrozenColumnsViewportHorizontalOffset, RelativeSource={RelativeSource FindAncestor, AncestorLevel=1, AncestorType={x:Type DataGrid}}}"/>
                                    <ColumnDefinition Width="*"/>
                                </Grid.ColumnDefinitions>
                                <ScrollBar x:Name="PART_HorizontalScrollBar" Grid.Column="1" Maximum="{TemplateBinding ScrollableWidth}" Orientation="Horizontal" Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}" Value="{Binding HorizontalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" ViewportSize="{TemplateBinding ViewportWidth}"/>
                            </Grid>
                        </Grid>
                    </ControlTemplate>
                </ScrollViewer.Template>
                <ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
            </ScrollViewer>
        </Border>
    </ControlTemplate>