The GridView control is one of the most powerful controls in ASP.NET 2.0. It allows you to display the data in a nice tabular form. It allows you to do paging, sorting, editing, deleting with little or no code at all. Along with all these cool features GridView also allows us to use databinding in a new fashion. In this article I will demonstrate how to bind data to the GridView control under different scenarios.



Introduction:

The GridView control is one of the most powerful controls in ASP.NET 2.0. It allows you to display the data in a nice tabular form. It allows you to do paging, sorting, editing, deleting with little or no code at all. Along with all these cool features GridView also allows us to use databinding in a new fashion. In this article I will demonstrate how to bind data to the GridView control under different scenarios.

Basic DataBinding:

I will not be using DataSets in this article. I apologize for all the DataSet lovers but this article will demonstrate the power of entity classes and GridView data binding. I will be using different classes throughout the article and explain them as needed. Let's check out the User class which plays a prominent role in this article.

 
public class User
{
    private int userID;
    private string firstName;
    private string lastName;
    private string fullName;

    public int UserID
    {
        get { return this.userID; }
        set { this.userID = value; }
    }

    public string FirstName
    {
        get { return this.firstName; }
        set { this.firstName = value; }
    }

    public string LastName
    {
        get { return this.lastName; }
        set { this.lastName = value; }
    }
    

    public string FullName
    {
        get { return this.fullName; }
        set { this.fullName = value; }
    }    
    public User()
    {
        
    }
}



The User class contains few fields and properties. Now, let's check out the method which gets all the users from the database and inserts them into a generic user list.


 public static List<User> GetUsers()
    {
        List<User> users = new List<User>();

        string connectionString = @"Server=localhost;Database=School;Trusted_Connection=true";

        using (SqlConnection myConnection = new SqlConnection(connectionString))
        {
            SqlCommand myCommand = new SqlCommand("SELECT UserID, (FirstName + ' ' + LastName) AS FullName FROM Users",myConnection);

            myConnection.Open();
            SqlDataReader reader = myCommand.ExecuteReader();
            while (reader.Read())
            {
                User user = new User();
                user.UserID =  (int) reader["UserID"];
                user.FullName = reader["FullName"] as String;

                users.Add(user);
            }
        }
       

        return users;
    }


The GetUsers() method simply returns generic collection of users to the caller. I am using the using statement which ensures that the connection will be closed after it has been used.

The HTML code for the GridView is pretty simply as shown below:

 <asp:GridView ID="gvUsers" runat="server" AutoGenerateColumns="true"/>

 

As, you can see in the above image that the GridView is displayed with all the properties of the User class even though I only populated and selected "UserID" and "FullName". This is because the GridView is set to AutoGenerateColumns="true" which means that it will automatically generate the columns for all the properties of the User class.

DataBinding with TemplateFields:

Most, of the time we only want selected columns to be displayed in the GridView control. In that case we use the GridView TemplateField columns or BoundField. TemplateField gives you the flexibility to change the title of the column and add other controls inside the GridView rows.

In order to use the TemplateField all you need to do is make the template columns in the GridView. Check out the code below which create three template fields.

<asp:GridView ID="gvUsers" AutoGenerateColumns="false" runat="server">
    
    <Columns>
    
    <asp:TemplateField HeaderText="User ID Number">
    <ItemTemplate>
    <asp:Label ID="lblUserID" runat="server" Text='<%# Eval("UserID") %>' />
    </ItemTemplate>    
    </asp:TemplateField>
    
     <asp:TemplateField HeaderText="First Name">
    <ItemTemplate>
    <asp:Label ID="lblFirstName" runat="server" Text='<%# Eval("FirstName") %>' />
    </ItemTemplate>    
    </asp:TemplateField>
    
     <asp:TemplateField HeaderText="Last Name">
    <ItemTemplate>
    <asp:Label ID="lblLastName" runat="server" Text='<%# Eval("LastName") %>' />
    </ItemTemplate>    
    </asp:TemplateField>
    
    
    </Columns>
    
    </asp:GridView>



Complex DataBinding (Single Field):

In a real world application you might come across relations. Objects of one type may have relations with object of another type. Consider a simple example of User and Address. User can have address. Actually, user can have addresses (means List<Address>) but right now let's keep the example simple and say that user can have an address. This relation can be represented in the User class as shown below:

