Ответ 1
У меня есть объединенный DataGrid с группами промежуточных строк в одном из моих проектов. Мы не беспокоились о некоторых проблемах, которые вы вызываете, например о скрытии и сортировке столбцов, поэтому я точно не знаю, может ли он быть расширен для этого. Я также понимаю, что могут быть проблемы с производительностью, которые могут быть проблемой при работе с большими наборами (мое окно работает с 32 отдельными DataGrids - ouch). Но это другое направление от других решений, которые я видел, поэтому я подумал, что брошу его сюда и посмотрю, поможет ли он вам.
Мое решение состоит из двух основных компонентов:
1. Строки промежуточного итога не являются строками в основном DataGrid, а являются отдельными DataGrids. У меня есть 2 дополнительных сетки в каждой группе: 1 в заголовке, который отображается только тогда, когда группа рухнула, а другая - под пунктом ItemsPresenter. Элемент ItemsSource для промежуточных DataGrids поступает из конвертера, который берет элементы в группе и возвращает общую модель представления. Столбцы промежуточных сеток точно такие же, как основная сетка (заполнены в DataGrid_Loaded, хотя я уверен, что это можно сделать и в xaml тоже).
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander Background="Gray" HorizontalAlignment="Left" IsExpanded="True"
ScrollViewer.CanContentScroll="True">
<Expander.Header>
<DataGrid Name="HeaderGrid" ItemsSource="{Binding Path=., Converter={StaticResource SumConverter}}"
Loaded="DataGrid_Loaded" HeadersVisibility="Row"
Margin="25 0 0 0" PreviewMouseDown="HeaderGrid_PreviewMouseDown">
<DataGrid.Style>
<Style TargetType="DataGrid">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=Expander}, Path=IsExpanded}"
Value="True">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.Style>
</DataGrid>
</Expander.Header>
<StackPanel>
<ItemsPresenter/>
<DataGrid Name="FooterGrid" ItemsSource="{Binding ElementName=HeaderGrid, Path=ItemsSource, Mode=OneWay}"
Loaded="DataGrid_Loaded" HeadersVisibility="Row"
Margin="50 0 0 0">
<DataGrid.Style>
<Style TargetType="DataGrid">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=Expander}, Path=IsExpanded}"
Value="False">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid>
</StackPanel>
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
2. Тогда проблема заключается в том, как заставить все DataGrids вести себя так, как если бы они были единой сеткой. Я обработал это путем подкласса DataGridTextColumn
(у нас есть только текст в этом случае, но другие типы столбцов тоже должны работать) в классе с именем DataGridSharedSizeTextColumn
, который имитирует поведение SharedSizeGroup класса Grid. Он имеет свойство строковой зависимости с именем группы и отслеживает все столбцы в одной группе. Когда Width.DesiredValue
изменяется в одном столбце, я обновляю MinWidth во всех остальных столбцах и принудительно обновляю его с помощью DataGridOwner.UpdateLayout()
. Этот класс также охватывает переупорядочение столбцов и обновляет группу, всякий раз, когда изменяется DisplayIndex. Я бы подумал, что этот метод также будет работать с любым другим свойством столбца, если у него есть сеттер.
Были и другие неприятные вещи, которые можно было решить с помощью выбора, копирования и т.д. Но оказалось, что с событиями MouseEntered и MouseLeave довольно легко справиться и с помощью специальной команды копирования.