Friday, October 30, 2009

Maintaining the states of selected checkboxes during paging in gridview

If you have a Gmail account then probably you have observed a great feature of maintaining selected CheckBoxes states in different pages on Inbox Grid, i.e. suppose that you are in the first page of your Inbox & select some mails through CheckBoxes & move to the second page. You also select some mails there and further move to the next page. Finally you return back to the first/second page where you find that all the previously selected mails are already selected. This means that Gmail maintains all the selected mails’ states in deferent pages of Inbox Grid. Now if you select mails in different pages of the Inbox Grid & click Delete link, then only current page’s selected mails are deleted. But my clients wanted some more advanced features. Actually my client’s requirement was to delete all pages’ selected mails by clicking on Delete link. So I started to work on it & finally came up with this solution.

CheckBoxes.aspx:
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="CheckBoxes.aspx.cs" Inherits="CheckBoxes" %>



<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">

<head runat="server">

<title>Untitled Page</title>



<script type="text/javascript">

//Reference of the GridView.

var TargetBaseControl = null;

//Total no of checkboxes in a particular column inside the GridView.

var CheckBoxes;

//Total no of checked checkboxes in a particular column inside the GridView.

var CheckedCheckBoxes;

//Array of selected item's Ids.

var SelectedItems;

//Hidden field that wil contain string of selected item's Ids separated by ''.

var SelectedValues;



window.onload = function()

{

//Get reference of the GridView.

try

{

TargetBaseControl = document.getElementById('<%= this.gvCheckboxes.ClientID %>');

}

catch(err)

{

TargetBaseControl = null;

}



//Get total no of checkboxes in a particular column inside the GridView.

try

{

CheckBoxes = parseInt('<%= this.gvCheckboxes.Rows.Count %>');

}

catch(err)

{

CheckBoxes = 0;

}



//Get total no of checked checkboxes in a particular column inside the GridView.

CheckedCheckBoxes = 0;



//Get hidden field that wil contain string of selected item's Ids separated by ''.

SelectedValues = document.getElementById('<%= this.hdnFldSelectedValues.ClientID %>');



//Get an array of selected item's Ids.

if(SelectedValues.value == '')

SelectedItems = new Array();

else

SelectedItems = SelectedValues.value.split('');



//Restore selected CheckBoxes' states.

if(TargetBaseControl != null)

RestoreState();

}



function HeaderClick(CheckBox)

{

//Get all the control of the type INPUT in the base control.

var Inputs = TargetBaseControl.getElementsByTagName('input');



//Checked/Unchecked all the checkBoxes in side the GridView & modify selected items array.

for(var n = 0; n < Inputs.length; ++n)

if(Inputs[n].type == 'checkbox' && Inputs[n].id.indexOf('chkBxSelect',0) >= 0)

{

Inputs[n].checked = CheckBox.checked;

if(CheckBox.checked)

SelectedItems.push(document.getElementById(Inputs[n].id.replace('chkBxSelect','hdnFldId')).value);

else

DeleteItem(document.getElementById(Inputs[n].id.replace('chkBxSelect','hdnFldId')).value);

}



//Update Selected Values.

SelectedValues.value = SelectedItems.join('');



//Reset Counter

CheckedCheckBoxes = CheckBox.checked ? CheckBoxes : 0;

}



function ChildClick(CheckBox, HCheckBox, Id)

{

//Modifiy Counter;

if(CheckBox.checked && CheckedCheckBoxes < CheckBoxes)

CheckedCheckBoxes++;

else if(CheckedCheckBoxes > 0)

CheckedCheckBoxes--;



//Change state of the header CheckBox.

if(CheckedCheckBoxes < CheckBoxes)

HCheckBox.checked = false;

else if(CheckedCheckBoxes == CheckBoxes)

HCheckBox.checked = true;



//Modify selected items array.

if(CheckBox.checked)

SelectedItems.push(Id);

else

DeleteItem(Id);



//Update Selected Values.

SelectedValues.value = SelectedItems.join('');

}



function RestoreState()

{

//Get all the control of the type INPUT in the base control.

var Inputs = TargetBaseControl.getElementsByTagName('input');



//Header CheckBox

var HCheckBox = null;



//Restore previous state of the all checkBoxes in side the GridView.

for(var n = 0; n < Inputs.length; ++n)

if(Inputs[n].type == 'checkbox' && Inputs[n].id.indexOf('chkBxSelect',0) >= 0)

if(IsItemExists(document.getElementById(Inputs[n].id.replace('chkBxSelect','hdnFldId')).value) > -1)

{

Inputs[n].checked = true;

CheckedCheckBoxes++;

}

else

Inputs[n].checked = false;

else if(Inputs[n].type == 'checkbox' && Inputs[n].id.indexOf('chkBxHeader',0) >= 0)

HCheckBox = Inputs[n];



//Change state of the header CheckBox.

if(CheckedCheckBoxes < CheckBoxes)

HCheckBox.checked = false;

else if(CheckedCheckBoxes == CheckBoxes)

HCheckBox.checked = true;

}



