none
WPF - Группировка строк DataGrid с источником данных DataTable RRS feed

  • Вопрос

  • Здравствуйте! 

    Не получается выполнить группировку строк в DataGrid, где источник данных DataTable. 

    1. Создаю в XAML CollectionViewSource и привязываю его к DataTable, указав какой столбец DataTable необходимо использовать для группировки.

    <Window.Resources>
            <ResourceDictionary>
                <ResourceDictionary.MergedDictionaries>
                    <ResourceDictionary Source="Styles/Button.xaml"/>
                    <ResourceDictionary Source="Styles/ComboBox.xaml"/>
                    <ResourceDictionary Source="Styles/DataGrid.xaml"/>
                    <ResourceDictionary Source="Styles/Tabcontrol.xaml"/>
                    <ResourceDictionary Source="Styles/TextBlock.xaml"/>
                    <ResourceDictionary Source="Styles/Window.xaml"/>
                </ResourceDictionary.MergedDictionaries>
                <CollectionViewSource x:Key="cvs" Source="{Binding dt}">
                    <CollectionViewSource.GroupDescriptions>
                        <PropertyGroupDescription PropertyName="datapost"/>
                    </CollectionViewSource.GroupDescriptions>
                </CollectionViewSource>
            </ResourceDictionary>
        </Window.Resources>

    dt - наименование DataTable

    datapost - наименование столбца в DataTable. В datapost  содержатся данные в формате дата+время: "01.12.14 10:33:50".

    Нюанс: при выводе данных в DataGrid я использую это поле (datapost) в 2 столбцах - в одном поле вывожу дату, а в другом - время. Группировать надо как раз по дате.

    2. Для DataGrid указываю источник данных CollectionViewSource и стиль строки группировки GroupStyle:

     <DataGrid  ItemsSource="{Binding Source={StaticResource ResourceKey=cvs}}"  x:Name="datagrid" Width="591" Height="456"  AutoGenerateColumns="False" Loaded="datagrid_Loaded" >
                        <DataGrid.Columns>
                            <DataGridTextColumn x:Name="Date_Start" Binding="{Binding Path=datapost, StringFormat={}{0:dd.MM.yy}}" Header="Дата" Width="Auto" />
                            <DataGridTextColumn x:Name="Time_Start" Binding="{Binding Path=datapost, StringFormat={}{0:HH:mm:ss}}" Header="Время" Width="Auto" />
                            <DataGridTextColumn x:Name="Name" Binding="{Binding Path=NAME}" Header="Имя" Width="Auto" />
                        </DataGrid.Columns>
                        <DataGrid.GroupStyle>
                            <GroupStyle ContainerStyle="{StaticResource GroupHeaderStyle}">
                                <GroupStyle.Panel>
                                    <ItemsPanelTemplate>
                                        <DataGridRowsPresenter/>
                                    </ItemsPanelTemplate>
                                </GroupStyle.Panel>
                            </GroupStyle>
                        </DataGrid.GroupStyle>
                    </DataGrid>

    3. Стиль группировки в отдельном файле:

    <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    
        <Style x:Key="GroupHeaderStyle" TargetType="{x:Type GroupItem}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type GroupItem}">
                        <Expander x:Name="exp" IsExpanded="True"
                              Background="White"
                              Foreground="Black">
                            <Expander.Header>
                                <TextBlock Text="{Binding Path=datapost, StringFormat={}{0:dd.MM.yy}}"/>
                            </Expander.Header>
                            <ItemsPresenter />
                        </Expander>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </ResourceDictionary>

    4. Во время DataGrid_Load выполняется код:

     private void datagrid_Loaded(object sender, RoutedEventArgs e)
            {
     ICollectionView cvs = CollectionViewSource.GetDefaultView(datagrid.ItemsSource);
                if (cvs != null && cvs.CanGroup == true)
                {
                    cvs.GroupDescriptions.Clear();
                    cvs.GroupDescriptions.Add(new PropertyGroupDescription("Date_Start"));
                }
            }

    Результат работы программы: все строки в одном Expander. Или так бывает: каждая строка в своем Expander и плюс к этому в этом Expander еще куча-куча Expander'ов.

    Не понимаю механизм группировки, описанный в статье msdn. Запутался, где должно использоваться поле DataTable, а где столбец DataGrid. И как быть с полем datapost..


    • Изменено kremlinbot 31 августа 2014 г. 8:14
    31 августа 2014 г. 8:13

