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

Custom Aggregate on a templated column with grouping

18 Answers 540 Views
Grid
This is a migrated thread and some comments may be shown as answers.
Albert Shenker
Top achievements
Rank 1
Veteran
Iron
Albert Shenker asked on 15 Oct 2008, 06:33 AM
I have a grid which uses grouping. I would like to implement some functionality that calculates some group-level stats on some of the columns in the grid, however I need to use TemplateColumns, so the built-in aggregates won't work. I am able to do the calculation in the grid's ItemDataBound event, however, at this point in the grid cycle, I don't have access to know which group i am in so the calculations won't be made on a group-level, as I want. Does anyone know how to accomplish this? A simple example would be a grid with a Template column which shows an Integer (the template column is needed for a variety of treasons which aren't pertinent). I would like the group header (or footer) to show a calculation made on this column (such as the number of items in the group which are greater than some fixed value)

18 Answers, 1 is accepted

Sort by
0
Shinu
Top achievements
Rank 2
answered on 15 Oct 2008, 11:28 AM
Hi Albert,

Try the following approach and see if it is helpful.

ASPX:
<telerik:GridTemplateColumn DataField="SupplierID"   HeaderText="SupplierID" SortExpression="SupplierID" UniqueName="SupplierID" DataType="System.Int32" > 
 <ItemTemplate> 
     <asp:Label ID="Label1" runat="server" Text='<%#Eval("SupplierID") %>'></asp:Label> 
 </ItemTemplate> 
</telerik:GridTemplateColumn> 

CS:
 protected void RadGrid1_PreRender(object sender, EventArgs e) 
    { 
        foreach (GridGroupHeaderItem groupHeader in RadGrid1.MasterTableView.GetItems(GridItemType.GroupHeader)) 
        { 
            GridItem[] children = groupHeader.GetChildItems(); 
            foreach (GridDataItem child in children) 
            { 
                GridDataItem childchildItem = child as GridDataItem; 
                Label lbl = (Label)childItem["SupplierID"].FindControl("Label1"); 
                total += Double.Parse(lbl.Text); 
 
                
            } 
            Label lbl1 = new Label(); 
            lbl1.ID = "Label2"
            lbl1.Text = string.Empty; 
            lbl1.Text = total.ToString(); ; 
            groupHeader.DataCell.Controls.Add(lbl1); 
        } 
    } 


Thanks
Shinu.
0
Albert Shenker
Top achievements
Rank 1
Veteran
Iron
answered on 16 Oct 2008, 10:46 AM
Thanks for the suggestion, however, in my real application, I will not be able to perform the aggregate calculation by simply reading the column text. The function is far too complicated, so I need to have access to the actual underlying dataitem. I have access to this in the Itemdatabound event, however, I don;t seem to have access to the necessary GroupIndex here. In the prerender event, I have access to the group index, but not the uderlying data which i need.
0
Albert Shenker
Top achievements
Rank 1
Veteran
Iron
answered on 16 Oct 2008, 04:02 PM
I think I figured out how to do this. I am able to get access to the underlying data at pre-render by accessing the GridGroupHeaderItem children, and then casting to my custom object. Furthermore, I can parse the GroupIndex property in order to loop through and set the proper headers for the hierarchical groups. Thanks for the lead!
0
Priya
Top achievements
Rank 1
answered on 31 Dec 2008, 11:13 PM
I have seen the above code for adding a control in the GridGroupHeaderItem. But How do I add a control into a GroupFooterItem?
I have a grid that uses grouping and I need to display the aggregate of a template column in the footer.
0
Shinu
Top achievements
Rank 2
answered on 02 Jan 2009, 06:58 AM
Hi Priya,

You can add control to the GridGroupFooter as shown below.

CS:
foreach(GridGroupFooterItem footer in RadGrid1.MasterTableView.GetItems(GridItemType.GroupFooter) ) 
        { 
            Label lbl =new Label(); 
            lbl.ID="Label1"
            lbl.Text="CustomText"
            footer.Cells[3].Controls.Add(lbl); 
 
        } 



Thanks
Shinu
0
Priya
Top achievements
Rank 1
answered on 02 Jan 2009, 01:44 PM
Cells[3] was what I was missing. Thank you. It worked!
0
Mike
Top achievements
Rank 1
answered on 15 Feb 2010, 04:29 PM
I am trying this approach using the prerender and  adding this to the radGrid
 OnPreRender="RadGrid1_PreRender"  

<telerik:GridTemplateColumn HeaderText="Avg" ItemStyle-HorizontalAlign="Center" UniqueName="AvgPrice">  
   <ItemTemplate> 
       <asp:Label ID="LabelAvgPrice" runat="server" /> 
   </ItemTemplate> 
</telerik:GridTemplateColumn> 

 protected void RadGrid1_ItemDataBound(object sender, GridItemEventArgs e)  
    {  
        if (e.Item is GridDataItem)  
        {  
         Label avgPrice = (Label)e.Item.Cells[0].FindControl("LabelAvgPrice");  
          avgPrice.Text = Convert.ToString(CalculateThis(value1,value2));  
        }  
    }  
 

But I am getting the following error, your help would be greatly appreciated..


Compiler Error Message: CS0103: The name 'childItem' does not exist in the current context

Source Error:

Line 176:            {
Line 177:                GridDataItem childchildItem = child as GridDataItem;
Line 178: Label lbl = (Label)childItem["AvgPrice"].FindControl("LabelAvgPrice");    
Line 179: total += Double.Parse(lbl.Text); Line 180: }
0
Albert Shenker
Top achievements
Rank 1
Veteran
Iron
answered on 15 Feb 2010, 04:40 PM
The error message is pointing you to your problem (line 178). It doesn't appear that you have defined childItem. It looks like you defined childchildItem.
0
Mike
Top achievements
Rank 1
answered on 15 Feb 2010, 04:43 PM
Thank you for the quick response, how do I define the childitem?  I am grouping this grid on four columns.
0
Albert Shenker
Top achievements
Rank 1
Veteran
Iron
answered on 15 Feb 2010, 05:00 PM
Here's an example in VB. You'll need to get Telerik Support if you can't translate this into C#, but I believe a close example is below in the Oct 15, 2008 post from Telerik. I have noticed that the Telerik Posts contain what appear to be some syntax errors, perhaps caused by the message board pasting mechanism. This seemed to cause the childchildItem issue. Anyhow, if you change childchildItem in their example to just childItem, it might work, but I am unfamiliar with the C# syntax on that line, so you will need to check with them.

    
Private Sub MyGrid_PreRender(ByVal sender As ObjectByVal e As System.EventArgs) Handles MyGrid.PreRender  
 
    For Each grpHeaderItem As GridGroupHeaderItem In MyGrid.MasterTableView.GetItems(GridItemType.GroupHeader)  
 
        Dim index As Integer = grpHeaderItem.GroupIndex  
 
        For Each childItem As GridItem In grpHeaderItem.GetChildItems()  
 
            If TypeOf (childItem) Is GridDataItem Then 
 
                Dim obj As MyCustomObject = DirectCast(childItem.DataItem, MyCustomObject)  
 
                ' Now I have a reference to the underlying data object, as well as the group index  
 
            End If 
 
        Next 
    Next 
 
End Sub 

you will notice in the original post here, that the Telerik agen uses C#, and also there appears to be sme syntax issue with their code (the appearance of childchildItem). I think if you changed this to just
0
Mike
Top achievements
Rank 1
answered on 15 Feb 2010, 05:10 PM
I am using this

 protected void RadGrid1_PreRender(object sender, EventArgs e)  
    {  
        foreach (GridGroupHeaderItem groupHeader in RadGrid1.MasterTableView.GetItems(GridItemType.GroupHeader))  
        {  
            GridItem[] children = groupHeader.GetChildItems();  
            foreach (GridDataItem child in children)  
            {  
                GridDataItem childchildchildItem = child as GridDataItem;  
                Label lbl = (Label)childItem["AvgPrice"].FindControl("LabelAvgPrice");  
                total += Double.Parse(lbl.Text);  
            }  
            Label lbl = new Label();  
            lbl.ID = "LabelAvgPrice";  
            lbl.Text = "CustomText";  
            footer.Cells[12].Controls.Add(lbl);    
 
        }  
    }   

I used your converter to generate this from your code and it throws the following error.
Compiler Error Message: CS0029: Cannot implicitly convert type 'string' to 'int'

Source Error:

Line 181:        foreach (GridGroupHeaderItem grpHeaderItem in RadGrid1.MasterTableView.GetItems(GridItemType.GroupHeader))
Line 182:        {
Line 183: int index = grpHeaderItem.GroupIndex;Line 184:            foreach (GridItem childItem in grpHeaderItem.GetChildItems())
Line 185:            {

 private void RadGrid1_PreRender(object sender, System.EventArgs e)  
    {  
        foreach (GridGroupHeaderItem grpHeaderItem in RadGrid1.MasterTableView.GetItems(GridItemType.GroupHeader))  
        {  
            int index = grpHeaderItem.GroupIndex;  
            foreach (GridItem childItem in grpHeaderItem.GetChildItems())  
            {  
                if ((childItem) is GridDataItem)  
                {  
                    MyCustomObject obj = (MyCustomObject)childItem.DataItem;  
                    // Now I have a reference to the underlying data object, as well as the group index     
                }  
            }  
        }  
    } 
0
Albert Shenker
Top achievements
Rank 1
Veteran
Iron
answered on 15 Feb 2010, 05:21 PM
Again, there appears to be some issue in the message board C# code pasting functionality. It keeps appending "child" to the variable name, which isn't right.
0
Mike
Top achievements
Rank 1
answered on 15 Feb 2010, 05:23 PM
I see that and have update it and it blows up on "total' now, where is that defined?

 protected void RadGrid1_PreRender(object sender, EventArgs e)  
    {  
        foreach (GridGroupHeaderItem groupHeader in RadGrid1.MasterTableView.GetItems(GridItemType.GroupHeader))  
        {  
            GridItem[] children = groupHeader.GetChildItems();  
            foreach (GridDataItem child in children)  
            {  
                GridDataItem childItem = child as GridDataItem;  
                Label lbl = (Label)childItem["AvgPrice"].FindControl("LabelAvgPrice");  
                total += Double.Parse(lbl.Text);  
            }  
            Label lbl1 = new Label();  
            lbl1.ID = "LabelAvgPrice";  
            lbl1.Text = "0.00";  
            groupHeader.DataCell.Controls.Add(lbl1);   
 
        }  
    } 

Compiler Error Message: CS0103: The name 'total' does not exist in the current context

Source Error:

Line 166:                GridDataItem childItem = child as GridDataItem;
Line 167:                Label lbl = (Label)childItem["AvgPrice"].FindControl("LabelAvgPrice");
Line 168: total += Double.Parse(lbl.Text);Line 169:            }
Line 170:            Label lbl1 = new Label();
0
Mike
Top achievements
Rank 1
answered on 15 Feb 2010, 05:23 PM
Sorry, double post... but I think we are close.. if we can get this recent error resolved.
0
Albert Shenker
Top achievements
Rank 1
Veteran
Iron
answered on 15 Feb 2010, 05:29 PM
The variable total is never defined. You need to define the variable prior to setting its value. Again, I don't write in C#, but I think you can do:

Double total = 0;

prior to the line where you set the value.
0
Mike
Top achievements
Rank 1
answered on 15 Feb 2010, 05:34 PM
I appreciate your assitance Albert, the error is gone but I don't see the label in the grouped footer.
0
Albert Shenker
Top achievements
Rank 1
Veteran
Iron
answered on 15 Feb 2010, 05:48 PM
I believe the examples here will add the label to the group header, not the group footer. I see in one of your examples you use the varialbe "footer", but i'm not sure what that refers to.

 If you can't get it to work, I would suggest you submit a formal support ticket to Telerik.
0
Phil H.
Top achievements
Rank 2
answered on 10 Sep 2014, 02:17 PM
Hi All:

I downloaded the 'sample' code.  This is my version of the Calculate function (hope it helps):
//
/// <summary>
/// Calculate the custom aggregate function
/// </summary>
/// <param name="grid">the RadGrid</param>
/// <param name="group">current group of row items to apply the aggregate function</param>
/// <returns>weighted average price</returns>
protected decimal CalculateWeightedAverage(RadGrid grid, GridGroupHeaderItem @group)
{
    try {
        int _weightCol = grid.MasterTableView.GetColumn("ContractedLbs").OrderIndex;
        int _priceCol = grid.MasterTableView.GetColumn("ContractedPrice").OrderIndex;
        decimal _groupWeightedPrice = 0m;
        int _groupTotalWeight = 0;
        foreach (GridItem _item in @group.GetChildItems()) {
            if (_item is GridDataItem) {
                string _weightStr = _item.Cells(_weightCol).Text;
                string _priceStr = _item.Cells(_priceCol).Text;
                _groupWeightedPrice += Convert.ToDecimal(_priceStr) * Convert.ToInt32(_weightStr);
                _groupTotalWeight += Convert.ToInt32(_weightStr);
            }
        }
        if (_groupTotalWeight != 0) {
            return _groupWeightedPrice / _groupTotalWeight;
        }
    } catch {
    }
    return 0.0;
}

Phil
Tags
Grid
Asked by
Albert Shenker
Top achievements
Rank 1
Veteran
Iron
Answers by
Shinu
Top achievements
Rank 2
Albert Shenker
Top achievements
Rank 1
Veteran
Iron
Priya
Top achievements
Rank 1
Mike
Top achievements
Rank 1
Phil H.
Top achievements
Rank 2
Share this question
or