我创建了一个基于 Grid(不是 DataGrid)的用户控件,该控件包含在 ScrollViewer 中。现在我想像在 DataGrid 中一样拥有冻结行/列的功能,但不知道如何。
有人可以告诉我它是如何在 WPF DataGrid 中完成的吗?
我创建了一个基于 Grid(不是 DataGrid)的用户控件,该控件包含在 ScrollViewer 中。现在我想像在 DataGrid 中一样拥有冻结行/列的功能,但不知道如何。
有人可以告诉我它是如何在 WPF DataGrid 中完成的吗?
在我自己遇到这个问题之后,我想分享我到目前为止发现的内容。
DataGrid
为此使用两种不同的方法。
第一个:RowHeader
这是简化Template
的DataGridRow
:
<Border x:Name="DGR_Border" ... >
<SelectiveScrollingGrid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<DataGridRowHeader Grid.RowSpan="2"
SelectiveScrollingGrid.SelectiveScrollingOrientation="Vertical" ... />
<DataGridCellsPresenter Grid.Column="1" ... />
<DataGridDetailsPresenter Grid.Column="1" Grid.Row="1"
SelectiveScrollingGrid.SelectiveScrollingOrientation="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}},
Path=AreRowDetailsFrozen, Converter={x:Static DataGrid.RowDetailsScrollingConverter},
ConverterParameter={x:Static SelectiveScrollingOrientation.Vertical}}" ... />
</SelectiveScrollingGrid>
</Border>
如您所见DataGrid
,使用SelectiveScrollingOrientation
附加属性将 RowHeader 保持在适当位置。如果此属性已设置(或更改),它会为元素创建TranslateTransform
与父级偏移量的适配绑定。ScrollViewer
请参阅源代码中的详细信息。
第二:FrozenColumns
这件事发生在. 它使用一个私有类“来维护多个孩子的排列之间的状态”。DataGridCellsPanel
ArrangeOverride()
ArrangeState
private class ArrangeState
{
public ArrangeState()
{
FrozenColumnCount = 0;
ChildHeight = 0.0;
NextFrozenCellStart = 0.0;
NextNonFrozenCellStart = 0.0;
ViewportStartX = 0.0;
DataGridHorizontalScrollStartX = 0.0;
OldClippedChild = null;
NewClippedChild = null;
}
public int FrozenColumnCount { get; set; }
public double ChildHeight { get; set; }
public double NextFrozenCellStart { get; set; }
public double NextNonFrozenCellStart { get; set; }
public double ViewportStartX { get; set; }
public double DataGridHorizontalScrollStartX { get; set; }
public UIElement OldClippedChild { get; set; }
public UIElement NewClippedChild { get; set; }
}
初始化状态后
private void InitializeArrangeState(ArrangeState arrangeState)
{
DataGrid parentDataGrid = ParentDataGrid;
double horizontalOffset = parentDataGrid.HorizontalScrollOffset;
double cellsPanelOffset = parentDataGrid.CellsPanelHorizontalOffset;
arrangeState.NextFrozenCellStart = horizontalOffset;
arrangeState.NextNonFrozenCellStart -= cellsPanelOffset;
arrangeState.ViewportStartX = horizontalOffset - cellsPanelOffset;
arrangeState.FrozenColumnCount = parentDataGrid.FrozenColumnCount;
}
它调用
ArrangeChild(children[childIndex] as UIElement, i, arrangeState);
对于所有已实现的孩子,并计算未实现的孩子/列的估计宽度。
double childSize = GetColumnEstimatedMeasureWidth(column, averageColumnWidth);
arrangeState.NextNonFrozenCellStart += childSize;
最后,这些值将设置在 中的相应字段中DataGrid
。
private void FinishArrange(ArrangeState arrangeState)
{
DataGrid parentDataGrid = ParentDataGrid;
// Update the NonFrozenColumnsViewportHorizontalOffset property of datagrid
if (parentDataGrid != null)
{
parentDataGrid.NonFrozenColumnsViewportHorizontalOffset = arrangeState.DataGridHorizontalScrollStartX;
}
// Remove the clip on previous clipped child
if (arrangeState.OldClippedChild != null)
{
arrangeState.OldClippedChild.CoerceValue(ClipProperty);
}
// Add the clip on new child to be clipped for the sake of frozen columns.
_clippedChildForFrozenBehaviour = arrangeState.NewClippedChild;
if (_clippedChildForFrozenBehaviour != null)
{
_clippedChildForFrozenBehaviour.CoerceValue(ClipProperty);
}
}
ArrangeChild(UIElement child, int displayIndex, ArrangeState arrangeState)
您可以从源代码中的第 1470 行找到详细信息。
结论
它不是简单的使列被冻结。即使这会起作用(除了整个宽度上的剪辑和滚动条)
<ListView ItemsSource="some rows">
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="Fixed"
Background="LightBlue" Width="300"
SelectiveScrollingGrid.SelectiveScrollingOrientation="Vertical" />
<TextBlock Grid.Column="1" Text="Scrolled"
Background="LightGreen" Width="300" />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
这不会:
<ScrollViewer HorizontalScrollBarVisibility="Auto">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="Fixed"
Background="LightBlue" Width="300"
SelectiveScrollingGrid.SelectiveScrollingOrientation="Vertical" />
<TextBlock Grid.Column="1" Text="Scrolled"
Background="LightGreen" Width="300" />
</Grid>
</ScrollViewer>
原因是DataGridHelper.FindVisualParent<ScrollViewer>(element)
(参见源代码中的第 149 行)SelectiveScrollingOrientation attached property
失败。也许您会找到解决方法,例如使用原始代码的副本创建您自己的附加属性,但 ScrollViewer
按名称获取。否则我认为你必须从头开始做很多事情。
Datagrid Column and Row 有一个名为“Frozen”的属性
如果您想冻结列,我建议您执行以下操作
您希望它在选定的行或列事件上,然后在事件上获取列/行并将其标记为 Frozen = true
或在鼠标右键单击时创建另一个按钮或上下文菜单,您可以在其上冻结/解冻当前标记
列/行
希望这可以帮助