2012-01-06 37 views
13

Tôi đã tự hỏi nếu trong một DataFrid WPF trong .net 4.0, là nó có thể có một hàng tĩnh.Đóng băng DataGrid Row

Điều tôi cố gắng đạt được là tạo hàng tĩnh (hàng 0), sẽ luôn được hiển thị ở trên cùng khi lưới dữ liệu được cuộn xuống.

Ý tưởng là hàng 0 sẽ luôn ở chế độ xem khi người dùng cuộn qua DataGrid.

Cảm ơn bạn.

+0

Bạn có nghĩa là các cột? Hoặc bạn có nghĩa là các cột và hàng 0? – RvdK

+1

Đặt GridViewHeaderRowPresenter trong ScrollView với thanh cuộn ẩn. Đặt ItemsPresenter trong ScrollView thứ hai với cả hai thanh cuộn được bật. – Dotnet

+0

Không, ý tôi là hàng.Khi bạn di chuyển xuống biểu đồ dữ liệu, bạn sẽ mất chế độ xem của hàng 0. Nhưng tôi luôn muốn hàng 0 trong chế độ xem. Vì vậy, khi bạn cuộn để nói hàng hàng 360 0 sẽ vẫn ở dạng xem như một tiêu đề. Hy vọng rằng có ý nghĩa. – user101010101

Trả lời

0

Tôi không chắc chắn về các hàng nhưng bạn có thể cố định cột bằng cách sử dụng FrozenColumnCount. Bằng cách này, nó sẽ luôn luôn được hiển thị. Nên có một tài sản đóng băng.

+3

và sau đó sử dụng RotateTransform :) –

+2

là không có cách nào khác? Có vẻ kỳ lạ này không thể được thực hiện. – user101010101

+0

Không phải những gì tôi biết – Sulby

6

"Giải pháp đơn giản" này chỉ dành cho chân trang có thể giải phóng được, giải pháp tiêu đề đã đóng băng sẽ khác một chút (và thực sự dễ dàng hơn nhiều - chỉ cần chơi với HeaderTeamplate - đặt bảng ngăn xếp với nhiều mục được xếp chồng lên nhau theo ý muốn của bạn).

Vì vậy, tôi cần một hàng chân trang có thể làm lạnh được, tôi không thể tìm thấy bất cứ điều gì trong nhiều tháng, vì vậy cuối cùng tôi quyết định ngừng lười biếng và điều tra. Vì vậy, nếu bạn cần một chân, ý chính là tìm một vị trí trong Template của DataGrid giữa các hàng và scrollviewer ngang, nơi bạn có thể squeeze thêm Grid.Row với một ItemsControl với các tế bào.

KẾ HOẠCH BẮT BUỘC:

Đầu tiên, trích xuất mẫu DataGrid (Tôi đã sử dụng Blend). Khi việc làm quen với các mẫu, lưu ý các phần theo thứ tự:

PART_ColumnHeadersPresenter 
PART_ScrollContentPresenter 
PART_VerticalScrollBar 

ngay dưới PART_VerticalScrollBar, có một mạng lưới (Tôi sẽ đăng nó ở đây cho rõ ràng)

