我想在顶部创建一个带有静态/冻结行的自定义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); }
}
}
答案 0 :(得分:0)
有几种方法可以解决这个问题。 一种是拥有两个数据网格,一个在另一个之上。隐藏第二个的列标题。 顶部显示您的固定行,第二个显示您想要滚动的行。
这里有一些并发症。 您可能必须绑定列宽。 如果允许用户对列进行排序,则需要单击冻结数据网格中的标题,对第二个中显示非冻结行的集合进行排序。 您最上一行也没有滚动条。 这种方法的好处在于,您可以直接使用数据网格,而不会更改相当复杂的代码,并可能产生不必要的副作用。
另一个选择是看看Vincent Sibal的方法,也许可以做一些工作。 &#34; 注意:样本的目的仅用于学习目的。请不要在生产代码中使用它,因为它没有经过全面测试。&#34; https://blogs.msdn.microsoft.com/vinsibal/2008/10/31/wpf-datagrid-frozen-row-sample/
如果你能说服它可靠地工作,那看起来它将是一个更优雅的解决方案。