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

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

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

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

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

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

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中,以便它们可以水平滚动.但是,正如您想象的那样,这不会很好,因为您必须向右滚动才能看到verticall滚动条.我确信有一种方法可以使它在右边保持冻结状态,但我还没弄明白.另一个问题是标题宽度必须与该列中任何单元格的最大可能宽度相匹配,或者所有内容都将关闭.这是向右滚动时显示的结果:

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

如果我给垂直滚动条左边的一个负边距(比如-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代码部分:

这是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>

使更改成为可能的重要部分是在代码片段的中途,我为ScrollBar设置了Margin =“ – 17,0,0,0”.

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

编辑#2:

请参阅上面更新的XAML代码.我做的是向ScrollContentPresenter添加Margin =“0,0,17,0”.

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

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

编辑#3:

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

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

编辑#4:

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

解决方法:

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

最后结果:

原谅凌乱的标题,我故意掩盖它们.如您所见,垂直滚动条在标题和位于底部的水平滚动条之间很好地排列.这是通过将垂直ScrollBar(位于模板的第一个网格中)的边距设置为左侧的-17来完成的.保证金= “ – 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”.

这是我的DataGrid和DataGridColumnHeader的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,保证金=“0,0,-17,0”.这实现了相同的结果.

上一篇:c# – Datagrid列排序生成错误


下一篇:c# – 如何防止将项添加到DataGrid?