function DeleteItem(Text)

{

var n = IsItemExists(Text);

if( n > -1)

SelectedItems.splice(n,1);

}



function IsItemExists(Text)

{

for(var n = 0; n < SelectedItems.length; ++n)

if(SelectedItems[n] == Text)

return n;



return -1;

}

</script>



</head>

<body>

<form id="form1" runat="server">

<asp:GridView ID="gvCheckboxes" runat="server" AutoGenerateColumns="False" OnPageIndexChanging="gvCheckboxes_PageIndexChanging"

OnRowDataBound="gvCheckboxes_RowDataBound" AllowPaging="True">

<Columns>

<asp:TemplateField HeaderText="Select">

<ItemTemplate>

<asp:CheckBox ID="chkBxSelect" runat="server" />

<asp:HiddenField ID="hdnFldId" runat="server" Value='<%# Eval("Id") %>' />

</ItemTemplate>

<HeaderStyle HorizontalAlign="Center" VerticalAlign="Middle" Width="50px" />

<ItemStyle HorizontalAlign="Center" VerticalAlign="Middle" Width="50px" />

<HeaderTemplate>

<asp:CheckBox ID="chkBxHeader" onclick="javascript:HeaderClick(this);" runat="server" />

</HeaderTemplate>

</asp:TemplateField>

<asp:BoundField DataField="RandomNo" HeaderText="Random Number">

<HeaderStyle HorizontalAlign="Center" VerticalAlign="Middle" Width="150px" />

<ItemStyle HorizontalAlign="Center" VerticalAlign="Middle" Width="150px" />

</asp:BoundField>

<asp:BoundField DataField="Date" HeaderText="Date">

<HeaderStyle HorizontalAlign="Center" VerticalAlign="Middle" Width="75px" />

<ItemStyle HorizontalAlign="Center" VerticalAlign="Middle" Width="75px" />

</asp:BoundField>

<asp:BoundField DataField="Time" HeaderText="Time">

<HeaderStyle HorizontalAlign="Center" VerticalAlign="Middle" Width="100px" />

<ItemStyle HorizontalAlign="Center" VerticalAlign="Middle" Width="100px" />

</asp:BoundField>

</Columns>

<RowStyle BackColor="Moccasin" />

<AlternatingRowStyle BackColor="NavajoWhite" />

<HeaderStyle BackColor="DarkOrange" Font-Bold="True" ForeColor="White" />

</asp:GridView>

<asp:HiddenField ID="hdnFldSelectedValues" runat="server" />

<asp:Button ID="btnDelete" runat="server" OnClick="btnDelete_Click" Text="DELETE" />

</form>

</body>

</html>
CheckBoxes.aspx.cs:
using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

public partial class CheckBoxes : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
BindGridView();
}

private void BindGridView()
{
gvCheckboxes.DataSource = GetDataSource();
gvCheckboxes.DataBind();
}
protected void gvCheckboxes_PageIndexChanging(object sender, GridViewPageEventArgs e)
{
gvCheckboxes.PageIndex = e.NewPageIndex;
BindGridView();
}
protected void gvCheckboxes_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow && (e.Row.RowState == DataControlRowState.Normal e.Row.RowState == DataControlRowState.Alternate))
{
CheckBox chkBxSelect = (CheckBox)e.Row.Cells[0].FindControl("chkBxSelect");
CheckBox chkBxHeader = (CheckBox)this.gvCheckboxes.HeaderRow.FindControl("chkBxHeader");
HiddenField hdnFldId = (HiddenField)e.Row.Cells[0].FindControl("hdnFldId");

chkBxSelect.Attributes["onclick"] = string.Format("javascript:ChildClick(this,document.getElementById('{0}'),'{1}');", chkBxHeader.ClientID, hdnFldId.Value.Trim());
}
}
private DataTable GetDataSource()
{
DataTable dTable = new DataTable();

DataRow dRow = null;
DateTime dTime;
Random rnd = new Random();

dTable.Columns.Add("Id", System.Type.GetType("System.Int32"));
dTable.Columns[0].AutoIncrement = true;
dTable.Columns.Add("RandomNo");
dTable.Columns.Add("Date");
dTable.Columns.Add("Time");

for (int n = 0; n < 25; ++n)
{
dRow = dTable.NewRow();
dTime = DateTime.Now;

dRow["RandomNo"] = rnd.NextDouble();
dRow["Date"] = dTime.ToString("MM/dd/yyyy");
dRow["Time"] = dTime.ToString("hh:mm:ss tt");

dTable.Rows.Add(dRow);
dTable.AcceptChanges();
}

return dTable;
}
protected void btnDelete_Click(object sender, EventArgs e)
{
//Get Ids
string[] IDs = hdnFldSelectedValues.Value.Trim().Split('');

//Code for deleting items
foreach (string Item in IDs)
{
//Call appropiate method for deletion operation.
}
}
}