In this article I will explain how to display SubTotal and Grand Total in ASP.Net GridView using C# and VB.Net.
	The records are divided into Groups and then SubTotal is calculated for each Group and then displayed using a dynamic Row in GridView.
	 
	Database
	For this article I am making use of the Microsoft’s Northwind Database. Download and install instructions are provided in the link below.
	 
	HTML Markup
	The HTML Markup consists of an ASP.Net GridView which will display details of the Orders table present in the Northwind database. I have made use of OnRowCreated and OnDataBound events of GridView for displaying SubTotal and Grand Total.
	
		<asp:GridView ID = "GridView1" runat = "server" AutoGenerateColumns = "false" OnDataBound = "OnDataBound" OnRowCreated = "OnRowCreated">
	
		<Columns>
	
		    <asp:BoundField DataField = "OrderID" HeaderText = "Order ID" ItemStyle-Width = "60" />
	
		    <asp:BoundField DataField = "ProductName" HeaderText = "Product Name" ItemStyle-Width = "210" />
	
		    <asp:BoundField DataField = "Price" HeaderText = "Price" ItemStyle-Width = "60" DataFormatString = "{0:N2}" ItemStyle-HorizontalAlign = "Right" />
	
		</Columns>
	
		</asp:GridView>
 
 
 
	Namespaces
	You will need to import the following namespaces
	C#
	
		using System.Data;
	
		using System.Drawing;
	
		using System.Configuration;
	
		using System.Data.SqlClient;
 
	 
	VB.Net
	
		Imports System.Data
	
		Imports System.Drawing
	
		Imports System.Configuration
	
		Imports System.Data.SqlClient
 
 
 
	Binding the GridView
	The GridView is populated with records inside the Page Load event of the page. The Query gets records of few Orders along with their Products and their respective costs. This result will be used to calculate the SubTotal for each Order and then finally the Grand Total for all Orders.
	C#
	
		protected void Page_Load(object sender, EventArgs e)
	
		{
	
		    if (!IsPostBack)
	
		    {
	
		        this.BindGrid();
	
		    }
	
		}
	
		 
	
		private void BindGrid()
	
		{
	
		    string query = "SELECT OrderID,";
	
		    query += "(SELECT ProductName FROM Products WHERE ProductID = details.ProductId) ProductName,";
	
		    query += "(Quantity * UnitPrice) Price";
	
		    query += " FROM [Order Details] details";
	
		    query += " WHERE OrderID IN (10248, 10249, 10250)";
	
		    query += " ORDER BY OrderID";
	
		    string conString = ConfigurationManager.ConnectionStrings["constr"].ConnectionString;
	
		    using (SqlConnection con = new SqlConnection(conString))
	
		    {
	
		        using (SqlCommand cmd = new SqlCommand(query))
	
		        {
	
		            using (SqlDataAdapter sda = new SqlDataAdapter())
	
		            {
	
		                cmd.Connection = con;
	
		                sda.SelectCommand = cmd;
	
		                using (DataTable dt = new DataTable())
	
		                {
	
		                    sda.Fill(dt);
	
		                    GridView1.DataSource = dt;
	
		                    GridView1.DataBind();
	
		                }
	
		            }
	
		        }
	
		    }
	
		}
 
	 
	VB.Net
	
		Protected Sub Page_Load(sender As Object, e As EventArgs) Handles Me.Load
	
		    If Not IsPostBack Then
	
		        Me.BindGrid()
	
		    End If
	
		End Sub
	
		 
	
		Private Sub BindGrid()
	
		    Dim query As String = "SELECT OrderID,"
	
		    query += "(SELECT ProductName FROM Products WHERE ProductID = details.ProductId) ProductName,"
	
		    query += "(Quantity * UnitPrice) Price"
	
		    query += " FROM [Order Details] details"
	
		    query += " WHERE OrderID IN (10248, 10249, 10250)"
	
		    query += " ORDER BY OrderID"
	
		    Dim conString As String = ConfigurationManager.ConnectionStrings("constr").ConnectionString
	
		    Using con As New SqlConnection(conString)
	
		        Using cmd As New SqlCommand(query)
	
		            Using sda As New SqlDataAdapter()
	
		                cmd.Connection = con
	
		                sda.SelectCommand = cmd
	
		                Using dt As New DataTable()
	
		                    sda.Fill(dt)
	
		                    GridView1.DataSource = dt
	
		                    GridView1.DataBind()
	
		                End Using
	
		            End Using
	
		        End Using
	
		    End Using
	
		End Sub
 
 
 
	Calculating and displaying SubTotal and Grand Total in GridView
	I have declared some variables to calculate the SubTotal and the Grand Total so they need to be declared outside directly inside the class so that they are accessible inside all events and methods on the page.
	Inside the OnRowCreated event handler, first we need to get the DataTable that was used to populate the GridView using the DataItem object. Once we have the DataTable we can easily get the Price of each product and use it for calculation of SubTotal and Grand Total.
	The OrderId is continuously tracked using the currentId variable an as soon as a change is detected a new row is created and added to the GridView using the AddTotalRow method.
	C#
	
		int currentId = 0;
	
		decimal subTotal = 0;
	
		decimal total = 0;
	
		int subTotalRowIndex = 0;
	
		protected void OnRowCreated(object sender, GridViewRowEventArgs e)
	
		{
	
		    subTotal = 0;
	
		    if (e.Row.RowType == DataControlRowType.DataRow)
	
		    {
	
		        DataTable dt = (e.Row.DataItem as DataRowView).DataView.Table;
	
		        int orderId = Convert.ToInt32(dt.Rows[e.Row.RowIndex]["OrderID"]);
	
		        total += Convert.ToDecimal(dt.Rows[e.Row.RowIndex]["Price"]);
	
		        if (orderId != currentId)
	
		        {
	
		            if (e.Row.RowIndex > 0)
	
		            {
	
		                for (int i = subTotalRowIndex; i < e.Row.RowIndex; i++)
	
		                {
	
		                    subTotal += Convert.ToDecimal(GridView1.Rows[i].Cells[2].Text);
	
		                }
	
		                this.AddTotalRow("Sub Total", subTotal.ToString("N2"));
	
		                subTotalRowIndex = e.Row.RowIndex;
	
		            }
	
		            currentId = orderId;
	
		        }
	
		    }
	
		}
	
		 
	
		private void AddTotalRow(string labelText, string value)
	
		{
	
		    GridViewRow row = new GridViewRow(0, 0, DataControlRowType.DataRow, DataControlRowState.Normal);
	
		    row.BackColor = ColorTranslator.FromHtml("#F9F9F9");
	
		    row.Cells.AddRange(new TableCell[3] { new TableCell (), //Empty Cell
	
		                                        new TableCell { Text = labelText, HorizontalAlign = HorizontalAlign.Right}, 
	
		                                        new TableCell { Text = value, HorizontalAlign = HorizontalAlign.Right } });
	
		 
	
		    GridView1.Controls[0].Controls.Add(row);
	
		}
 
	 
	VB.Net
	
		Private currentId As Integer = 0
	
		Private subTotal As Decimal = 0
	
		Private total As Decimal = 0
	
		Private subTotalRowIndex As Integer = 0
	
		Protected Sub OnRowCreated(sender As Object, e As GridViewRowEventArgs)
	
		    subTotal = 0
	
		    If e.Row.RowType = DataControlRowType.DataRow Then
	
		        Dim dt As DataTable = TryCast(e.Row.DataItem, DataRowView).DataView.Table
	
		        Dim orderId As Integer = Convert.ToInt32(dt.Rows(e.Row.RowIndex)("OrderID"))
	
		        total += Convert.ToDecimal(dt.Rows(e.Row.RowIndex)("Price"))
	
		        If orderId <> currentId Then
	
		            If e.Row.RowIndex > 0 Then
	
		                For i As Integer = subTotalRowIndex To e.Row.RowIndex - 1
	
		                    subTotal += Convert.ToDecimal(GridView1.Rows(i).Cells(2).Text)
	
		                Next
	
		                Me.AddTotalRow("Sub Total", subTotal.ToString("N2"))
	
		                subTotalRowIndex = e.Row.RowIndex
	
		            End If
	
		            currentId = orderId
	
		        End If
	
		    End If
	
		End Sub
	
		 
	
		Private Sub AddTotalRow(labelText As String, value As String)
	
		    Dim row As New GridViewRow(0, 0, DataControlRowType.DataRow, DataControlRowState.Normal)
	
		    row.BackColor = ColorTranslator.FromHtml("#F9F9F9")
	
		    'Empty Cell
	
		    row.Cells.AddRange(New TableCell(2) {New TableCell(), New TableCell() With { _
	
		      .Text = labelText, _
	
		      .HorizontalAlign = HorizontalAlign.Right _
	
		    }, New TableCell() With { _
	
		      .Text = value, _
	
		      .HorizontalAlign = HorizontalAlign.Right _
	
		    }})
	
		 
	
		    GridView1.Controls(0).Controls.Add(row)
	
		End Sub
 
	 
	The OnRowCreated event calculates SubTotal of all Groups except the last one since after the last row is added the OnRowCreated event does not fire and hence the SubTotal Row for the last Group cannot be added.
	To handle this problem, I have made use of the OnDataBound event that occurs after the GridView is completely populated with data. Here the SubTotal as well as the Grand Total Row are added to the GridView.
	C#
	
		protected void OnDataBound(object sender, EventArgs e)
	
		{
	
		    for (int i = subTotalRowIndex; i < GridView1.Rows.Count; i++)
	
		    {
	
		        subTotal += Convert.ToDecimal(GridView1.Rows[i].Cells[2].Text);
	
		    }
	
		    this.AddTotalRow("Sub Total", subTotal.ToString("N2"));
	
		    this.AddTotalRow("Total", total.ToString("N2"));
	
		}
 
	 
	VB.Net
	
		Protected Sub OnDataBound(sender As Object, e As EventArgs)
	
		    For i As Integer = subTotalRowIndex To GridView1.Rows.Count - 1
	
		        subTotal += Convert.ToDecimal(GridView1.Rows(i).Cells(2).Text)
	
		    Next
	
		    Me.AddTotalRow("Sub Total", subTotal.ToString("N2"))
	
		    Me.AddTotalRow("Total", total.ToString("N2"))
	
		End Sub
 
	 
 
 
	Demo
	 
	Downloads