WPF DataGrid 如何让冻结的行/列工作?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13774417/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How does WPF DataGrid get frozen rows/columns working?
提问by newman
I created a user control based on Grid (not DataGrid), which is wrapped in a ScrollViewer. Now I would like to have frozen rows/columns capability just like in DataGrid, but couldn't figure out how.
我创建了一个基于 Grid(不是 DataGrid)的用户控件,它被包装在一个 ScrollViewer 中。现在我想像在 DataGrid 中一样具有冻结行/列的功能,但不知道如何。
Can somebody give me some insight how it is done in WPF DataGrid?
有人可以让我了解一下它是如何在 WPF DataGrid 中完成的吗?
回答by LPL
After having this problem by myself I want to share what I've found out so far.
在自己遇到这个问题之后,我想分享我迄今为止发现的内容。
DataGriduses two different methods for that.
DataGrid为此使用两种不同的方法。
First: The RowHeader
第一:行标题
This is the simplified Templatefor DataGridRow:
这是简化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>
As you can see DataGriduses the SelectiveScrollingOrientationattached property to hold the RowHeader in position. If this property is set (or changing) it creates an adapted TranslateTransformbound to the parental ScrollViewerOffset for the element. See the details in source code.
如您所见,DataGrid使用SelectiveScrollingOrientation附加属性将 RowHeader 固定到位。如果设置(或更改)此属性,它会为元素创建一个TranslateTransform到父ScrollViewer偏移量的自适应绑定。请参阅源代码中的详细信息。
Second: The FrozenColumns
第二个:FrozenColumns
This stuff takes place in DataGridCellsPanelArrangeOverride(). It uses a private ArrangeStateclass "to maintain state between arrange of multiple children".
这件事发生在. 它使用一个私有类“在多个孩子的安排之间维护状态”。DataGridCellsPanelArrangeOverride()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; }
}
After initializing the state with
初始化状态后
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;
}
it calls
它叫
ArrangeChild(children[childIndex] as UIElement, i, arrangeState);
for all realized childs and calculates the estimated width for non realized childs/columns.
对于所有已实现的子项并计算未实现的子项/列的估计宽度。
double childSize = GetColumnEstimatedMeasureWidth(column, averageColumnWidth);
arrangeState.NextNonFrozenCellStart += childSize;
At the end the values will be set in the appropriate fields in DataGrid.
最后,这些值将在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);
}
}
The details for ArrangeChild(UIElement child, int displayIndex, ArrangeState arrangeState)you can find from line 1470 in source code.
ArrangeChild(UIElement child, int displayIndex, ArrangeState arrangeState)您可以从源代码中的第 1470 行找到详细信息。
Conclusion
结论
It's not as simple making columns are frozen. Even though this will work (apart from clipping and scrollbar over whole width)
不是让列被冻结那么简单。即使这会起作用(除了在整个宽度上剪切和滚动条)
<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>
this will not:
这不会:
<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>
The reason is that DataGridHelper.FindVisualParent<ScrollViewer>(element)(see from line 149 in souce code) in SelectiveScrollingOrientation attached propertyfails. Maybe you find workarounds e.g. create your own attached property with a copy of the original code but get the ScrollViewerby name. Otherwise I think you have to do many things from scratch.
原因是DataGridHelper.FindVisualParent<ScrollViewer>(element)(参见源代码中的第 149 行) inSelectiveScrollingOrientation attached property失败。也许您会找到解决方法,例如使用原始代码的副本创建您自己的附加属性,但ScrollViewer按名称获取 。否则我认为你必须从头开始做很多事情。
回答by Sagar Modi
Datagrid Column and Row has a property called "Frozen"
Datagrid Column 和 Row 有一个名为“Frozen”的属性
if you want to freeze a column i recommend you do the following
如果您想冻结一列,我建议您执行以下操作
either you want it on selected Row or Column Event and then on the Event Get the Column/Row and mark it as Frozen = true
您希望在选定的行或列事件上使用它,然后在事件上获取列/行并将其标记为 Frozen = true
or create another button or a context menu on mouse right click on which you Freeze/Unfreeze the currently marked
或在鼠标右键单击时创建另一个按钮或上下文菜单,您可以冻结/解冻当前标记的
column/row
列/行
hope this helps
希望这可以帮助

