2012-12-08 40 views
7

我創建了一個基於Grid(不是DataGrid)的用戶控件,該控件包裝在ScrollViewer中。現在我想要像DataGrid一樣凍結行/列的功能,但無法弄清楚。WPF DataGrid如何獲得凍結行/列的工作?

有人可以給我一些見解如何在WPF DataGrid中完成它?

+1

你是什麼意思被凍結?尺寸? – Joe

+0

像DataGrid或Excel中那樣凍結行/列,以便標題始終可見。更具體地說,頂部的列標題可以水平滾動,但不是垂直滾動;左側的行標題可以垂直滾動,但不能水平滾動。 – newman

回答

0

DataGrid列和行有一個叫做財產「凍結」

如果要凍結一個專欄中,我建議你執行以下操作

無論你想它選擇的行或列的事件,然後在事件獲取列/行並將其標記爲凍結=真

或創建另一個按鈕或鼠標右鍵菜單右鍵點擊您凍結/解凍當前標記

行/列上

希望這有助於

+0

這不會幫助,因爲問題是別的。 – Ramin

+0

感謝您的輸入,薩加爾,但那不是我問的。 – newman

4

自己有這個問題後,我想分享我迄今發現的。

DataGrid對此使用了兩種不同的方法。


第一:的rowHeader


這是簡化TemplateDataGridRow

<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


這東西發生在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; } 
} 

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。否則,我認爲你必須從頭開始做很多事情。

+0

好的,我在那裏看到一些線索,但我無法讓它爲我工作。你能給我一些進一步的提示嗎? – newman

+0

遇到同樣的問題後,請看我更新的答案。 – LPL