冻结DataGrid行 [英] Freeze DataGrid Row

查看:130
本文介绍了冻结DataGrid行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想知道如果在.net 4.0中的WPF数据网格中,是否可以有一个静态行。

I was wondering if in a WPF datagrid in .net 4.0, is it possible to have a static row.

我想要实现的是创建一个静态行(行0),当数据网格向下滚动时,它将始终显示在顶部。

What I am trying to achieve is to create a static row (row 0), that will always be displayed at the top when the data grid is scrolled down.

这个想法是当用户滚动数据网格时,行0将始终处于视图。

The idea being that row 0 will always be in view as the user scrolls through the datagrid.

感谢

推荐答案

这个简单解决方案仅适用于可冻结的页脚,冻结的头文件解决方案会有所不同(和实际上更容易 - 只需使用HeaderTeamplate - 放置一个堆栈面板,尽可能多的物品堆叠起来,如你所愿)。

This "Simple solution" is only for a freezable footer, the frozen header solution would be a bit different (and actually much easier - just play with the HeaderTeamplate - put a stack panel with as many items stacked up as you want).

所以我需要一个可以冻结的页脚排,几个月我找不到任何东西,所以终于决定停止懒惰和调查。

So I needed a footer row that is freezable, I couldn't find anything for months, so finally I decided to stop being lazy and investigate.

所以如果你需要一个页脚,这个要点就是在DataGrid的模板中找到一个位于行和水平滚动浏览器之间的位置,在这里可以使用ItemsControl来加载Grid.Row单元格。

So if you need a footer, the gist is find a place in DataGrid's Template between the rows and the horizontal scrollviewer where you can squeeze extra Grid.Row with an ItemsControl with Cells.

计划的攻击:

首先,提取DataGrid模板(我使用Blend)。熟悉模板时,请按顺序注意部分:

First, extract the DataGrid template (I used Blend). When getting familiarized with the template, note the parts in order:

 PART_ColumnHeadersPresenter
 PART_ScrollContentPresenter
 PART_VerticalScrollBar

在PART_VerticalScrollBar下面,有一个网格(为了清楚起见,我会在这里发布)

right under PART_VerticalScrollBar, there is a grid (I'll post it here for clarity)

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

这是我修改为包含freezable / footer row的网格。我将只是硬编码颜色,并为了简单而替代Binding与令人信服的假装属性(我会标记他们MyViewModel.SomeProperty,所​​以他们很容易看到):

That's the grid I modified to include a "freezable/footer row". I am going to just hard-code colors, and replace Binding with hoperfully helpful "pretend" properties for simplicity (I'll mark them "MyViewModel.SomeProperty so they are easy to see):

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

还添加到DataGrid回复滚动和标题大小

Also add to DataGrid respond to scroll and header resize

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

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

现在,回到.xaml.cs

Now, back in .xaml.cs

基本上需要两件主要的事情:

Basically two main things are needed:

(1)同步列调整大小(以便相应的页脚单元格调整大小)
(2)同步DataGrid滚动与页脚滚动

(1) sync column resize (so that corresponding footer cell resizes) (2) sync DataGrid scroll with footer scroll

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

就是这样!我认为最重要的部分是XAML看到你可以把你的可冻结的行,其他的一切,像操纵/同步的东西很容易 - 几乎一个衬垫)

that's it! I think the most important part is the XAML to see where you can put your "freezable row", everything else, like manipulating/sync'ing things is pretty easy - almost one liners)

这篇关于冻结DataGrid行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