views:

27

answers:

1

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

A: 

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?

Paul Chavez