DataGrid for WPF

时间:2018-04-03 22:43:04

标签: c# .net wpf wpfdatagrid

我想在顶部创建一个带有静态/冻结行的自定义DataGrid,类似于Excel的冻结行功能,无论您如何滚动,静态行始终保持最高位置。我遇到了Freeze DataGrid Row,但发现没有一个完整的解决方案。静态行还需要像所有其他行一样允许可重新排序的列。

以下是我尝试创建自定义DataGrid的方法。我找到了静态行显示的区域。 space between column headers and scroll content presenter

我尝试使用DataGridRow控件但无法显示/工作。也许我误解了这个控件是如何使用的,这是错误的方法?

错误的DataGridRow尝试

<DataGridRow Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="2" Item="{Binding StaticRow, RelativeSource={RelativeSource AncestorType={x:Type local:CustomDataGrid}}}" />

CustomDataGrid.xaml

我在DataGridColumnHeadersPresenter和ScrollContentPresenter之间有一个textblock占位符

<Style TargetType="{x:Type local:CustomDataGrid}">
    <Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
    <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
    <Setter Property="BorderBrush" Value="#FF688CAF"/>
    <Setter Property="BorderThickness" Value="1"/>
    <Setter Property="RowDetailsVisibilityMode" Value="VisibleWhenSelected"/>
    <Setter Property="ScrollViewer.CanContentScroll" Value="true"/>
    <Setter Property="ScrollViewer.PanningMode" Value="Both"/>
    <Setter Property="Stylus.IsFlicksEnabled" Value="False"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:CustomDataGrid}">
                <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="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}}}"/>

                                    <TextBlock Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="2">Static Row Here</TextBlock>

                                    <ScrollContentPresenter x:Name="PART_ScrollContentPresenter" CanContentScroll="{TemplateBinding CanContentScroll}" Grid.ColumnSpan="2" Grid.Row="2"/>
                                    <ScrollBar x:Name="PART_VerticalScrollBar" Grid.Column="2" Maximum="{TemplateBinding ScrollableHeight}" Orientation="Vertical" Grid.Row="2" Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}" Value="{Binding VerticalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" ViewportSize="{TemplateBinding ViewportHeight}"/>
                                    <Grid Grid.Column="1" Grid.Row="3">
                                        <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.Triggers>
        <MultiTrigger>
            <MultiTrigger.Conditions>
                <Condition Property="IsGrouping" Value="true"/>
                <Condition Property="VirtualizingPanel.IsVirtualizingWhenGrouping" Value="false"/>
            </MultiTrigger.Conditions>
            <Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
        </MultiTrigger>
    </Style.Triggers>
</Style>

CustomDataGrid.cs

public class CustomDataGrid : DataGrid
{
    static CustomDataGrid()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomDataGrid), new FrameworkPropertyMetadata(typeof(CustomDataGrid)));
    }

    public static readonly DependencyProperty StaticRowProperty = DependencyProperty.Register(
        "StaticRow", typeof(object), typeof(CustomDataGrid), new PropertyMetadata(default(object)));

    public object StaticRow
    {
        get { return GetValue(StaticRowProperty); }
        set { SetValue(StaticRowProperty, value); }
    }
}

1 个答案:

答案 0 :(得分:0)

有几种方法可以解决这个问题。 一种是拥有两个数据网格,一个在另一个之上。隐藏第二个的列标题。 顶部显示您的固定行,第二个显示您想要滚动的行。

这里有一些并发症。 您可能必须绑定列宽。 如果允许用户对列进行排序,则需要单击冻结数据网格中的标题,对第二个中显示非冻结行的集合进行排序。 您最上一行也没有滚动条。 这种方法的好处在于,您可以直接使用数据网格,而不会更改相当复杂的代码,并可能产生不必要的副作用。

另一个选择是看看Vincent Sibal的方法,也许可以做一些工作。 &#34; 注意:样本的目的仅用于学习目的。请不要在生产代码中使用它,因为它没有经过全面测试。&#34; https://blogs.msdn.microsoft.com/vinsibal/2008/10/31/wpf-datagrid-frozen-row-sample/

如果你能说服它可靠地工作,那看起来它将是一个更优雅的解决方案。