WPF Grouping a DataGrid nested in databound tabs
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 />
<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 InvoiceLineNumber}" />
<DataGridTextColumn Header="Description" MinWidth="50" Width="*" Binding="{Binding Description}" />
<DataGridTextColumn Header="Quantity" MinWidth="50" Binding="{Binding Quantity}" />
<DataGridTextColumn Header="Extended Cost" MinWidth="50" Width="*" Binding="{Binding 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>
</UserControl>
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
So I found a possible answer. I'm open to other people's interpretation. Is this a good solution?
Applying an SO post regarding what part of MVVM pattern is resonsible for grouping of DataGrid, I went in search of a solution to generate a grouping in the ViewModel. I found a simple example on WpfTutorial.com
In my InvoicePageViewModel, I created a new property that creates a ListViewCollection from my List. ListViewCollection allows me to add my own GroupDescription as follows:
public ListCollectionView GroupedInvoiceLines
{
get
{
ListCollectionView groupedLines = new ListCollectionView(InvoiceLines); // TODO should this be cached?
groupedLines.GroupDescriptions.Add(new PropertyGroupDescription("DepartmentBillingCode"));
return groupedLines;
}
}
Then it was trivial to change the data binding on the DataGrid from InvoiceLines to GroupedInvoiceLines.
Comments? Questions?
精彩评论