I need to apply grouping to rows in a DataGrid that is nested in a TabControl. Both the DataGrid and the TabControl are databound. The outermost control is bound to a ViewModel that exposes a collection of pages that is bound to the TabControl. Each page exposes a collection of lines that is bound to the Grid.
I am tried to follow patterns like this one from SO and this one from C-SharpCorner. I'm not married to these, so if there is a better pattern (as this post seems to indicate), I'm willing to go in another direction.
For now, I am not sure where to inject the definition of the PropertyGroupDescription and bind it to my desired PropertyName. I've tried doing it as a resource and directly as a CollectionViewSource on the datagrid. But neither produced reasonable results.
This is what I have so far:
<UserControl x:Class="View.ViewInvoiceUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d" >
<Grid Name="_grid" MinHeight="100">
snipped for clarity...
<TabControl
ItemsSource="{Binding Path=CurrentInvoice.InvoicePages}"
Grid.Column="0"
Grid.ColumnSpan="4"
Grid.Row="5"
HorizontalAlignment="Left"
Margin="0,4,0,0"
Name="_invoicePageTabControl"
VerticalAlignment="Top"
>
<TabControl.ItemContainerStyle /> - snipped for clarity
<TabControl.ContentTemplate>
<DataTemplate>
<DataGrid
Name="_invoiceLineGrid"
AutoGenerateColumns="False"
CanUserSortColumns="True"
ColumnHeaderStyle="{StaticResource columnHeaderStyle}"
HorizontalAlignment="Left"
ItemsSource="{Binding InvoiceLines}"
IsReadOnly="True"
RowDetailsVisibilityMode="VisibleWhenSelected"
RowStyle="{StaticResource DataGridRowStyle}"
SelectionUnit="FullRow"
VerticalAlignment="Top"
Visibility="{Binding Path=InvoiceLineGridVisibility}"
Initialized="_invoiceLineGrid_Initialized"
>
<DataGrid.Columns>
<DataGridTextColumn Header="Line Number" MinWidth="50" Binding="{Binding Path=InvoiceLineNumber}" />
<DataGridTextColumn Header="Description" MinWidth="50" Width="*" Binding="{Binding Path=Description}" />
<DataGridTextColumn Header="Quantity" MinWidth="50" Binding="{Binding Path=Quantity}" />
<DataGridTextColumn Header="Extended Cost" MinWidth="50" Width="*" Binding="{Binding Path=ExtendedCost}" />
</DataGrid.Columns>
<DataGrid.GroupStyle>
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander>
<Expander.Header>
<StackPanel>
<TextBlock Text="{Binding Name}" />
</StackPanel>
</Expander.Header>
<ItemsPresenter />
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</DataGrid.GroupStyle>
</DataGrid>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
</Grid>
I think I need to add something like:
<CollectionViewSource>
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="DepartmentBillingCode" />
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
If I add the CollectionViewSource as a resource and change the DataGrid binding, there are no rows in the grid. If I add the CollectionViewSource to the DataGrid, I get an exception: {"Operation is not valid while ItemsSource is in use. Access and modify elements with ItemsControl.ItemsSource instead."} nested in {"Add value to collection of type 'System.Windows.Controls.ItemCollection' threw an exception."} But I don't see a GroupDescription or PropertyGroupDescription on DataGrid.ItemSource
So, I'm feeling lost now. Any suggestions are appreciated.
Thanks