This is a migrated thread and some comments may be shown as answers.

2010 Q3 Broken GridViewGroupingEventArgs: AggregateFunctions is missing

6 Answers 76 Views
GridView
This is a migrated thread and some comments may be shown as answers.
Rodney Foley
Top achievements
Rank 1
Rodney Foley asked on 18 Nov 2010, 09:13 PM
The following code has been working for well over a year since it was put into our code until we upgraded to 2010 Q3 controls.

private void RadWindow_Opened(object sender, RoutedEventArgs e)
{
    detailGridView.Grouping += new EventHandler<GridViewGroupingEventArgs>(detailGridView_Grouping);
}
 
private void detailGridView_Grouping(object sender, GridViewGroupingEventArgs e)
{
    if (e.GroupDescriptor != null
        && e.GroupDescriptor.AggregateFunctions.Count == 0
        && detailGridView.GroupDescriptors.Count == 0)
    {
        try
        {
            e.GroupDescriptor.AggregateFunctions.Add(new CountFunction() { ResultFormatString = "({0})" });
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message, "Error", MessageBoxButton.OK);
        }
    }
}
}

Now it it wont compile saying AggregateFunctions is an unknown member.  I looked at the posted Known Issues and Breaking Changes - RadGridView and it doesn't go into any detail about this being removed. It just has mention of these two changes:

  • The GroupDescriptor property of GridViewGroupedEventArgs and GridViewGroupingEventArgs is now of type IGroupDescriptor. 
  • The Action property of the GridViewGroupedEventArgs and GridViewGroupingEventArgs is now of type GroupingEventAction instead of CollectionChangeAction.
  • The GroupDescriptors property of RadGridView is now a collection of IGroupDescriptor, instead of GroupDescriptor.

When I look at the IGroupDiscriptor it of course doesn't have this member.  Why the heck would you make this kind of breaking functionality without providing resolution on how to get the now missing members?  The code I am using was provided by Telerik Support for how to add group counts when a user groups by any column. So I went to look at your Changes and Backward Compatibility page to see if you provided a new functionality to provide this grouping count another way but nothing.

Please advise where the AggregateFunctions collection went and how to add this same type of group count on any grouping a user does.  The only examples you have in your documentation is how to do it for a specific (programmatically) grouped column. These are not helpful as they only show how to pre-group a column and how to add the count only to this grouped column.  And this documentation confuses the issue more because they show the collection I want on the GroupDescriptor object, it just isn't on the interface any more.

So after all that searching I tried the bellow change and it doesn't work. Because the GroupDescriptor is now a ColumnGroupDescriptor which doesn't have the AggregateFunctions collection.

private void detailGridView_Grouping(object sender, GridViewGroupingEventArgs e)
{
    Telerik.Windows.Data.GroupDescriptor gd = e.GroupDescriptor as Telerik.Windows.Data.GroupDescriptor;
    if (gd != null
        && gd.AggregateFunctions.Count == 0
        && detailGridView.GroupDescriptors.Count == 0)
    {
        try
        {
            gd.AggregateFunctions.Add(new CountFunction() { ResultFormatString = "({0})" });
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message, "Error", MessageBoxButton.OK);
        }
    }
}

We are not happy aboutTelerik making this breaking change without proving new solutions to solve what they broke.

6 Answers, 1 is accepted

Sort by
0
Stefan Dobrev
Telerik team
answered on 19 Nov 2010, 01:56 PM
Hi Rodney,

First of all, let me apologize for any inconveniences the upgrade to RadControls for Silverlight Q3 2010 may have caused you.

As noted in the breaking changes post, RadGridView now generates the new ColumnGroupDescriptor by default, which lacks the Member and AggregateFunctions properties of GroupDescriptor and instead relies on its Column.

Regarding a generic implementation of how to obtain the aggregates for a particular IGroupDescriptor we are providing the following extension method as a solution:
public static IEnumerable<AggregateFunction> GetAggregateFunctions(this IGroupDescriptor groupDescriptor)
{
    var aggregateFunctionsProvider = groupDescriptor as IAggregateFunctionsProvider;
    if (aggregateFunctionsProvider != null)
    {
        return aggregateFunctionsProvider.AggregateFunctions;
    }
 
    return Enumerable.Empty<AggregateFunction>();
}

A little background why we have implemented this and introduced this breaking change. As you know Microsoft's vision how to group items in a collection is to use ICollectionView (via CollectionViewSource or PagedCollectionView) and its GroupDescriptions property. However their base class GroupDescription does not have the notion of aggregates, thus making it not applicable to use in our pre Q3 2010 implementation which relies on concrete implementation of a GroupDescriptor. Introducing IGroupDescriptor interface along with IAggregateFunctionsProvider allows us to have group descriptors which do not have aggregates (not implementing IAggregateFunctionsProvider). This opens the door for supporting custom GroupDescription that our clients have already written.

Thanks again for your feedback. We have taken a note and we will try to provide a sample migration code for future breaking changes.

Regards,
Stefan Dobrev
the Telerik team
Browse the videos here>> to help you get started with RadControls for Silverlight
0
Rodney Foley
Top achievements
Rank 1
answered on 19 Nov 2010, 06:25 PM
Thanks Stefan,

