Thursday, 16 May 2013

GridView - Overview of different ways to bind data to columns


GridView - Overview of different ways to bind data to columns

Introduction

This article will give you an overview of different ways to specify the columns of a GridView. It won't discuss different ways to bind Data (e.g. assigning a collection to the DataSource property, or using controls like the ObjectDataSource)

I will present three ways of specifying the columns:
  1. Using the AutoGenerateColumns property to render all columns of the bound dataobject.
  2. Specify which columns should be displayed, by adding BoundColumns to the Columns property.
  3. Using the TemplateFields and the RowDataBound Event to have a flexible way of binding data to columns from the code.
If you want to follow this article step-by-step, this is how you can do it:

Step 1:
Create a new Asp.net WebApplication Project.

Step 2:
I have created a sample class, that will be used for this entire article.
Insert this class into your project:
1
2
3
4
5
6
7
8
public class SampleUserClass
{
    public int IDUser { get; set; }
    public String Name { get; set; }
    public String UserName { get; set; }
    public bool IsBanned { get; set; }
    public String BanReason { get; set; }
}
Step 3:
Open the default.aspx and add this Line in your markup:
1
<asp:GridView ID="gvUsers" runat="server"></asp:GridView>
Step 4:
Switch to the code-behind and insert this code for the databinding:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
protected override void OnInit(EventArgs e)
{
    base.OnInit(e);
    if (!Page.IsPostBack)
    {
        this.BindGrid();
    }
}
 
 
protected void BindGrid()
{
    List<SampleUserClass> list = new List<SampleUserClass>()
    {
        new SampleUserClass()
        {
        IDUser = 1,
        Name = "Darren Merrigan",
        UserName = "mighty dragon",
        IsBanned = false,
        BanReason = string.Empty
        },
        new SampleUserClass()
        {
        IDUser = 2,
        Name = "Max Slane",
        UserName = "slan0r",
        IsBanned = true,
        BanReason = "no l33t names allowed"
        }
    };
    this.gvUsers.DataSource = list;
    this.gvUsers.DataBind();
}

Way 1: Using the AutoGenerateColumns property to populate the colums in a GridView

The first way I will present you, is to let the columns be autogenerated by the GridView. The GridView creates a column for each property in our dataobject. (SampleUserClass in our case)

This is done by the AutoGenerateColumns Property which is set to true as default value.
1
<asp:GridView ID="gvUsers" runat="server" AutoGenerateColumns="true"></asp:GridView>
A obvious disadvatange is, that it is not possible to explicity say, which properties should be displayed as columns, what the HeaderText or width of each column should be.

Running this code will result in this GridView:
GridView with AutoGeneratedColumns

Way 2: Using BoundFields to populate the columns in a GridView

The second way to create the columns allows to explicitly define, which columns should be displayed, how they look and in which order they are displayed.
A slight disadvantage that comes with this, is that designing the GridView the way you want costs time (but not that much).

In order to specify the columns we need to set theAutoGeneratedColumns property to false.
1
<asp:GridView ID="gvUsers" runat="server" AutoGenerateColumns="false"></asp:GridView>
The GridView provides a Columns Property, in which we add columns. (We can also set AutoGeneratedColumns=true and add columns to the autogenerated ones, if this is desired)

There are several childelements which can be added to the Columns property.
The BoundField is the most easy to use column type. You just need to set the DataField property to the name of the property, you want to show in this column. The GridView will automatically render the display or edit-controls, depending on the Mode the GridView is in.
1
2
3
4
5
<asp:GridView ID="gvUsers" runat="server" AutoGenerateColumns="false">
    <Columns>
        <asp:BoundField DataField="IDUser"/>
    </Columns>
</asp:GridView>

The BoundField class provides several properties, that can be used to design the GridView.
Some of the most commonly used properties are:
DataField: Name of the Property, that should be displayed. (The dataobject must provide this property. The name is case-insensitive)
HeaderText: Specify which text should be displayed in the HeaderRow of the GridView (if the ShowHeader property of the GridView is true, which is also the default value)
ItemStyle-Width: Specify a fixed width for this column. If this value is not set a column (or more), the GridView will automatically look for its width property and augment the size of the non-fixed-width columns that the entire width of the GridView is being used. (This only applies, if the Width property of the GridView is set)

