I'll try to make this as simple as possible, I have been working on this for 3 days and have tried many different options but for some reason I still cannot get it to work. I'm fairly new to wpf and for that matter vb.net.
So I have a DataGrid that has grouping, multiple levels. The code for this is below.
This is the UserControl.Resources section:
<CollectionViewSource x:Key="HoursViewSource">
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="Phase"/>
<PropertyGroupDescription PropertyName="Employee"/>
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
<local:GroupTotalConverter x:Key="GroupTotal"/>
And The DataGrid: I have a second groupstyle below this one on the same datagrid, but it is not really important to the question.
<DataGrid Grid.Row="1" Grid.ColumnSpan="2" ItemsSource="{Binding Mode=OneWay}" IsReadOnly="True" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Width="80" Header="Date" Binding="{Binding TransDate, StringFormat=d}"/>
<DataGridTextColumn Width="80" Header="Period" Binding="{Binding Period}"/>
<DataGridTextColumn Width="80" Header="Hours" Binding="{Binding Hours, StringFormat=n}"/>
<DataGridTextColumn Width="200" Header="Comment" Binding="{Binding TransComment, StringFormat=n}"/>
</DataGrid.Columns>
<DataGrid.GroupStyle>
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Expander Foreground="White" Margin="0,0,0,3">
<Expander.Header>
<DockPanel>
<TextBlock Text="{Binding Path=Name}"/>
<TextBlock Text="{Binding Path=Items, Converter={StaticResource GroupTotal}"/>
</DockPanel>
</Expander.Header>
<Expander.Content>
<ItemsPresenter>
<ItemsPresenter.Effect>
<DropShadowEffect/>
</ItemsPresenter.Effect>
</ItemsPresenter>
</Expander.Content>
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</DataGrid.GroupStyle>
</DataGrid>
As you can see I have a converter that gets passed the Items from the group, I have been checking the items that get passed and this is working correctly. The problem is in the converter, or at least that's the assumption that I have been going on. When I look at the collection of items that it gets passed there are all the properties that are being sent to the datagrid. However I cannot do anything with the data that is sent to the converter.
Converter:
Public Function Convert(value As Object, targetType As Type, parameter As Object, culture As CultureInfo) As Object Implements IValueConverter.Convert
If TypeOf value Is ReadOnlyObservableCollection(Of Object) Then
Dim items = CType(value, ReadOnlyObservableCollection(Of Object))
Dim total As Decimal = 0
For Each gi As GroupItem In items
total += gi.Hours
Next gi
Return total.ToString()
End If
Return ""
So this converter was a conversion from c#, that I found in another question. I cannot cast it to the same type of object as the original, although this probably could be done with some major modifications to the underlying datagrid source. I have also tried casting it to a simple class that has the properties of the collection that is passed to the converter it just errors and says that the item "Hours" in this case is not part of the CollectionGroupViewInternal When stepping through the code and looking at the collection there is a property Hours = .
I hope I made my issue clear, something tells me this is a super easy fix, but my stubborn nature required that I spend way to many hours on this.
What I'm hoping to do is create a converter that I can use over and over to get the total of specific columns and place it in a TextBlock of the header of that group. The current project that I'm working on will have dozens of these DataGrids with groupings.
Thank you for your help in advance.
Isn't that how it goes, as soon as you ask for help you figure it out.
Well I will post the solution that I found and how I came about it. I'm not sure if this is the best solution, but it does work.
So as I was working with the debugger, I realized that it was sending the converter a collection of collections. Well sort of. It was sending a ReadOnlyObservableCollection, that collection had 1 thing, a collection of CollectionViewGroupInternal which derives from CollectionViewGroup, Then that collection had the items that I wanted to be included in the total amount.
So here is the converter: I hope it will help someone.
Public Function Convert(value As Object, targetType As Type, parameter As Object, culture As CultureInfo) As Object Implements IValueConverter.Convert
If TypeOf value Is ReadOnlyObservableCollection(Of Object) Then
For Each r In value
Dim items As CollectionViewGroup = CType(r, CollectionViewGroup)
Dim total As Decimal = 0
For Each item In items.Items
total += item.Hours
Next
Return total
Next
End If
Return ""
End Function
If you see a way to improve this I would be grateful.