<Grid Grid.Column="1" Grid.Row="2"> 
    <Grid.ColumnDefinitions> 
     <ColumnDefinition Width="{Binding NonFrozenColumnsViewportHorizontalOffset, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"/> 
     <ColumnDefinition Width="*"/> 
    </Grid.ColumnDefinitions> 
    <ScrollBar x:Name="PART_HorizontalScrollBar" Grid.Column="1" Maximum="{TemplateBinding ScrollableWidth}" Orientation="Horizontal" Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}" Value="{Binding HorizontalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" ViewportSize="{TemplateBinding ViewportWidth}"/> 
</Grid> 

Đó là lưới tôi sửa đổi để bao gồm một hàng "freezable/footer". Tôi sẽ chỉ mã hóa cứng màu sắc, và thay thế Ràng buộc với hoperfully hữu ích "giả vờ" thuộc tính cho đơn giản (Tôi sẽ đánh dấu chúng "MyViewModel.SomeProperty vì vậy họ dễ dàng để xem):

<Grid Grid.Column="1" Grid.Row="2" x:Name="PART_DataGridColumnsVisualSpace"> 
    <Grid.ColumnDefinitions> 
     <ColumnDefinition Width="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}, Path=NonFrozenColumnsViewportHorizontalOffset}"/> 
     <ColumnDefinition Width="*"/> 
    </Grid.ColumnDefinitions> 
    <Grid.RowDefinitions> 
     <RowDefinition/> 
     <RowDefinition/> 
     <RowDefinition/> 
    </Grid.RowDefinitions> 
    <ScrollBar Grid.Column="2" Grid.Row="3" Name="PART_HorizontalScrollBar" Orientation="Horizontal" 
      Maximum="{TemplateBinding ScrollableWidth}" ViewportSize="{TemplateBinding ViewportWidth}" 
      Value="{Binding Path=HorizontalOffset, RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay}" 
      Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}"/> 

    <Border x:Name="PART_FooterRowHeader" Grid.Row="1" Height="30" Background="Gray" BorderBrush="Black" BorderThickness="0.5"> 
    <TextBlock Margin="4,0,0,0" VerticalAlignment="Center">MY FOOTER</TextBlock> 
    </Border> 
    <ItemsControl x:Name="PART_Footer" ItemsSource="{Binding MyViewModel.FooterRow}" 
       Grid.Row="1" Grid.Column="1" Height="30"> 
     <ItemsControl.ItemTemplate> 
      <DataTemplate> 
       <Border Background="Gray" BorderThickness="0,0,0.5,0.5" BorderBrush="Black"> 
        <!-- sticking a textblock as example, i have a much more complex control here--> 
        <TextBlock Text="{Binding FooterItemValue}"/> 
       </Border> 
      </DataTemplate> 
     </ItemsControl.ItemTemplate> 
     <ItemsControl.Template> 
      <ControlTemplate> 
       <ScrollViewer x:Name="PART_Footer_ScrollViewer" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden" 
          CanContentScroll="True" Focusable="false"> 
        <StackPanel IsItemsHost="True" Orientation="Horizontal"/> 
       </ScrollViewer> 
      </ControlTemplate> 
     </ItemsControl.Template> 
    </ItemsControl> 
</Grid> 

Cũng thêm vào đáp ứng DataGrid để di chuyển và thay đổi kích thước tiêu đề

<DataGrid ... ScrollViewer.ScrollChanged="OnDatagridScrollChanged" 

<Style TargetType="DataGridColumnHeader"> 
    <EventSetter Event="SizeChanged" Handler="OnDataColumnSizeChanged"/> 
</Style> 

Bây giờ, trở lại trong .xaml.cs

về cơ bản hai điều chính là cần thiết:

(1) đồng bộ cột nhà ng ze (để tương ứng với tế bào chân thay đổi kích thước) (2) đồng bộ DataGrid cuộn với chân cuộn

//syncs the footer with column header resize 
private void OnDatagridScrollChanged(object sender, ScrollChangedEventArgs e) 
{ 
    if (e.HorizontalChange == 0.0) return; 
    FooterScrollViewer.ScrollToHorizontalOffset(e.HorizontalOffset); 
} 

//syncs scroll 
private void OnDataColumnSizeChanged(object sender, SizeChangedEventArgs e) 
{ 
    //I don't know how many of these checks you need, skip if need to the gist 
    if (!_isMouseDown) return; 
    if (!_dataGridLoaded) return; 
    if (!IsVisible) return; 

    var header = (DataGridColumnHeader)sender; 
    var index = header.DisplayIndex - ViewModel.NumberOfHeaderColumns; 

    if (index < 0 || index >= FooterCells.Count) return; 

    FooterCells[index].Width = e.NewSize.Width; 
} 

//below referencing supporting properties: 
private ScrollViewer _footerScroll; 
private ScrollViewer FooterScrollViewer 
{ 
    get { 
     return _footerScroll ?? 
       (_footerScroll = myDataGrid.FindVisualChildByName<ScrollViewer>("PART_Footer_ScrollViewer")); 
     } 
} 

//added this so I don't have to hunt them down from XAML every time 
private List<Border> _footerCells; 
private List<Border> FooterCells 
{ 
    get 
    { 
     if (_footerCells == null) 
     { 
      var ic = myDataGrid.FindVisualChildByName<ItemsControl>("PART_Footer"); 
      _footerCells = new List<Border>(); 
      for (var i = 0; i < ic.Items.Count; i++) 
      { 
       var container = ic.ItemContainerGenerator.ContainerFromIndex(i);        
       var border = ((Visual)container).FindVisualChild<Border>(); 
       _footerCells.Add(border); 
      } 
     } 
     return _footerCells; 
    } 
} 

đó là nó! Tôi nghĩ phần quan trọng nhất là XAML để xem nơi bạn có thể đặt "hàng có thể tháo rời" của bạn, mọi thứ khác, như thao tác/đồng bộ hóa mọi thứ khá dễ dàng - gần như một lớp lót)

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