In this article I will explain how to dynamically add BoundField and TemplateField column to GridView in ASP.Net using C# and VB.Net.
Dynamic BoundField and TemplateField columns will be created and then added to GridView after that the GridView will be populated from database. At runtime using the OnRowDataBound event of GridView, controls like TextBox, Button, etc. will be added to the Dynamic TemplateField columns.
This article also covers the problem of dynamic columns disappearing on PostBack and describes the necessary solution to retain the dynamic columns on PostBack.
Finally this article explains how to handle click events of dynamic Button, LinkButton or ImageButton that will be added to the dynamic TemplateField columns and also explains how to fetch values from the dynamic BoundField and TemplateField columns when thee Buttons are clicked.
 
HTML Markup
The HTML Markup consists of an HTML GridView with no columns defined.
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns = "false" OnRowDataBound = "OnRowDataBound">
</asp:GridView>
 
 
Namespaces
You will need to import the following namespaces
C#
using System.Data;
 
VB.Net
Imports System.Data
 
 
Adding dynamic BoundField and TemplateField columns and binding the GridView
A BoundField and two TemplateField columns are dynamically created and added to the GridView control.
For the BoundField column, DataField property has been defined, which is the name of the column that will be populated within it.
For the TemplateField, only HeaderText property has been set as we will have to first add controls to its ItemTemplate before we can bind data.
Once the dynamic BoundField and TemplateField columns are added, the GridView is populated using some dummy records using DataTable inside the BindGrid method.
Note: The BindGrid method is called outside the Not IsPostBack condition, this is necessary to retain the dynamic BoundField and TemplateField columns and its data.
C#
protected void Page_Load(object sender, EventArgs e)
{
    if (!this.IsPostBack)
    {
        BoundField bfield = new BoundField();
        bfield.HeaderText = "Name";
        bfield.DataField = "Name";
        GridView1.Columns.Add(bfield);
 
        TemplateField tfield = new TemplateField();
        tfield.HeaderText = "Country";
        GridView1.Columns.Add(tfield);
 
        tfield = new TemplateField();
        tfield.HeaderText = "View";
        GridView1.Columns.Add(tfield);
    }
    this.BindGrid();
}
 
private void BindGrid()
{
    DataTable dt = new DataTable();
    dt.Columns.AddRange(new DataColumn[3] { new DataColumn("Id", typeof(int)),
                        new DataColumn("Name", typeof(string)),
                        new DataColumn("Country",typeof(string)) });
    dt.Rows.Add(1, "John Hammond", "United States");
    dt.Rows.Add(2, "Mudassar Khan", "India");
    dt.Rows.Add(3, "Suzanne Mathews", "France");
    dt.Rows.Add(4, "Robert Schidner", "Russia");
    GridView1.DataSource = dt;
    GridView1.DataBind();
}
 
VB.Net
Protected Sub Page_Load(sender As Object, e As EventArgs) Handles Me.Load
    If Not Me.IsPostBack Then
        Dim bfield As New BoundField()
        bfield.HeaderText = "Name"
        bfield.DataField = "Name"
        GridView1.Columns.Add(bfield)
 
        Dim tfield As New TemplateField()
        tfield.HeaderText = "Country"
        GridView1.Columns.Add(tfield)
 
        tfield = New TemplateField()
        tfield.HeaderText = "View"
        GridView1.Columns.Add(tfield)
    End If
    Me.BindGrid()
End Sub
 
Private Sub BindGrid()
    Dim dt As New DataTable()
    dt.Columns.AddRange(New DataColumn(2) {New DataColumn("Id", GetType(Integer)), New DataColumn("Name", GetType(String)), New DataColumn("Country", GetType(String))})
    dt.Rows.Add(1, "John Hammond", "United States")
    dt.Rows.Add(2, "Mudassar Khan", "India")
    dt.Rows.Add(3, "Suzanne Mathews", "France")
    dt.Rows.Add(4, "Robert Schidner", "Russia")
    GridView1.DataSource = dt
    GridView1.DataBind()
