I have an app on WPF / .Net Framework 4.8 and Prism for MVVM. And I dont understand how to group items in datagrid with MVVM. All guides that I found implement this feature only without MVVM. And the only one found with MVVM doesnt work for me (no errors, but no groups in the datagrid either)
The main window has a datagrid of following objects:
Product p = new Product() {
Id = "H196A", //Any string
Name = "Box A", //Any string
Count = 3 //Any int
}
ViewModel looks like this
public ObservableCollection<Product> MyCollection { get; set; }
public ViewModel()
{
//Filling in the collection
}
And View
<DataGrid ItemsSource="{Binding MyCollection}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Id"/>
<DataGridTextColumn Header="Name"/>
<DataGridTextColumn Header="Count"/>
</DataGrid.Columns>
</DataGrid>
I've tried to bind datagrid to CollectionViewSource this way:
public CollectionViewSource MyCollectionViewSource { get; set; }
public ViewModel()
{
//Filling in the collection
MyCollectionViewSource = new CollectionViewSource();
MyCollectionViewSource.Source = MyCollection;
MyCollectionViewSource.GroupDescriptions.Add(new PropertyGroupDescription(nameof(Product.Name)));
}
<DataGrid ItemsSource="{Binding MyCollectionViewSource.View}" AutoGenerateColumns="False">
...
</DataGrid>
But it didn't work
You may find it easier to define the CollectionViewSource
in the xaml as a static resource. By way of explanation,
<Grid.Resources>
is just a dictionary that allows static objects to be referenced using the key
that you define, so in this case the key is GroupedProducts
.
<Window x:Class="data_grid_grouping.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:data_grid_grouping"
mc:Ignorable="d"
Background="Azure"
Title="MainWindow" Width="500" Height="500" >
<Window.DataContext>
<local:ViewModel />
</Window.DataContext>
<Grid>
<Grid.Resources>
<CollectionViewSource x:Key="GroupedProducts" Source="{Binding MyCollection}">
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="Name"/>
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
</Grid.Resources>
<DataGrid ItemsSource="{Binding Source={StaticResource GroupedProducts}}" AutoGenerateColumns="False" Margin="10, 5">
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding Name}" Width="*" />
<DataGridTextColumn Header="Count" Binding="{Binding Count}" />
<DataGridTextColumn Header="Id" Binding="{Binding Id}" />
</DataGrid.Columns>
<DataGrid.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<TextBlock FontWeight="Bold" FontSize="14" Text="{Binding Name}" Margin="5" Foreground="Maroon"/>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</DataGrid.GroupStyle>
</DataGrid>
</Grid>
</Window>
public partial class MainWindow : Window
{
public MainWindow() => InitializeComponent();
}
class ViewModel : BindableBase
{
public ViewModel()
{
var tmp = MyCollection.GroupBy(_=>_.Name);
foreach (var tmpGroup in tmp)
{
var count = 1;
foreach (Product product in tmpGroup)
{
product.Count = count++;
}
}
}
public ObservableCollection<Product> MyCollection { get; } = new ObservableCollection<Product>
{
new Product{ Name = "Hammer" },
new Product{ Name = "Screwdriver Set" },
new Product{ Name = "Drill Bit Set" },
new Product{ Name = "Measuring Tape" },
new Product{ Name = "Wrench" },
new Product{ Name = "Drill Bit Set" },
new Product{ Name = "Hammer" },
new Product{ Name = "Wrench" },
new Product{ Name = "Drill Bit Set" },
new Product{ Name = "Hammer" },
new Product{ Name = "Screwdriver Set" },
new Product{ Name = "Measuring Tape" }
};
public event PropertyChangedEventHandler? PropertyChanged;
}
public class Product : BindableBase
{
private int _count;
public int Count
{
get => _count;
set => SetProperty(ref _count, value);
}
private string _name = string.Empty;
public string Name
{
get => _name;
set => SetProperty(ref _name, value);
}
private string _id =
Guid
.NewGuid()
.ToString()
.Replace("-", string.Empty)
.ToUpper()
.Substring(0, 12);
public string Id
{
get => _id;
set => SetProperty(ref _id, value);
}
}