Manually group DataGrid items

2019-05-05 13:45发布

问题:

I need to use a data grid and my data looks as follows: firstName, lastName, street, zip, city, country, image

In my datagrid I will only show firstName, lastName and image but it has to be grouped after city.

Update The code below shows grouped items but the three items I want to display (firstName, lastName, image) are followed by all items (firstName, lastName, street, zip, city, country, image) per row. I think I have to replace the <ItemsPresenter /> but thats only speculation..

Can anyone help me, I can't manage this on my own...

<Grid>
    <DataGrid ItemsSource="{Binding GroupedMovables}">
        <DataGrid.Columns>
            <DataGridTemplateColumn Header="Preview" Width="SizeToCells" IsReadOnly="True">
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <Image Name="Preview" Height="20" Source="{Binding Image}" HorizontalAlignment="Center" />
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
            <DataGridTextColumn Header="first name" Binding="{Binding FirstName}" />
            <DataGridTextColumn Header="last name" Binding="{Binding LastName}" />
        </DataGrid.Columns>
        <DataGrid.GroupStyle>
            <GroupStyle>
                <GroupStyle.HeaderTemplate>
                    <DataTemplate>
                        <StackPanel>
                            <TextBlock Text="{Binding Path=City}" FontWeight="Bold" Padding="3"/>
                        </StackPanel>
                    </DataTemplate>
                </GroupStyle.HeaderTemplate>
                <GroupStyle.ContainerStyle>
                    <Style TargetType="{x:Type GroupItem}">
                        <Setter Property="Template">
                            <Setter.Value>
                                <ControlTemplate TargetType="{x:Type GroupItem}">
                                    <Expander>
                                        <Expander.Header>
                                            <StackPanel Orientation="Horizontal">
                                                <TextBlock Text="{Binding Path=Name}" />
                                                <TextBlock Text="{Binding Path=ItemCount}" Margin="8,0,4,0"/>
                                                <TextBlock Text="Element(s)"/>
                                            </StackPanel>
                                        </Expander.Header>
                                        <ItemsPresenter />
                                    </Expander>
                                </ControlTemplate>
                            </Setter.Value>
                        </Setter>
                    </Style>
                </GroupStyle.ContainerStyle>
            </GroupStyle>
        </DataGrid.GroupStyle>
    </DataGrid>
</Grid>

回答1:

The proper way for grouping is to use a CollectionView (for more details: How to Navigate, Group, Sort and Filter Data in WPF). The following is a simple proof of concept application I created for you to show you how to use a CollectionView for grouping you data:

This class represents a row in the DataGrid:

public class Employee
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Street { get; set; }
    public string ZipCode { get; set; }
    public string City { get; set; }
    public string Country { get; set; }
    public string Image { get; set; }
}

MaindWindow code behind:

    /// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        // Create some test data
        var employees =
            new ObservableCollection<Employee>
                {
                    new Employee {FirstName = "Mohammed", LastName = "Fadil", Street = "A B C", ZipCode = "123", City = "London", Country = "UK", Image = "/Images/globe.png"},
                    new Employee {FirstName = "Siraj", LastName = "Hussam", Street = "A B C", ZipCode = "123", City = "London", Country = "UK", Image = "/Images/globe.png"},
                    new Employee {FirstName = "Ayman", LastName = "Tariq", Street = "A B C", ZipCode = "123", City = "London", Country = "UK", Image = "/Images/globe.png"},
                    new Employee {FirstName = "Khalid", LastName = "Sheik", Street = "X Y Z", ZipCode = "234", City = "Paris", Country = "France", Image = "/Images/monitor.png"},
                    new Employee {FirstName = "Hassan", LastName = "Ali", Street = "Q W E R", ZipCode = "544", City = "NY", Country = "USA", Image = "/Images/star.png"},
                    new Employee {FirstName = "Ehsan", LastName = "Mahmoud", Street = "A B C", ZipCode = "123", City = "London", Country = "UK", Image = "/Images/globe.png"},
                    new Employee {FirstName = "Idris", LastName = "Sheik", Street = "X Y Z", ZipCode = "234", City = "Paris", Country = "France", Image = "/Images/monitor.png"},
                    new Employee {FirstName = "Khalil", LastName = "Ali", Street = "Q W E R", ZipCode = "544", City = "NY", Country = "USA", Image = "/Images/star.png"}
                };

        ICollectionView employeesView =
            CollectionViewSource.GetDefaultView(employees);

        // Set the grouping by city proprty
        employeesView.GroupDescriptions.Add(new PropertyGroupDescription("City"));

        // Set the view as the DataContext for the DataGrid
        EmployeesDataGrid.DataContext = employeesView;
    }
}

The DataGrid XAML code:

    <DataGrid Name="EmployeesDataGrid" ItemsSource="{Binding}" AutoGenerateColumns="False">
        <DataGrid.Columns>
            <DataGridTextColumn Binding="{Binding FirstName}" Header="First Name"/>
            <DataGridTextColumn Binding="{Binding LastName}" Header="Last Name"/>
            <DataGridTemplateColumn Header="Image">
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <Image Source="{Binding Image}"/>
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
        </DataGrid.Columns>

        <DataGrid.GroupStyle>
            <GroupStyle>
                <GroupStyle.HeaderTemplate>
                    <DataTemplate>
                        <StackPanel>
                            <TextBlock Text="{Binding Path=City}" FontWeight="Bold" Padding="3"/>
                        </StackPanel>
                    </DataTemplate>
                </GroupStyle.HeaderTemplate>
                <GroupStyle.ContainerStyle>
                    <Style TargetType="{x:Type GroupItem}">
                        <Setter Property="Template">
                            <Setter.Value>
                                <ControlTemplate TargetType="{x:Type GroupItem}">
                                    <Expander>
                                        <Expander.Header>
                                            <StackPanel Orientation="Horizontal">
                                                <TextBlock Text="{Binding Path=Name}" />
                                                <TextBlock Text="{Binding Path=ItemCount}" Margin="8,0,4,0"/>
                                                <TextBlock Text="Element(s)"/>
                                            </StackPanel>
                                        </Expander.Header>
                                        <ItemsPresenter />
                                    </Expander>
                                </ControlTemplate>
                            </Setter.Value>
                        </Setter>
                    </Style>
                </GroupStyle.ContainerStyle>
            </GroupStyle>
        </DataGrid.GroupStyle>

    </DataGrid>

The result is:

For more information about styling the DataGrid groups please check this post: WPF DataGrid Control > Grouping