<
gridView:RadGridView
x:Name
=
"textGridView"
ItemsSource
=
"{Binding testList}"
Style
=
"{StaticResource _gridStyle}"
>
<
gridView:RadGridView.Columns
>
<
gridView:GridViewDataColumn
Header
=
"Name"
DataMemberBinding
=
"{Binding Name}"
/>
<
gridView:GridViewDataColumn
Header
=
"Description"
DataMemberBinding
=
"{Binding Description}"
/>
<
gridView:GridViewDataColumn
Header
=
"Grade"
DataMemberBinding
=
"{Binding Grade}"
UniqueName="_Grade">
<telerik:GridViewDataColumn.AggregateFunctions>
<telerik:CountFunction Caption="Total customers:" />
</telerik:GridViewDataColumn.AggregateFunctions>
<telerik:GridViewDataColumn.AggregateFunctions>
<telerik:CountFunction Caption="Total customers:" />
</telerik:GridViewDataColumn.AggregateFunctions>
<telerik:GridViewDataColumn.AggregateFunctions>
<telerik:CountFunction Caption="Total customers:" />
</telerik:GridViewDataColumn.AggregateFunctions>
<telerik:GridViewDataColumn.AggregateFunctions>
<telerik:CountFunction Caption="Total customers:" />
</telerik:GridViewDataColumn.AggregateFunctions>
<telerik:GridViewDataColumn.AggregateFunctions>
<telerik:CountFunction Caption="Total customers:" />
</telerik:GridViewDataColumn.AggregateFunctions>
<telerik:GridViewDataColumn.AggregateFunctions>
<telerik:CountFunction Caption="Total customers:" />
</telerik:GridViewDataColumn.AggregateFunctions>
<telerik:GridViewDataColumn.AggregateFunctions>
<telerik:CountFunction Caption="Total customers:" />
</telerik:GridViewDataColumn.AggregateFunctions>
<telerik:GridViewDataColumn.AggregateFunctions>
<telerik:CountFunction Caption="Total customers:" />
</telerik:GridViewDataColumn.AggregateFunctions>
<telerik:GridViewDataColumn.AggregateFunctions>
<telerik:CountFunction Caption="Total customers:" />
</telerik:GridViewDataColumn.AggregateFunctions>
<telerik:GridViewDataColumn.AggregateFunctions>
<telerik:CountFunction Caption="Total customers:" />
</telerik:GridViewDataColumn.AggregateFunctions>
<telerik:GridViewDataColumn.AggregateFunctions>
<telerik:CountFunction Caption="Total customers:" />
</telerik:GridViewDataColumn.AggregateFunctions>
<telerik:GridViewDataColumn.AggregateFunctions>
<telerik:CountFunction Caption="Total customers:" />
</telerik:GridViewDataColumn.AggregateFunctions>
<telerik:GridViewDataColumn.AggregateFunctions>
<telerik:SumFunction/>
</telerik:GridViewDataColumn.AggregateFunctions>
</gridView:GridViewDataColumn>
</
gridView:RadGridView.Columns
>
<
gridView:RadGridView.GroupDescriptors
>
<
telerikData:GroupDescriptor
DisplayContent
=
"Name"
Member
=
"Name"
SortDirection
=
"Ascending"
/>
</
gridView:RadGridView.GroupDescriptors
>
</
gridView:RadGridView
>
<telerik:GridViewDataColumn.AggregateFunctions>
<telerik:CountFunction Caption="Total customers:" />
</telerik:GridViewDataColumn.AggregateFunctions>
Now when I click the groupdescriptor, gridview reordered by "Name".
If I want to reorder by Value of Sum "_Grade" after clicked the groupdescriptor, What should I do?
<telerik:GridViewDataColumn.AggregateFunctions>
<telerik:CountFunction Caption="Total customers:" />
</telerik:GridViewDataColumn.AggregateFunctions>
<telerik:GridViewDataColumn.AggregateFunctions>
<telerik:CountFunction Caption="Total customers:" />
</telerik:GridViewDataColumn.AggregateFunctions>
9 Answers, 1 is accepted
You need to override the CreateGroupSortExpression() method and implement an expression for sorting according to the result of the aggregate functions. I am sending you a sample project illustrating how to achieve the desired functionality.
Maya
the Telerik team
Thanks,
Justin
May you provide a bit more details about your exact requirement ? Do you want to perform multiple sorting or sorting based only on a single aggregate function from the aggregates in the group ? How do you want to visualize the different sorting - how do you want to choose which aggregate to sort by ?
Maya
the Telerik team
Thanks
Justin Wilson
If you want to be able to sort based on different aggregate functions, you may slightly extend the SortingGroupDescriptor class:
public class SortingGroupDescriptor : GroupDescriptor
{
private AggregateFunction sortFunction;
public AggregateFunction SortFunction
{
get
{
return sortFunction;
}
set
{
sortFunction = value;
this.OnPropertyChanged("SortFunction");
}
}
public override Expression CreateGroupSortExpression(Expression groupingExpression)
{
if (this.SortFunction != null)
{
return this.SortFunction.CreateAggregateExpression(groupingExpression);
}
else
{
return base.CreateGroupSortExpression(groupingExpression);
}
}
In this case the SortFunction will give us the information towards which function you want to sort. Afterwards, depending on your custom implementation, you may set the function as follows:
var descriptor = this.playersGrid.GroupDescriptors[0] as SortingGroupDescriptor;
descriptor.SortFunction = descriptor.AggregateFunctions[1];
Once you change the SortFunction, sorting will be performed again when clicking on the group panel cell.
Still, I am sending you a sample project illustrating the proposed solution.
Maya
the Telerik team
I have the same issue as Justin.
But not what you have in the example.
Instead of 2 aggregates for one column, I have multiple columns with aggregates.
So let's say number had a sum aggregate and position had a sum aggregate.
I want to be able to drag country (and state and continent, etc) into the grouped by section
and then I want to be able to click the number header and have the aggregates sort by number
or click the position header and sort by position.
Is this possible?
Can you provide a sample?
It would be very much appreciated.
Thanks, Megan
You could use the same approach as the one illustrated above by creating a SortingGroupDescriptor-s. Each descriptor created will be sorted based on the values of its aggregate function.
If you want to add groups through the UI, you could handle the Grouping event and define such SortingGroupDescriptor instead of the default one - ColumnGroupDescriptor. For example:
private void playersGrid_Grouping(object sender, GridViewGroupingEventArgs e)
{
if (e.Action == GroupingEventAction.Place)
{
e.Cancel = true;
ColumnGroupDescriptor currentDescriptor = e.GroupDescriptor as ColumnGroupDescriptor;
SortingGroupDescriptor sortingDescriptor = new SortingGroupDescriptor();
sortingDescriptor.Member = (currentDescriptor.Column as GridViewDataColumn).DataMemberBinding.Path.Path;
foreach (AggregateFunction function in (currentDescriptor.Column as GridViewDataColumn).AggregateFunctions)
{
sortingDescriptor.AggregateFunctions.Add(function);
}
this.playersGrid.GroupDescriptors.Add(sortingDescriptor);
}
}
The code above is based on the project attached at the beginning of the thread - SortGroupsByAggregates.
Best wishes,
Maya
the Telerik team
Explore the entire Telerik portfolio by downloading the Ultimate Collection trial package. Get it now >>
Thanks so much for your help. With a bunch more customization in the sort and group functions, I was able to fulfill the requirements.
Notes for others, if interested:
I added some logic into the sorting function in order to sort all groups (and in the same direction)
I also added a function to get the sortgroupdescriptor and sortfundtion - for reuse.
private void CurrentGridView_Sorting(object sender, GridViewSortingEventArgs e)
{
//capture sorting state so all levels can be sorted the same way
SortingState sortState = e.OldSortingState;
//if group, sort by agg
if (CurrentGridView.GroupCount > 0)
{
//sort for each group
for (int i = 0; i < CurrentGridView.GroupCount; i++)
{
//get descriptor (and set sortfunction)
var descriptor = GetGroupSortFunctionDescriptor(e.Column.UniqueName, i);
//set sort direction
switch (sortState)
{
case SortingState.Ascending:
//descriptor.SortDirection = null;
descriptor.SortDirection = ListSortDirection.Descending;
break;
case SortingState.Descending:
//descriptor.SortDirection = ListSortDirection.Ascending;
descriptor.SortDirection = null;
break;
case SortingState.None:
//descriptor.SortDirection = ListSortDirection.Descending;
descriptor.SortDirection = ListSortDirection.Ascending;
break;
}
}
}
//else sort by non-agg values
else
{
GridViewBoundColumnBase c = (GridViewBoundColumnBase)e.Column;
string cDataType = c.DataType.ToString();
if (cDataType.Contains("System.Int32"))
{
switch (sortState)
{
case SortingState.Ascending:
e.NewSortingState = SortingState.None;
break;
case SortingState.Descending:
e.NewSortingState = SortingState.Ascending;
break;
case SortingState.None:
e.NewSortingState = SortingState.Descending;
break;
}
}
}
}
private SortingGroupDescriptor GetGroupSortFunctionDescriptor(string columnName, int groupId)
{
var descriptor = CurrentGridView.GroupDescriptors[groupId] as SortingGroupDescriptor;
//get aggregate id
int id = 0;
foreach (AggregateFunction function in descriptor.AggregateFunctions)
{
//TODO: Figure out a way to sort by functions with captions (string columns)
//"Name" (which is the 'count:' field) is hard-coded right now - this is not ideal
if (function.FunctionName.Contains(columnName) || (function.FunctionName.Contains("Count") && columnName == "Name"))
{
break;
}
id++;
}
//set sort to clicked column's aggregate
descriptor.SortFunction = descriptor.AggregateFunctions[id];
return descriptor;
}
Then in the grouping function, I added some logic to sort the groups based on the previous sort column and direction when a new group is placed:
private void CurrentGridView_Grouping(object sender, GridViewGroupingEventArgs e)
{
if (e.Action == GroupingEventAction.Place)
{
e.Cancel = true;
ColumnGroupDescriptor currentDescriptor = e.GroupDescriptor as ColumnGroupDescriptor;
SortingGroupDescriptor sortingDescriptor = new SortingGroupDescriptor();
sortingDescriptor.Member = (currentDescriptor.Column as GridViewBoundColumnBase).DataMemberBinding.Path.Path;
foreach (AggregateFunction function in (currentDescriptor.Column as GridViewBoundColumnBase).AggregateFunctions)
{
sortingDescriptor.AggregateFunctions.Add(function);
}
this.CurrentGridView.GroupDescriptors.Add(sortingDescriptor);
//if first group, set sort to current non-aggregate sort column
if (CurrentGridView.GroupDescriptors.Count == 1)
{
//get previous non-aggregate sort column
var previousDescriptor = CurrentGridView.SortDescriptors[0] as SortDescriptor;
//get current group descriptor (and sortfunction)
var descriptor = GetGroupSortFunctionDescriptor(previousDescriptor.Member.ToString(), 0);
//set sort function and direction
sortingDescriptor.SortFunction = descriptor.SortFunction;
sortingDescriptor.SortDirection = CurrentGridView.SortDescriptors[0].SortDirection;
}
//else not first group, agg sorting already in place, set sort to current aggregate sort column
else
{
//get previous descriptor (and sortfunction)
var previousDescriptor = CurrentGridView.GroupDescriptors[0] as SortingGroupDescriptor;
//set sort function and direction
sortingDescriptor.SortFunction = previousDescriptor.SortFunction;
sortingDescriptor.SortDirection = previousDescriptor.SortDirection;
}
}
//placing group or removing a group when there is more than one group already
if (e.Action != GroupingEventAction.Remove || CurrentGridView.GroupCount > 1)
{
CurrentGridView.Columns[0].Width = 200;
}
else
{
CurrentGridView.Columns[0].Width = 25;
}
}
HTH someone out there. ;)
-Megan
The issue I'm having is that if I drop the column "number" from the group by in the UI and re-add it the aggregates don't show anymore.
So I added the aggregate to the column definition:
<
telerik:RadGridView.Columns
>
<
telerik:GridViewDataColumn
Header
=
"Name"
DataMemberBinding
=
"{Binding Name}"
>
</
telerik:GridViewDataColumn
>
<
telerik:GridViewDataColumn
Header
=
"Number"
DataMemberBinding
=
"{Binding Number}"
>
<
telerik:GridViewDataColumn.AggregateFunctions
>
<
data:SumFunction
Caption
=
"Sum: "
SourceField
=
"Number"
/>
<
data:CountFunction
Caption
=
"Count"
/>
</
telerik:GridViewDataColumn.AggregateFunctions
>
</
telerik:GridViewDataColumn
>
<
telerik:GridViewDataColumn
Header
=
"Position"
DataMemberBinding
=
"{Binding Position}"
>
</
telerik:GridViewDataColumn
>
<
telerik:GridViewDataColumn
Header
=
"Country"
DataMemberBinding
=
"{Binding Country}"
>
</
telerik:GridViewDataColumn
>
</
telerik:RadGridView.Columns
>
But then the aggragates are doubled initially and when I re-add the "number" column to the group by the aggregates are there only once but then the aggregate sorting buttons don't work(which makes sense since they are tied to the missing set of aggregates)
How do I make the aggregate sorting work with the aggregate defined in the column definition?