Monday 11 April 2011

Multirow Selection in GridView when CSS used for row style



This post concentrates on How to select multiple rows using a checkbox in a separate column in GridView with ASP.NET. There are multiple types of implementation on the same. So I am planning to provide the implementation example in following five ways.

  1. The first implementation will work if we have GridView rows with two types of colors - one for normal row and another one for selected row. There won’t be any alternative row color exist (I am using css class to set the row color)
  2. The next implementation will work if we have GridView with alternative colors. So when unselect the row color should be change back to normal color as per the alternative row)
  3. The next implementation will work if we have GridView where the user should be able to select the multiple rows with multiple pages.
  4. The next implementation for Select All future with multi selection in a single page.
  5. The next implementation for Select All future with multi selection and multiple pages (like gmail select all).

I am using Northwind database for this example, so make sure to have Northwind database to use this sample. The comments on the code will explain more about the functionality of the code.

In this post, I will be explaining the first implementation in the list (Multi Select with prefixed color row using CSS)

For more understanding below is the use case:

  • When page gets loaded, the GridView should bind the records from the database.
  • When the GridView shows, rows should be selected with the data already stored and fetched in code behind (say Id = 2, 3, 8 etc.). It means, the check box must be selected and the color of the row must be changed to selected color.
  • Once the page loaded, the used can select or unselect any row in the grid using check box provided on each row using check box column.
  • When the user selects (check the checkbox) a particular row, the row background color must be changed to selected color.
  • When the user unselects (uncheck the checkbox) a particular row, the row background color must be changed to unselected row color.
  • When user press a button, the code behind should have the ability to get the selected row Id. (For this example, show the Id selected in the page itself)

This implementation will work fine if only one page exist in GridView. If multiple page exist, it will get the selected row only for the current page it shows. If you required to handle for multiple page with multi row selection, please check the third post in this series.

The implementation as follows:

In aspx script.
<asp:GridView ID="grdViewProducts" runat="server"
    AllowPaging="True" AutoGenerateColumns="False" TabIndex="1"
    DataKeyNames="ProductID" Width="100%"
    CellPadding="4" ForeColor="#333333" 
    onrowdatabound="grdViewProducts_RowDataBound" 
    onpageindexchanging="grdViewProducts_PageIndexChanging">
    <Columns>
        <asp:BoundField DataField="ProductName" HeaderText="Product Name" />
        <asp:BoundField DataField="CompanyName" HeaderText="Supplier" />
        <asp:BoundField DataField="CategoryName" HeaderText="Category Name" />
        <asp:BoundField DataField="CategoryName" HeaderText="Category" />
        <asp:BoundField DataField="QuantityPerUnit" HeaderText="Quantity Per Unit"/>
        <asp:BoundField DataField="UnitPrice" HeaderText="UnitPrice" DataFormatString="{0:#0.00}" />
        <asp:TemplateField HeaderText="Select" ItemStyle-HorizontalAlign="Center">
            <ItemTemplate>
                <asp:CheckBox runat="server" ID="chkSelect" onclick="SelectRow(this.id)" />
                <asp:Label runat="server" ID="lblProductId" Text='<%# Eval("ProductID") %>' Visible="false"></asp:Label>
            </ItemTemplate>
        </asp:TemplateField>
    </Columns>
    <FooterStyle BackColor="#5D7B9D" Font-Bold="True" ForeColor="White" />
    <PagerStyle BackColor="#284775" ForeColor="White" HorizontalAlign="Right" />
    <HeaderStyle BackColor="#5D7B9D" Font-Bold="True" ForeColor="White" />
</asp:GridView>
<asp:Button ID="btnProcess" runat="server" Text="Process" Width="100px" OnClick="btnProcess_Click" />
JavaScript
var Const_LastCol_Index = 6;

// I am calling a Javascript function to change the selected row color on page load
var browserName = navigator.appName;
if (browserName == "Microsoft Internet Explorer") {
    window.onload = SelectGridOnLoad;
}
else {
    if (browserName == "Netscape") //google chrome app.Name
    {
        setTimeout("SelectGridOnLoad()", 500);
    }
    else {
        window.onload = SelectGridOnLoad; // helps with Opera
    }
}

