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

Как обрабатывать групповой промежуточный итог и, например, целевые строки в WPF DataGrid?

Я реализую WPF DataGrid, который содержит проекты со многими ключевыми фигурами. Проекты сгруппированы по категориям проектов.

Для каждой категории должно быть:

  • строка, которая показывает в каждой строке столбца столбца сумму всех строк для столбца.
  • целевая строка, которая не является частью сетки источника данных, привязанной к ней. Целевая строка указывает каждому столбцу, что является целью для года (например, сколько денег там потратить).

Эти строки должны быть всегда сверху в каждой группе (сортировка фильтрации).

Моим первым решением было иметь эти данные в заголовке группы. Это нехорошее решение, потому что заголовок группы не поддерживает столбцы. то есть его следует построить, получив ширину столбцов.

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

DataGrid использует CollectionViewSource, поэтому он не заполняется кодом С#. В основном я расширяю этот пример: http://msdn.microsoft.com/en-us/library/ff407126.aspx

Спасибо и с наилучшими пожеланиями - matti

4b9b3361

Ответ 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 довольно легко справиться и с помощью специальной команды копирования.

Ответ 2

Одним из вариантов может быть добавление строк в источник данных со специальными значениями для имени и других полей, которые не имеют смысла, и использовать DataTrigger для отображения их со специальными цветами и, возможно, с некоторыми другими.

Фильтрация выполняется в С# в любом случае, поэтому она не влияет на эти строки.

Сортировка - единственная проблема здесь. Было бы здорово просто сказать, что некоторые строки всегда имеют порядок 0 и с порядком 1 в группе. Но я не знаю, как это сделать. Мне нужно сделать обычную сортировку в С# для всех столбцов, а не просто объявить сортировку:

<CollectionViewSource.SortDescriptions>
   <!-- Requires 'xmlns:scm="clr-namespace:System.ComponentModel;assembly=WindowsBase"' declaration. -->
    <scm:SortDescription PropertyName="ProjectName"/>
    <scm:SortDescription PropertyName="Complete" />
    <scm:SortDescription PropertyName="DueDate" />
</CollectionViewSource.SortDescriptions>

EDIT: помимо всего прочего, у него есть главный недостаток по сравнению с моим 1-м решением (сумма информации в заголовке группы), потому что при фильтрации изменений я должен обновлять суммы, которые будут вычисляться только для видимых строк.

Таким образом, этот ответ является полным взломом и не обладает всей элегантностью и не использует никаких приятных функций, которые WPF должен иметь: (