We can add some more columns with this markup:
1
2
3
4
5
6
7
<asp:GridView ID="gvUsers" runat="server" AutoGenerateColumns="false">
    <Columns>
        <asp:BoundField HeaderText="ID" DataField="IDUser" ItemStyle-Width="50"/>
        <asp:BoundField HeaderText="Name" DataField="Name" ItemStyle-Width="200"/>
        <asp:BoundField HeaderText="Username" DataField="UserName" ItemStyle-Width="200"/>
    </Columns>
</asp:GridView>
Running this code will result in this GridView:
GridView with BoundFields
The second way I present works for basic stuff, regarding the Display-Mode of the GridView.
The third way will add more flexibility by using TemplateFields. You can combine different column types, if you like.

Way 3: Using TemplateField and the RowDataBound Event to populate the columns in a GridView

The third way I will present you, is to use TemplateFields.
In a TemplateField you can specify per column, which control should be rendered for which Display-Mode. This is done by several sub-properties of the TemplateField property:
InsertItemTemplate: Template that is used, if the GridView is in the Insert-Mode
EditItemTemplate: Template that is used, if the GridView is in the Edit-Mode
ItemTemplate: Template that is used, if the GridView is in the Display-Mode, or if no template is specyfied for the current mode the GridView.

This article focuses on the ItemTemplate.

As I've said, a TemplateField gives us more flexibility.

For example, we can insert a HyperLink Control into the Template (we could also use a HyperLinkField for this).
Let's assume we want to display a link to a user profile, but only, if the user isn't banned.
Otherwise we will display the ban reason.

We add a TemplateField to our previous markup, and insert a HyperLink and a Literal control. It is important, that both of these controls have an ID and a runat="server" attribute.
1
2
3
4
5
6
7
8
9
10
11
12
13
<asp:GridView ID="gvUsers" runat="server" AutoGenerateColumns="false">
    <Columns>
        <asp:BoundField HeaderText="ID" DataField="IDUser" ItemStyle-Width="50" />
        <asp:BoundField HeaderText="Name" DataField="Name" ItemStyle-Width="200" />
        <asp:BoundField HeaderText="Username" DataField="UserName" ItemStyle-Width="200" />
        <asp:TemplateField HeaderText="Userprofile">
            <ItemTemplate>
                <asp:HyperLink ID="hlUserProfile" runat="server" />
                <asp:Literal ID="litBanreason" runat="server" />
            </ItemTemplate>
        </asp:TemplateField>
    </Columns>
</asp:GridView>
And subscribe to the GridView's RowDataBound-Event.
For ASP.Net beginners, this might be a difficult process. As a result, I'll tell you how you can do it:
- Switch to the design view
- Select the GridView
- Open the properties window
-  and doubleclick on the RowDataBound row


For this reason, a new method is created in the code-behind:
1
2
3
4
protected void gvUsers_RowDataBound(object sender, GridViewRowEventArgs e)
{
 
}
This method will be called for every row that is bound to the GridView, including a seperate row for the header and the footer.

So basically, what we want now, are two things:
For each row, we want to get a reference to the object that is bound and we want references to the output controls, to be able to access their properties from within this method.
The RowDataBound method has GridViewRowEventArgs. This class provides us with references to the current row, and to the dataobject. The dataobject needs to be casted to our SampleUserClass.
e.Row.FindControl("ID") returns a reference to the usercontrol in the template, with the specified ID

This is the "translation" of my words into code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
protected void gvUsers_RowDataBound(object sender, GridViewRowEventArgs e)
{
    if (e.Row.RowType == DataControlRowType.DataRow)
    {
        HyperLink hlUserProfile = e.Row.FindControl("hlUserProfile") as HyperLink;
        Literal litBanreason = e.Row.FindControl("litBanreason") as Literal;
        SampleUserClass dataItem = e.Row.DataItem as SampleUserClass;
        if (dataItem.IsBanned)
        {
            hlUserProfile.Visible = false;
            litBanreason.Text = String.Format("User is banned. Reason: {0}", dataItem.BanReason);
        }
        else
        {
            litBanreason.Visible = false;
            hlUserProfile.Text = "Profile";
            hlUserProfile.NavigateUrl = String.Format("~/userprofile.aspx?IDUser={0}", dataItem.IsBanned);
        }
    }
}
Trying to run this code results in this:
GridView with TemplateField and RowDataBound-Event

No comments:

Post a Comment