function SelectGridOnLoad() {

    // Looping all the row (Here - 1 is used as I have footer in the Grid View and starting from 1 Row (0 is Header)
    // So if you dont have Footer required to loop till end of the row (ie., no -1).
    for (var intRow = 1; intRow < document.getElementById('<%= grdViewProducts.ClientID %>').rows.length - 1; intRow++) {

        // Getting the GridView Row
        var gridRow = document.getElementById('<%= grdViewProducts.ClientID %>').rows[intRow];

        for (var intCell = 0; intCell < gridRow.cells[Const_LastCol_Index].childNodes.length; intCell++) // Looping the Row cell
        {
            if (gridRow.cells[Const_LastCol_Index].childNodes[intCell].id != null) {

                if (gridRow.cells[Const_LastCol_Index].childNodes[intCell].id.indexOf("chkSelect") != -1) {
                    if (gridRow.cells[Const_LastCol_Index].childNodes[intCell].checked == true)
                        gridRow.className = "SelectedRowStyle";
                    else
                        gridRow.className = "NormalRowStyle";
                }
            }
        }
    }
}
function SelectRow(Id) {
    if (document.getElementById(Id).checked == true) // If Selected
    {
        document.getElementById(Id).parentNode.parentNode.className = "SelectedRowStyle";
    }
    else // If unselected - Replace the style to normal row
    {
        document.getElementById(Id).parentNode.parentNode.className = "NormalRowStyle";
    }
}
Style Sheet
.NormalRowStyle
{
 background-color:#F7F6F3;
 color:#333333;
}

.SelectedRowStyle
{
 background-color:#F7BE81;
 color:#333333;
}
C# Codebehind
protected void Page_Load(object sender, EventArgs e)
{
    if (!Page.IsPostBack)
        BindGrid();
}
/// <summary>
/// Method which binds the data to the Grid
/// </summary>
private void BindGrid()
{
    using (SqlConnection connection =
        new SqlConnection(ConfigurationManager.ConnectionStrings
                            ["SQLConnection"].ConnectionString))
    {

        SqlCommand command = new SqlCommand(
               "SELECT ProductID, ProductName, CompanyName, CategoryName, " +
               "QuantityPerUnit, UnitPrice FROM Products " +
               "JOIN Suppliers ON Products.SupplierID = Suppliers.SupplierID " +
               "JOIN Categories ON Products.CategoryID = Categories.CategoryID ", connection);

        connection.Open();
        SqlDataReader dr = command.ExecuteReader(CommandBehavior.CloseConnection);

        IList<ProductView> productViewList = new List<ProductView>();
        while (dr.Read())
        {
            ProductView productView = new ProductView();
            productView.ProductID = Convert.ToInt32(dr["ProductID"].ToString());
            productView.ProductName = dr["ProductName"].ToString();
            productView.CompanyName = dr["CompanyName"].ToString();
            productView.CategoryName = dr["CategoryName"].ToString();
            productView.QuantityPerUnit = dr["QuantityPerUnit"].ToString();
            productView.UnitPrice = Convert.ToDouble(dr["UnitPrice"].ToString());
            productViewList.Add(productView);
        }
        grdViewProducts.DataSource = productViewList;
        grdViewProducts.DataBind();
    }
}
protected void grdViewProducts_RowDataBound(object sender, GridViewRowEventArgs e)
{
    if (e.Row.RowType == DataControlRowType.DataRow)
    {
        ProductView productView = (ProductView)e.Row.DataItem;
        // Selecting the products programatically 
        // Considering those records (2, 5, 8) are already selected and stored in the database
        if ((productView.ProductID == 2) ||
            (productView.ProductID == 16) ||
            (productView.ProductID == 20))
        {
            CheckBox chkSelect = (CheckBox)e.Row.FindControl("chkSelect");
            chkSelect.Checked = true;
        }
    }
}