private Address address = new Address();

 public Address Address
    {
        get { return this.address; }
        set { this.address = value; }
    }


Here Address is another class defined below:

public class Address
{
    private int addressID;
    private string city;
    private string state;
    private string street;
    private string zipcode;

    public int AddressID
    {
        get { return this.addressID; }
        set { this.addressID = value; }
    }

    public string City
    {
        get { return this.city; }
        set { this.city = value; }
    }

    public string State
    {
        get { return this.state; }
        set { this.state = value; }
    }

    public string Street
    {
        get { return this.street; }
        set { this.street = value; }
    }

    public string ZipCode
    {
        get { return this.zipcode; }
        set { this.zipcode = value; }
    }



    public Address()
    {
        
    }
}



Let's say that you want to populate the List<User> with all the users and their address. You can use the following code:

 public static List<User> GetUsersWithAddress()
    {
        string connectionString = @"Server=localhost;Database=School;Trusted_Connection=true";
        string selectQuery = @"SELECT FirstName, LastName FROM Users";

        List<User> users = new List<User>();
        int counter = 1;

        using (SqlConnection myConnection = new SqlConnection(connectionString))
        {
            myConnection.Open();
            SqlCommand myCommand = new SqlCommand(selectQuery, myConnection);

            SqlDataReader reader = myCommand.ExecuteReader();
            while (reader.Read())
            {
                User user = new User();
                user.FirstName = reader["FirstName"] as String;
                user.LastName = reader["LastName"] as String;
                user.Address.State = "State" + counter;
                user.Address.City = "City" + counter;
                user.Address.Street = "Street" + counter;
                user.Address.ZipCode = "ZipCode" + counter;
                

                users.Add(user);

                counter++;
            }
        }

        return users;
    }



In the above code I am just using dummy addresses and assigning to each of the Users. The question comes that how are we going to show the address of the User on the screen inside the GridView. Let's check out the GridView HTML code which is used to display the user information along with the address.


 <asp:TemplateField HeaderText="First Name" >
    <ItemTemplate>
    <asp:Label ID="lblFirstName" runat="server"  Text='<%# Eval("FirstName") %>' />
    </ItemTemplate>    
    </asp:TemplateField>
    
     <asp:TemplateField HeaderText="Last Name" >
    <ItemTemplate>
    <asp:Label ID="lblLastName" runat="server"  Text='<%# Eval("LastName") %>' />
    </ItemTemplate>    
    </asp:TemplateField>
    
     <asp:TemplateField HeaderText="State" >
    <ItemTemplate>
    <asp:Label ID="lblState" runat="server"  Text='<%# ((Address) Eval("Address")).State %>' />
    </ItemTemplate>    
    </asp:TemplateField>
    
     <asp:TemplateField HeaderText="City" >
    <ItemTemplate>
    <asp:Label ID="lblCity" runat="server"  Text='<%# ((Address) Eval("Address")).City %>' />
    </ItemTemplate>    
    </asp:TemplateField>
    
     <asp:TemplateField HeaderText="Street" >
    <ItemTemplate>
    <asp:Label ID="lblStreet" runat="server"  Text='<%# ((Address) Eval("Address")).Street %>' />
    </ItemTemplate>    
    </asp:TemplateField>
    
     <asp:TemplateField HeaderText="Zip Code" >
    <ItemTemplate>
    <asp:Label ID="lblZipCode" runat="server"  Text='<%# ((Address) Eval("Address")).ZipCode %>' />
    </ItemTemplate>    
    </asp:TemplateField>



Now, let's check out the code above. The fields "FirstName" and "LastName" are simply the properties of the User class hence they are binded easily. The real challenge was with the address. I am using the following notation to bind the address to the GridView.

<%# ((Address) Eval("Address")).State %>

Let's analyze this more closely. Eval("Address") represents the User's class property. Then ((Address) Eval("Address")) means that the property "Address" is of type Address. And finally when the casting is done we can access the properties defined in the Address class using the syntax ((Address) Eval("Address")).State. As, you can see that I have used the same procedure to

access different properties of the Address class.

 


Complex DataBinding (Binding With a Child List):

