Custom Group Comparer
RadPivotGrid uses the GroupComparer class to determine the order of groups within rows and columns. The two built-in comparers, GroupNameComparer and GrandTotalComparer, cover common scenarios such as sorting groups alphabetically or by their aggregate totals. When neither fits your requirements, you can create a custom comparer by inheriting the GroupComparer base class.
Understanding the GroupComparer Class
The GroupComparer abstract class resides in the Telerik.Pivot.Core namespace. It exposes a single abstract method that you must override:
public abstract int CompareGroups(IAggregateResultProvider results, IGroup left, IGroup right, PivotAxis axis);
The parameters provide the following information:
results—Gives access to the current aggregate values throughGetAggregateResultand the root groups through theRootproperty.leftandright—The twoIGroupinstances being compared. Each group exposes aNameproperty (the group key), aLevel, and a reference to itsParentgroup.axis—Indicates whether the groups belong toPivotAxis.RowsorPivotAxis.Columns.
The method returns a signed integer following the standard comparison contract—a negative value when left precedes right, zero when they are equal, and a positive value when left follows right.
Because GroupComparer inherits from Cloneable, you must also override CreateInstanceCore and CloneCore.
Creating a Custom GroupComparer
The following example demonstrates a custom comparer that orders groups by the length of their names. Groups with shorter names appear first.
Defining the Custom Comparer
public class NameLengthComparer : GroupComparer
{
public override int CompareGroups(IAggregateResultProvider results, IGroup left, IGroup right, PivotAxis axis)
{
string leftName = left.Name != null ? left.Name.ToString() : string.Empty;
string rightName = right.Name != null ? right.Name.ToString() : string.Empty;
return leftName.Length.CompareTo(rightName.Length);
}
protected override Cloneable CreateInstanceCore()
{
return new NameLengthComparer();
}
protected override void CloneCore(Cloneable source)
{
}
}
Assigning the Custom Comparer
Set the GroupComparer property on the target PropertyGroupDescription or DateTimeGroupDescription. The SortOrder property controls whether the comparer result is applied in ascending or descending direction.
Using the Custom Comparer
PropertyGroupDescription groupDescription = (PropertyGroupDescription)this.radPivotGrid1.RowGroupDescriptions[0];
groupDescription.GroupComparer = new NameLengthComparer();
groupDescription.SortOrder = Telerik.Pivot.Core.SortOrder.Ascending;
this.radPivotGrid1.ReloadData();
Using Aggregate Values in a Custom Comparer
A custom comparer can also use aggregate results. The following example compares groups based on the aggregate value at a specific index, falling back to group name comparison when the aggregate values are equal.
Defining a Comparer with Aggregate Access
public class AggregateWithFallbackComparer : GroupComparer
{
private int aggregateIndex;
public int AggregateIndex
{
get { return this.aggregateIndex; }
set
{
if (this.aggregateIndex != value)
{
this.aggregateIndex = value;
this.OnPropertyChanged("AggregateIndex");
}
}
}
public override int CompareGroups(IAggregateResultProvider results, IGroup left, IGroup right, PivotAxis axis)
{
Coordinate leftCoordinate;
Coordinate rightCoordinate;
if (axis == PivotAxis.Rows)
{
leftCoordinate = new Coordinate(left, results.Root.ColumnGroup);
rightCoordinate = new Coordinate(right, results.Root.ColumnGroup);
}
else
{
leftCoordinate = new Coordinate(results.Root.RowGroup, left);
rightCoordinate = new Coordinate(results.Root.RowGroup, right);
}
AggregateValue leftAggregate = results.GetAggregateResult(this.AggregateIndex, leftCoordinate);
AggregateValue rightAggregate = results.GetAggregateResult(this.AggregateIndex, rightCoordinate);
object leftValue = leftAggregate != null ? leftAggregate.GetValue() : null;
object rightValue = rightAggregate != null ? rightAggregate.GetValue() : null;
if (leftValue is AggregateError)
{
leftValue = null;
}
if (rightValue is AggregateError)
{
rightValue = null;
}
int result = System.Collections.Comparer.Default.Compare(leftValue, rightValue);
if (result == 0)
{
IComparable leftName = left.Name as IComparable;
if (leftName != null && right.Name != null)
{
return leftName.CompareTo(right.Name);
}
}
return result;
}
protected override Cloneable CreateInstanceCore()
{
return new AggregateWithFallbackComparer();
}
protected override void CloneCore(Cloneable source)
{
AggregateWithFallbackComparer comparer = source as AggregateWithFallbackComparer;
if (comparer != null)
{
this.AggregateIndex = comparer.AggregateIndex;
}
}
}
When the comparer exposes additional properties (such as
AggregateIndex), copy their values in theCloneCoreoverride. This ensures the comparer state is preserved when the pivot engine clones group descriptions internally.