protected void btnProcess_Click(object sender, EventArgs e)
{
    if (grdViewProducts.Rows.Count > 0)
    {
        Response.Write("Selected Row Id : ");
        foreach (GridViewRow grdViewRow in grdViewProducts.Rows)
        {
            CheckBox chkSelect = (CheckBox)grdViewRow.FindControl("chkSelect");
            if (chkSelect.Checked == true)
            {
                Response.Write(((Label)grdViewRow.FindControl("lblProductId")).Text + ", ");
            }
        }
    }
}

protected void grdViewProducts_PageIndexChanging(object sender, GridViewPageEventArgs e)
{
    grdViewProducts.PageIndex = e.NewPageIndex;
    BindGrid();
}
VB Codebehind
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        If Not Page.IsPostBack Then
            BindGrid()
        End If
    End Sub
    ''' <summary>
    ''' Method which binds the data to the Grid
    ''' </summary>
    Private Sub BindGrid()
        Using connection As New SqlConnection(ConfigurationManager.ConnectionStrings("SQLConnection").ConnectionString)

            Dim command As New SqlCommand("SELECT ProductID, ProductName, CompanyName, CategoryName, " & "QuantityPerUnit, UnitPrice FROM Products " & "JOIN Suppliers ON Products.SupplierID = Suppliers.SupplierID " & "JOIN Categories ON Products.CategoryID = Categories.CategoryID ", connection)

            connection.Open()
            Dim dr As SqlDataReader = command.ExecuteReader(CommandBehavior.CloseConnection)

            Dim productViewList As IList(Of ProductView) = New List(Of ProductView)()
            While dr.Read()
                Dim productView As New ProductView()
                productView.ProductID = Convert.ToInt32(dr("ProductID").ToString())
                productView.ProductName = dr("ProductName").ToString()
                productView.CompanyName = dr("CompanyName").ToString()
                productView.CategoryName = dr("CategoryName").ToString()
                productView.QuantityPerUnit = dr("QuantityPerUnit").ToString()
                productView.UnitPrice = Convert.ToDouble(dr("UnitPrice").ToString())
                productViewList.Add(productView)
            End While
            grdViewProducts.DataSource = productViewList
            grdViewProducts.DataBind()
        End Using
    End Sub

    Protected Sub grdViewProducts_RowDataBound(ByVal sender As Object, ByVal e As GridViewRowEventArgs)
        If e.Row.RowType = DataControlRowType.DataRow Then
            Dim productView As ProductView = DirectCast(e.Row.DataItem, ProductView)
            ' Selecting the products programatically 
            ' Considering those records (2, 5, 8) are already selected and stored in the database
            If (productView.ProductID = 2) OrElse (productView.ProductID = 16) OrElse (productView.ProductID = 20) Then
                Dim chkSelect As CheckBox = DirectCast(e.Row.FindControl("chkSelect"), CheckBox)
                chkSelect.Checked = True
            End If
        End If
    End Sub

    Protected Sub btnProcess_Click(ByVal sender As Object, ByVal e As EventArgs)
        If grdViewProducts.Rows.Count > 0 Then
            Response.Write("Selected Row Id : ")
            For Each grdViewRow As GridViewRow In grdViewProducts.Rows
                Dim chkSelect As CheckBox = DirectCast(grdViewRow.FindControl("chkSelect"), CheckBox)
                If chkSelect.Checked = True Then
                    Response.Write(DirectCast(grdViewRow.FindControl("lblProductId"), Label).Text + ", ")
                End If
            Next
        End If
    End Sub

    Protected Sub grdViewProducts_PageIndexChanging(ByVal sender As Object, ByVal e As GridViewPageEventArgs)
        grdViewProducts.PageIndex = e.NewPageIndex
        BindGrid()
    End Sub

This code has been tested with IE 6.0/8.0, Chrome 10.0, Firefox 3.6, Opera 11.01

Here is the output of the example.
Before Selecting Multirow selection in GridView (already one row selected from code behind)

After selecting GridView press Process button (the selected ids are in top)

download the source code in C# here and in VB here


0 Responses to “Multirow Selection in GridView when CSS used for row style”

Post a Comment