Подтвердить что ты не робот

Заморозить строку DataGrid

Мне было интересно, есть ли в WPF datagrid в .net 4.0, возможно ли иметь статическую строку.

Я пытаюсь создать статическую строку (строку 0), которая всегда будет отображаться вверху, когда сетка данных прокручивается вниз.

Идея состоит в том, что строка 0 всегда будет отображаться, когда пользователь прокручивается через datagrid.

Спасибо.

4b9b3361

Ответ 1

Это "простое решение" предназначено только для незамерзающего нижнего колонтитула, замороженное решение для заголовков будет немного отличаться (и на самом деле намного проще - просто играть с HeaderTeamplate - класть панель стека с таким количеством элементов, как вы хотите),

Итак, мне нужна строка нижнего колонтитула, которая является замороженной, я не мог найти ничего в течение нескольких месяцев, поэтому, наконец, я решил перестать лениться и исследовать.

Итак, если вам нужен нижний колонтитул, то он найдет место в шаблоне DataGrid между строками и горизонтальным scrollviewer, где вы можете выжать дополнительную Grid.Row с помощью ItemsControl с ячейками.

ПЛАН АТАКИ:

Сначала извлеките шаблон DataGrid (я использовал Blend). При ознакомлении с шаблоном обратите внимание на детали в порядке:

 PART_ColumnHeadersPresenter
 PART_ScrollContentPresenter
 PART_VerticalScrollBar

прямо под PART_VerticalScrollBar, есть сетка (я буду публиковать ее здесь для ясности)

<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, чтобы их было легко увидеть):

<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 ответ на изменение прокрутки и заголовка

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

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

Теперь вернемся .xaml.cs

В основном необходимы две основные вещи:

(1) изменение размера столбца с синхронизацией (так, чтобы соответствующая ячейка нижнего колонтитула изменялась)  (2) синхронизация прокрутки DataGrid с прокруткой нижнего колонтитула

//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, чтобы увидеть, где вы можете поместить свою "замораживаемую строку", все остальное, например, манипулирование/синхронизация вещей довольно просто - почти один лайнер)

Ответ 2

Я не уверен в строках, но вы можете заморозить столбцы, используя FrozenColumnCount. Таким образом, это всегда будет видно. Должно быть свойство замораживания.