End Sub
 
 
Adding controls and binding data to dynamic TemplateField Columns
Inside the OnRowDataBound event of the GridView, the process of adding controls like TextBox, DropDownLists. Buttons, etc. to the ItemTemplate of the TemplateField columns are carried out.
Firstly a TextBox is added to the 2nd Column of GridView which is a TemplateField and it is also bound with data from the Row DataItem object.
Then to the 3rd TemplateField column of GridView, a LinkButton is added dynamically. To the LinkButton, a dynamic click event handler is attached and the ID field from the Row DataItem object is set to the CommandArgument property.
C#
protected void OnRowDataBound(object sender, GridViewRowEventArgs e)
{
    if (e.Row.RowType == DataControlRowType.DataRow)
    {
        TextBox txtCountry = new TextBox();
        txtCountry.ID = "txtCountry";
        txtCountry.Text = (e.Row.DataItem as DataRowView).Row["Country"].ToString();
        e.Row.Cells[1].Controls.Add(txtCountry);
 
        LinkButton lnkView = new LinkButton();
        lnkView.ID = "lnkView";
        lnkView.Text = "View";
        lnkView.Click += ViewDetails;
        lnkView.CommandArgument = (e.Row.DataItem as DataRowView).Row["Id"].ToString();
        e.Row.Cells[2].Controls.Add(lnkView);
    }
}
 
VB.Net
Protected Sub OnRowDataBound(sender As Object, e As GridViewRowEventArgs)
    If e.Row.RowType = DataControlRowType.DataRow Then
        Dim txtCountry As New TextBox()
        txtCountry.ID = "txtCountry"
        txtCountry.Text = TryCast(e.Row.DataItem, DataRowView).Row("Country").ToString()
        e.Row.Cells(1).Controls.Add(txtCountry)
 
        Dim lnkView As New LinkButton()
        lnkView.ID = "lnkView"
        lnkView.Text = "View"
        AddHandler lnkView.Click, AddressOf ViewDetails
        lnkView.CommandArgument = TryCast(e.Row.DataItem, DataRowView).Row("Id").ToString()
        e.Row.Cells(2).Controls.Add(lnkView)
    End If
End Sub
 
Dynamically add BoundField and TemplateField Columns to GridView in ASP.Net
 
Click Event handler of the dynamic TemplateField column LinkButton
Below is the code for the click event handler that is raised when the LinkButton inside the dynamic TemplateField column is clicked, here all the three values namely Id, Name and Country from the GridView Row and the displayed in JavaScript alert message box.
C#
protected void ViewDetails(object sender, EventArgs e)
{
    LinkButton lnkView = (sender as LinkButton);
    GridViewRow row = (lnkView.NamingContainer as GridViewRow);
    string id = lnkView.CommandArgument;
    string name = row.Cells[0].Text;
    string country = (row.FindControl("txtCountry") as TextBox).Text;
    ClientScript.RegisterStartupScript(this.GetType(), "alert", "alert('Id: " + id + " Name: " + name + " Country: " + country + "')", true);
}
 
VB.Net
Protected Sub ViewDetails(sender As Object, e As EventArgs)
    Dim lnkView As LinkButton = TryCast(sender, LinkButton)
    Dim row As GridViewRow = TryCast(lnkView.NamingContainer, GridViewRow)
    Dim id As String = lnkView.CommandArgument
    Dim name As String = row.Cells(0).Text
    Dim country As String = TryCast(row.FindControl("txtCountry"), TextBox).Text
    ClientScript.RegisterStartupScript(Me.[GetType](), "alert", (Convert.ToString((Convert.ToString((Convert.ToString("alert('Id: ") & id) + " Name: ") & name) + " Country: ") & country) + "')", True)
End Sub
 
Dynamically add BoundField and TemplateField Columns to GridView in ASP.Net
 
Demo
 
Downloads