views:

425

answers:

2

I'm creating a WPF TimeCard app using the MVVM design pattern, and I'm trying to display the sum (total) hours the user has clocked in grouped by each day. I have a ListView with all of the TimeCard data broken into groups using the following XAML:

<ListView.GroupStyle>
    <GroupStyle ContainerStyle="{StaticResource GroupItemStyle}">
        <GroupStyle.HeaderTemplate>
            <DataTemplate>
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="{Binding Path=Name, StringFormat=\{0:D\}}" FontWeight="Bold"/>
                    <TextBlock Text="  (" FontWeight="Bold"/>
                    <!-- This needs to display the sum of the hours -->
                    <TextBlock Text="{Binding ???}" FontWeight="Bold"/>
                    <TextBlock Text=" hours)" FontWeight="Bold"/>
                </StackPanel>
            </DataTemplate>
        </GroupStyle.HeaderTemplate>
    </GroupStyle>
</ListView.GroupStyle>

Is this even possible? At first I thought I would create a partial class of the CollectionViewGroup and add my own properties. But I'm not sure this will even work. Perhaps there is a better solution... any suggestions?

+1  A: 

Use a Converter.

See:

http://www.codeproject.com/KB/WPF/WPFAggregateConverter.aspx

This might help you too:

http://www.codeproject.com/KB/WPF/DsxGridCtrl.aspx

e.tadeu
Thanks... although the answer you gave was also correct, I decided to give it to NathanAW because of the code he provided as it fit directly into my solution.
Brent
+2  A: 

To expand on what e.tadeu said, you can bind your HeaderTemplate's DataTemplate to the Items property of the CollectionViewGroup. This will return you all of the items that are in the current group.

Then you can supply a converter that will return you the desired data from that collection of items. In your case, you say you want the sum of the hours. You could implement a converter that does something like:

public class GroupHoursConverter : IValueConverter
{

    public object Convert(object value, System.Type targetType, 
                          object parameter, 
                          System.Globalization.CultureInfo culture)
    {
        if (null == value)
            return "null";

        ReadOnlyObservableCollection<object> items = 
              (ReadOnlyObservableCollection<object>)value;

        var hours = (from i in items
                     select ((TimeCard)i).Hours).Sum();

        return "Total Hours: " + hours.ToString();
    }

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

Then you could use this converter on your data template:

    <Window.Resources>
        <local:GroupHoursConverter  x:Key="myConverter" />
    </Window.Resources>

    <ListView.GroupStyle>
        <GroupStyle ContainerStyle="{StaticResource GroupItemStyle}">
            <GroupStyle.HeaderTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="{Binding Path=Name, 
                                                  StringFormat=\{0:D\}}" 
                                   FontWeight="Bold"/>
                        <TextBlock Text="  (" FontWeight="Bold"/>
                        <!-- This needs to display the sum of the hours -->
                        <TextBlock Text="{Binding Path=Items, 
                                         Converter={StaticResource myConverter}}"
                                   FontWeight="Bold"/>
                        <TextBlock Text=" hours)" FontWeight="Bold"/>
                    </StackPanel>
                </DataTemplate>
            </GroupStyle.HeaderTemplate>
        </GroupStyle>
    </ListView.GroupStyle>

Cheers!

NathanAW
Thanks! I always forget all the things you can do w/ ValueConverters. Thanks for the sample code.
Brent