Ответы

  •  private void GroupRow()
            {
                ICollectionView cvs = CollectionViewSource.GetDefaultView(datagrid_on.ItemsSource);
                if (cvs != null && cvs.CanGroup == true)
                {
                    cvs.GroupDescriptions.Clear();
                    // Указываем поле DataTable, по которому осуществляется новая группировка
                    cvs.GroupDescriptions.Add(new PropertyGroupDescription("datapost", new DateTimeConverter()));
                }
            }
    
            private void UnGroupRow()
            {
                ICollectionView cvs = CollectionViewSource.GetDefaultView(datagrid_on.ItemsSource);
                if (cvs != null)
                {
                    cvs.GroupDescriptions.Clear();
                }
            }
    
            private void SortRow()
            {
                ICollectionView cvs = CollectionViewSource.GetDefaultView(datagrid_on.ItemsSource);
                if (cvs != null && cvs.CanSort == true)
                {
                    cvs.SortDescriptions.Clear();
                    // Указываем поле DataTable, по которому осуществляется сортировка
                    cvs.SortDescriptions.Add(new SortDescription("datapost", ListSortDirection.Descending));
                }
            }

    Прочитал еще раз статью на msdn "Группировка, сортировка, фильтрация", в частности заострив внимание на строке "Создайте объект PropertyGroupDescription, задающий свойство, по которому выполняется группировка. Это свойство можно задать в XAML или в коде". Почему-то в мозгу отложился союз и вместо или. Считал, что XAML код был обязателен для объявления. В итоге, группировку и сортировку можно осуществить из кода C# без всяких объявлений XAML.

    Для группировка столбца DataGrid, привязанного к DataTable datapost, который в себе содержит и дату и время одновременно, при необходимости группировки только по дате, был написан конвертер:

     class DateTimeConverter : IValueConverter
        {
            public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
            {
                if (value is DateTime)
                {
                    return ((DateTime)value).ToString("dd.MM.yy");
                }
                else
                {
                    return "Non dates";
                }
            }
    
            public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
            {
                throw new Exception("The method or operation is not implemented.");
            }
        }
    }

    • Изменено kremlinbot 11 сентября 2014 г. 14:57
    • Помечено в качестве ответа kremlinbot 11 сентября 2014 г. 14:58
    11 сентября 2014 г. 14:55

Все ответы

  • 130 просмотров и ни одного сообщения, ни одной попытки теоретической помощи. Ну да, никто же никогда группировкой, сортировкой, фильтрацией строк в DataGrid не занимался. Я и забыл, что я первопроходец...

    Чем нравился GotDotNet, тем что там были люди, которые не боялись ковыряться в коде, перелопачивая десятки и сотни строк чужого кода. А здесь, если вопрос больше чем на 3 строчки, то всё - все специалисты испарились. И это официальный форум русско-язычного сообщества разработчиков на платформе .Net.. ) Слабовато комьюнити.

    В принципе вопрос самостоятельно решен, но нужна небольшая теоретическая консультация. Есть те, кто могут ответить на вопросы по группировке, сортировке? Или можно закрывать топик?


    • Изменено kremlinbot 5 сентября 2014 г. 16:04
    5 сентября 2014 г. 16:03
  •  private void GroupRow()
            {
                ICollectionView cvs = CollectionViewSource.GetDefaultView(datagrid_on.ItemsSource);
                if (cvs != null && cvs.CanGroup == true)
                {
                    cvs.GroupDescriptions.Clear();
                    // Указываем поле DataTable, по которому осуществляется новая группировка
                    cvs.GroupDescriptions.Add(new PropertyGroupDescription("datapost", new DateTimeConverter()));
                }
            }
    
            private void UnGroupRow()
            {
                ICollectionView cvs = CollectionViewSource.GetDefaultView(datagrid_on.ItemsSource);
                if (cvs != null)
                {
                    cvs.GroupDescriptions.Clear();
                }
            }
    
            private void SortRow()
            {
                ICollectionView cvs = CollectionViewSource.GetDefaultView(datagrid_on.ItemsSource);
                if (cvs != null && cvs.CanSort == true)
                {
                    cvs.SortDescriptions.Clear();
                    // Указываем поле DataTable, по которому осуществляется сортировка
                    cvs.SortDescriptions.Add(new SortDescription("datapost", ListSortDirection.Descending));
                }
            }

    Прочитал еще раз статью на msdn "Группировка, сортировка, фильтрация", в частности заострив внимание на строке "Создайте объект PropertyGroupDescription, задающий свойство, по которому выполняется группировка. Это свойство можно задать в XAML или в коде". Почему-то в мозгу отложился союз и вместо или. Считал, что XAML код был обязателен для объявления. В итоге, группировку и сортировку можно осуществить из кода C# без всяких объявлений XAML.

    Для группировка столбца DataGrid, привязанного к DataTable datapost, который в себе содержит и дату и время одновременно, при необходимости группировки только по дате, был написан конвертер:

     class DateTimeConverter : IValueConverter
        {
            public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
            {
                if (value is DateTime)
                {
                    return ((DateTime)value).ToString("dd.MM.yy");
                }
                else
                {
                    return "Non dates";
                }
            }
    
            public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
            {
                throw new Exception("The method or operation is not implemented.");
            }
        }
    }

    • Изменено kremlinbot 11 сентября 2014 г. 14:57
    • Помечено в качестве ответа kremlinbot 11 сентября 2014 г. 14:58
    11 сентября 2014 г. 14:55
  • Добрый день.

    Интересно, а у меня не получается прибиндить DataTable к DataGrid таким образом. DataGrid пуст. 

    29 апреля 2017 г. 7:31