2012-12-08 25 views
7

Tôi đã tạo một điều khiển người dùng dựa trên Grid (không phải DataGrid), được bao bọc trong một ScrollViewer. Bây giờ tôi muốn có khả năng hàng/cột đông lạnh giống như trong DataGrid, nhưng không thể tìm ra cách.WPF DataGrid nhận hàng/cột cố định hoạt động như thế nào?

Ai đó có thể cho tôi một số thông tin chi tiết về cách thực hiện trong WPF DataGrid?

+1

Bạn có ý nghĩa gì khi được cố định? Kích cỡ? – Joe

+0

Hàng/cột được cố định như trong DataGrid hoặc Excel, để các tiêu đề luôn hiển thị. Cụ thể hơn, tiêu đề cột ở trên cùng có thể cuộn theo chiều ngang, nhưng không được theo chiều dọc; tiêu đề hàng bên trái có thể cuộn theo chiều dọc nhưng không theo chiều ngang. – newman

Trả lời

0

Datagrid Column và Row có một tài sản gọi là "Frozen"

nếu bạn muốn đóng băng một cột tôi khuyên bạn nên làm như sau

hoặc là bạn muốn nó trên Row chọn hoặc cột sự kiện và sau đó trên Event Lấy Column/Row và đánh dấu nó như đông lạnh = true

hoặc tạo ra một nút hoặc một menu ngữ cảnh chuột nhấp chuột phải vào đó bạn Freeze/Bỏ cố định hiện đang được đánh dấu

cột/hàng

hy vọng điều này sẽ giúp

+0

Điều này sẽ không giúp được gì vì câu hỏi là một thứ khác. – Ramin

+0

Cảm ơn bạn đã nhập, Sagar, nhưng đó không phải là những gì tôi hỏi. – newman

4

Sau khi có vấn đề này một mình tôi muốn chia sẻ những gì tôi đã phát hiện cho đến nay.

DataGrid sử dụng hai phương pháp khác nhau cho điều đó.


đầu tiên: RowHeader


Đây là đơn giản Template cho 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> 

Như bạn thấy DataGrid sử dụng SelectiveScrollingOrientation tài sản gắn liền với giữ RowHeader trong Chức vụ. Nếu thuộc tính này được thiết lập (hoặc thay đổi), nó sẽ tạo ra một điều chỉnh TranslateTransform được điều chỉnh cho phụ huynh ScrollViewer Bù đắp cho phần tử. Xem chi tiết trong source code.


Thứ hai: Các FrozenColumns


thứ này diễn ra trong DataGridCellsPanelArrangeOverride(). Nó sử dụng một lớp học ArrangeState riêng "để duy trì trạng thái giữa việc sắp xếp nhiều trẻ em".

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; } 
} 

Sau khi khởi tạo trạng thái với

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; 
} 

nó gọi

ArrangeChild(children[childIndex] as UIElement, i, arrangeState); 

cho tất cả Childs nhận và tính toán chiều rộng ước tính cho những người không nhận ra Childs/cột.

double childSize = GetColumnEstimatedMeasureWidth(column, averageColumnWidth); 
arrangeState.NextNonFrozenCellStart += childSize; 

Khi kết thúc, giá trị sẽ được đặt trong các trường thích hợp trong 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); 
    } 
} 

Chi tiết cho ArrangeChild(UIElement child, int displayIndex, ArrangeState arrangeState) bạn có thể tìm thấy từ dòng 1470 trong source code.


Kết luận


Nó không cột làm cũng đơn giản được đông lạnh. Mặc dù điều này sẽ làm việc (ngoài cắt và cuộn qua toàn bộ chiều rộng)

<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> 

này sẽ không:

<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> 

Lý do là DataGridHelper.FindVisualParent<ScrollViewer>(element) (xem từ dòng 149 trong souce code) trong SelectiveScrollingOrientation attached property thất bại. Có thể bạn tìm giải pháp thay thế, ví dụ: tạo thuộc tính đính kèm của riêng bạn với một bản sao của mã gốc nhưng nhận được ScrollViewer theo tên. Nếu không tôi nghĩ bạn phải làm nhiều thứ từ đầu.

+0

Được rồi, tôi thấy một số đầu mối ở đó, nhưng tôi không thể làm cho nó hoạt động cho tôi. Bạn có thể vui lòng cho tôi thêm một số gợi ý không? – newman

+0

Vui lòng xem câu trả lời cập nhật của tôi sau khi gặp sự cố tương tự. – LPL

Các vấn đề liên quan