I have seen that posted as well, unfortunately it doesn't solve the issue since IEnumerable<T> doesn't allow you to modify the collection.  If you would see in my code I posted your GetAggregateFunctions extension method doesn't slid into it.  Since I need to ADD a NEW Aggregate Function to the collection.  Again which you would see if you read my code I posted and looked at what I am doing. 

Also I looked at IAggregateFunctionsProvider to see if this helps but it has no methods to add a function to it.

So please, I beg you and anyone else at Telerik support, to READ MY CODE and SEE WHAT IT IS DOING. Then respond with a solution how to accomplish this with based on  your new breaking changes.  
0
Stefan Dobrev
Telerik team
answered on 22 Nov 2010, 09:43 AM
Hi Rodney,

I have looked at your code. The snippet I have written is a generic version that can be used in any scenario and this is the reason I have shared it in the forums, so that other users can benefit from it.

Here is the updated version of the snippet that will work in your case:
public static class GroupDescriptorExtensions
{
    public static IList<AggregateFunction> GetAggregateFunctions(this IGroupDescriptor groupDescriptor)
    {
        var aggregateFunctionsProvider = groupDescriptor as IAggregateFunctionsProvider;
        if (aggregateFunctionsProvider != null)
        {
            return aggregateFunctionsProvider.AggregateFunctions as IList<AggregateFunction>;
        }
 
        return null;
    }
}

Greetings,
Stefan Dobrev
the Telerik team
Browse the videos here>> to help you get started with RadControls for Silverlight
0
Arcadia_User
Top achievements
Rank 1
answered on 22 Nov 2010, 05:28 PM

Hello Telerik,

We have exactly the same problem. We need to have Count aggregation function by default when user groups by any column.

How would you suggest to implement this?

0
Rodney Foley
Top achievements
Rank 1
answered on 22 Nov 2010, 09:50 PM
Hi Stefan,

Did you test that code? I thought about that, and decided against it because if it worked it wouldn't be safe as it violates the API.  It turns out that it doesn't work as I suspected. 

Main issue you can't always cast to IList<T>. If you actually look in your own source code which I just did (but I shouldn't have to), you would notice that on the ColumnGroupDescriptor it has a private GetAggregateFunctions method which can return two different types.  First if it has a DataControl (as I do in this case) it returns a raw IEnumerable<T> based on a Linq SelectMany query. Otherwise it returns an AggregateFunctionsCollection.  If it returns the AggregateFunctionsCollection we would be good, but it doesn't do that if there is a DataControl.

However, even if could safely cast the AggregateFunctions to an IList the API is returning an IEnumerable<AggregateFunction> for a reason and they can change the underlying implementation that would break this workaround if it worked. They developer of the API does not want the collection returned it to be modified.

Not to mention your provided workaround breaks common Linq guidelines because now you will return null in a couple cases instead of an empty collection. 

So after digging around in your source code I came up with this workaround, which does work for me. I am not happy with this workaround, the first one is the Extension Method version. The second is just doing it in the event handler.

With Extension Method
private void detailGridView_Grouping(object sender, GridViewGroupingEventArgs e)
{
    if (e.GroupDescriptor != null
        && e.GroupDescriptor.AggregateFunctions().Count == 0
        && detailGridView.GroupDescriptors.Count == 0)
    {
        try
        {
            e.GroupDescriptor.AggregateFunctions().Add(new CountFunction() { ResultFormatString = "({0})" });
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message, "Error", MessageBoxButton.OK);
        }
    }
}
 
public static AggregateFunctionCollection AggregateFunctions(this IGroupDescriptor groupDescriptor)
{
    var columnGroupDescriptor = groupDescriptor as ColumnGroupDescriptor;
 
    if (columnGroupDescriptor != null)
        return columnGroupDescriptor.Column.AggregateFunctions;
 
 
    return new AggregateFunctionCollection();
}

Without Extension Method
private void detailGridView_Grouping(object sender, GridViewGroupingEventArgs e)
{
    var columnGroupDescriptor = e.GroupDescriptor as ColumnGroupDescriptor;
 
    if (columnGroupDescriptor != null && detailGridView.GroupDescriptors.Count == 0)
    {
        try
        {
            var functions = columnGroupDescriptor.Column.AggregateFunctions;
 
            if (functions.Count == 0)
                functions.Add(new CountFunction() { ResultFormatString = "({0})" });
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message, "Error", MessageBoxButton.OK);
        }
    }
}

I have tested this and they work for me. I am going with the non-extension method approach as I only have to do this in one place. I am not happy with having to do this in such away. However I am more disappointed that I have to look through your source code to get my workaround, that Telerik couldn't provide one on their own since Telerik made the breaking changes. This is very disappointing.
0
Arcadia_User
Top achievements
Rank 1
answered on 23 Nov 2010, 12:16 PM
Rodney, thank you for your code, I did no notice that column has AggregateFunctions, that helps a lot.
Tags
GridView
Asked by
Rodney Foley
Top achievements
Rank 1
Answers by
Stefan Dobrev
Telerik team
Rodney Foley
Top achievements
Rank 1
Arcadia_User
Top achievements
Rank 1
Share this question
or