Matthis Kohli Matthis Kohli - 2 months ago 26 Question

How do I get the value of a cell in a grouped CollectionView?

I would prefer a solution in VB.NET but C# is also very welcome.

I have a ObservableCollection which I group. The groups can be expanded and collapsed. Each group has a different amount of rows with multiple cells. I want to sum the value of a single cell for every row of each group. This is for your imagination so that you can follow my thoughts.

Group A Total amount: "Cell#0 = 55" - "Cell#1 = 70"

Row#0 |-- Cell#0 = 25 --|-- Cell#1 = 50 --|

Row#1 |-- Cell#0 = 35 --|-- Cell#1 = 20 --|

Group B Total amount: 0

Group C Total amount: "Cell#0 = 12" - "Cell#1 = 8"

Row#0 |-- Cell#0 = 12 --|-- Cell#1 = 8 --|

Group D Total amount: "Cell#0 = 150" - "Cell#1 = 99"

Row#0 |-- Cell#0 = 25 --|-- Cell#1 = 33 --|

Row#1 |-- Cell#0 = 75 --|-- Cell#1 = 33 --|

Row#2 |-- Cell#0 = 50 --|-- Cell#1 = 33 --|

Here is a short code example so that you can try it out yourself if you want.

I have a class libary which I call Models. This libary contains a class called ProjectCompletedModel.vb

Public Class ProjectCompletedModel
Public Property SomeColumnToGroup As String
Public Property SomeValueToSum As Double
End Class

Next I have a class libary ViewModels. It contains the class ProjectCompletedViewModel.vb

Public Class ProjectCompletedViewModel
Private _projCompl As New ProjectCompletedModel

Public Property Projects As ObservableCollection(Of ProjectCompletedModel)

Public Property SomeColumnToGroup As String
Return Me._projCompl.SomeColumnToGroup
End Get
Set(value As String)
Me._projCompl.SomeColumnToGroup = value
End Set
End Property

Public Property SomeValueToSum As Double
Return Me._projCompl.SomeValueToSum
End Get
Set(value As Double)
Me._projCompl.SomeValueToSum = value
End Set
End Property

Public Sub New()

Dim view As CollectionView = CollectionViewSource.GetDefaultView(Me.Projects)
view.GroupDescriptions.Add(New PropertyGroupDescription("SomeColumnToGroup"))
view.SortDescriptions.Add(New SortDescription("SomeColumnToGroup", ListSortDirection.Ascending))
End Sub
End Class

The code for my view is the folowing:

<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">

<!-- Define the Grid design -->
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="2*"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="3*"/>

<ListView Grid.ColumnSpan="2"
ItemsSource="{Binding Projects}">

<!-- Define the column names -->
<GridViewColumn Header="SomeColumnToGroup" Width="150" DisplayMemberBinding="{Binding SomeColumnToGroup}"/>
<GridViewColumn Header="SomeValueToSum" Width="100" DisplayMemberBinding="{Binding SomeValueToSum}"/>

<!-- Define the group style-->
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Expander IsExpanded="True">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}" FontWeight="Bold" Foreground="#FF425C8F" FontSize="14"/>
<TextBlock Text="(" FontSize="14" Foreground="#FF425C8F"/>
<TextBlock Text="{Binding ItemCount}" Foreground="#FF425C8F" FontSize="14" FontWeight="Bold"/>
<TextBlock Text=")" Foreground="#FF425C8F" FontSize="14"/>
<ItemsPresenter />

Finally the .xaml.vb file:

Public Class ProjectCompletedView

Public Sub New()
' This call is required by the designer.

' Add any initialization after the InitializeComponent() call.
Me.DataContext = New ProjectCompletedViewModel
End Sub
End Class

My application has a reference to ViewModels. ViewModels to Models.

This is what it looks like with random values:


My approach:

I managed by following the debugger to reach the cells so I did the following:

ProjectCompletedModel.vb does the grouping in the constructor. There I wanted to get the GroupNames.

  • Ferrari

  • Lamborghini

  • Lotus

  • etc

For each GroupName I wanted to loop through my ObservAbleCollection and see if the "ColumnName" matches the "GroupName". Then access the cell for the row where this condition is true. But I can't even get the GroupNames as the internal implementation is of this type which I can't retrieve any information.



Write a Converter (eg; SumConverter) to calculate the sum of the values.

Update your TextBlock in your Expander.Header to use this Converter.

Change <TextBlock Text="{Binding ItemCount}" .../> in your Expander Header to <TextBlock Text="{Binding .,Converter={StaticResource SumCnvKey}}" .../>.

Now your SumConverter will be called for every group.

public class SumConverter : IValueConverter

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        CollectionViewGroup group = (CollectionViewGroup)value;            
        ReadOnlyObservableCollection<object> items = group.Items;
        var sum = (from p in items select ((ProjectCompletedModel)p).SomeValueToSum).Sum();

        return sum;

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        throw new NotImplementedException();

I created my own ViewModel with Car in a collection, and checked, it works fine.

Group Sum Output

See if this solves your issue.