我創建了一個基於Grid(不是DataGrid)的用戶控件,該控件包裝在ScrollViewer中。現在我想要像DataGrid一樣凍結行/列的功能,但無法弄清楚。WPF DataGrid如何獲得凍結行/列的工作?
有人可以給我一些見解如何在WPF DataGrid中完成它?
我創建了一個基於Grid(不是DataGrid)的用戶控件,該控件包裝在ScrollViewer中。現在我想要像DataGrid一樣凍結行/列的功能,但無法弄清楚。WPF 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
偏移量。請參閱source code中的詳細信息。
第二: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 source code找到。
結論
它不是那麼簡單的決策列被凍結。儘管這將工作(除了剪裁和滾動條在整個寬度)
<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 souce code)在SelectiveScrollingOrientation attached property
失敗。也許你會找到解決方法,例如用原始代碼的副本創建自己的附屬財產,但按名稱獲得ScrollViewer
。否則,我認爲你必須從頭開始做很多事情。
你是什麼意思被凍結?尺寸? – Joe
像DataGrid或Excel中那樣凍結行/列,以便標題始終可見。更具體地說,頂部的列標題可以水平滾動,但不是垂直滾動;左側的行標題可以垂直滾動,但不能水平滾動。 – newman