In the previous section I discussed the one to one relationship binding. In this section I will discuss one to many relationship bindings. The one to many relationship is the most common type of relationship used in the applications. Let's assume that we need to find the tasks associated with the users. One user can perform many tasks. This means that the relationship between the User and the Task is one to many. For this we need to add a List<Task> field to our user class.

private List<Task> taskList = new List<Task>();

  public List<Task> TaskList
    {
        get { return this.taskList; }
        set { this.taskList = value; }
    }



And the Task class is defined as follows:

public class Task
{
    private int taskID;
    private string name;
    private string description;
   

    public int TaskID
    {
        get { return this.taskID; }
        set { this.taskID = value; }
    }

    public string Name
    {
        get { return this.name; }
        set { this.name = value; }
    }

    public string Description
    {
        get { return this.description; }
        set { this.description = value; }
    }
      
    public Task(int taskID, string name, string description)
    {
        this.taskID = taskID;
        this.name = name;
        this.description = description;
    }

    public Task()
    {
    }
}



The code shown below is used to get the users and their tasks.

public static List<User> GetUserWTasks()
    {
        List<User> users = new List<User>();

        int index = -1;

        string connectionString = @"Server=localhost;Database=School;Trusted_Connection=true";
        string selectQuery = @"SELECT t.TaskID,t.UserID AS TaskUserID,u.UserID AS UserID, u.FirstName,
                             u.LastName, t.Name, t.Description
                            FROM Users u JOIN Tasks t ON u.UserID = t.UserID
                            ORDER BY u.UserID ASC";


        using (SqlConnection myConnection = new SqlConnection(connectionString))
        {
            SqlCommand myCommand = new SqlCommand(selectQuery, myConnection);

            myConnection.Open();
            SqlDataReader reader = myCommand.ExecuteReader();
            while (reader.Read())
            {
                User user = new User();
                user.UserID = (int)reader["UserID"];
                user.FirstName = reader["FirstName"] as String;
                user.LastName = reader["LastName"] as String;


                if (!DoesContain(users, user))
                {
                    users.Add(user);
                    index++;
                    users[index].TaskList.Add(new Task((int)reader["TaskID"], (string)reader["Name"], (string)reader["Description"]));
                }
                else
                {
                   users[index].TaskList.Add(new Task((int)reader["TaskID"], (string)reader["Name"], (string)reader["Description"]));                             

                }              

            }
        }

        return users;
    }

 private static bool DoesContain(List<User> users, User user)
    {
        bool result = false;

        foreach (User u in users)
        {
            if (u.UserID == user.UserID)
            {
                result = true;
                break;
            }
        }

        return result;
    }



The method GetUserWTasks() adds the user to the users list and the DoesContain method checks that if the user is already added in the list. If the user was already added in the list then the user is not added again but his task is added to the task collection.

In order to get a clear picture I will use a nested GridView which will be used to display the tasks of the users. Check out the HTML code for the nested GridView.

 <asp:GridView ID="gvParent" BackColor="Azure" AutoGenerateColumns="false" runat="server">
   
   <Columns>
   
   <asp:TemplateField>
   
   <ItemTemplate>
   <asp:Label ID="lblFullName" runat="server" Text= '<%# Eval("FullName") %>' />  
   
   <asp:GridView ID="gvChild" BackColor="wheat" AutoGenerateColumns="false" runat="server" DataSource='<%#  Eval("TaskList") %>'>
   
   <Columns>
   <asp:TemplateField HeaderText="Tasks" >
   
   <ItemTemplate>
   <asp:Label ID="lblName" runat="server" Text='<%# Eval("Name") %>' />
   </ItemTemplate>  
   
   
   </asp:TemplateField>
   
   </Columns>
   
   </asp:GridView>
    
   </ItemTemplate>   
   
   </asp:TemplateField>
   
   </Columns>
   
   
   </asp:GridView>  



In the code behind all you need to do is bind the user collection to the parent GridView.

 private void BindData()
    {
        List<User> users =  UserManager.GetUserWithTasks();

        gvParent.DataSource = users;
        gvParent.DataBind();

    }


When you run this example you will see the following result.

 



Conclusion:

In this article I demonstrated how to use different binding scenarios related to the GridView control. You can even call public, protected methods inside the GridView Templates which gives you the flexibility to process the information further before sending it to the screen.

I hope you liked the article, happy programming!