在 GridView 中不同页面上保持选中的 CheckBoxes 的状态






4.96/5 (57投票s)
本文介绍如何在 GridView 的不同页面中管理 CheckBox 的状态。

引言
在这里,我将介绍如何在 GridView 控件的不同页面中维护选中的 CheckBox
的状态。
背景
如果您有 Gmail 账户,您可能已经注意到了在 收件箱 Grid 中跨页面维护选中 CheckBox
状态的强大功能。例如,假设您在 收件箱 的第一页选中了一些邮件,然后移动到第二页。您在那里也选中了一些邮件,然后继续移动到下一页。最后,您返回到第一页/第二页,发现所有之前选中的邮件仍然被选中。这意味着 Gmail 在 收件箱 Grid 的不同页面中维护了所有已选中邮件的状态。现在,如果您在 收件箱 Grid 的不同页面中选中邮件并点击 删除 链接,则只会删除当前页面中选中的邮件。但我的客户想要更高级的功能。实际上,我客户的要求是点击 删除 链接时删除所有页面中选中的邮件。于是我开始着手研究,最终提出了这个解决方案。
实现细节
为了实现这个功能,我将其分为三个部分:
- 选中/取消选中 GridView 内的所有
CheckBox
.
我使用HeaderClick
和ChildClick
JavaScript 方法实现了这个功能。 - 恢复 GridView 内特定页面的选中
CheckBox
状态.
我通过在window.onload 事件
中调用RestoreState
方法来实现这个功能。 - 存储选中的
CheckBox
的行 ID.
我为此目的使用了HiddenField hdnFldSelectedValues
。它以“|”分隔存储了选中CheckBox
的行 ID。
HTML 代码
我在 GridView
中使用了一个 TemplateField
,并在 ItemTemplate
中放置了一个 CheckBox
和一个 HiddenField
,并在 HeaderTemplate
中放置了另一个 CheckBox
。为了唯一标识每个 GridView Row
,我在数据源中使用了 AutoIncrement
列,并将其绑定到 HiddenField hdnFldId
。但这可以是任何内容,例如数据库中的行 ID 等。
<asp:GridView ID="gvCheckboxes" runat="server"
AutoGenerateColumns="False" AllowPaging="True"
OnPageIndexChanging="gvCheckboxes_PageIndexChanging"
OnRowDataBound="gvCheckboxes_RowDataBound">
<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>
我还向页面添加了一个 HiddenField
来跟踪相应选中 CheckBox
的行 ID。
<asp:HiddenField ID="hdnFldSelectedValues" runat="server" />
附加 Click 事件
我像这样为标题 CheckBox
附加了 onclick event
:
<asp:CheckBox ID="chkBxHeader"
onclick="javascript:HeaderClick(this);" runat="server" />
我还像这样通过 GridView
的 RowDataBound event
为每个 Row-CheckBox
附加了 onclick event
:
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()
);
}
页面 window.onload 事件
我使用 window.onload event
来初始化全局变量以及恢复 GridView 中特定列的所有 CheckBox
的先前状态。
//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 will 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 will 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();
}
GridView 的 Header Checkbox 的 Click 事件
每当点击 GridView
的标题 CheckBox
时,就会触发这个 event
。在这个 event
中,所有 Row-CheckBox
的状态会根据标题 CheckBox
的状态而改变。如果标题 CheckBox
被选中,则对应的行 ID 会被维护在 SelectedItems 数组
中,否则会被移除。在此 event
中,SelectedValues HiddenField
的值和 CheckedCheckBoxes
计数器也会被更新。
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;
}
GridView 的 Rows Checkboxes 的 Click 事件
每当点击 GridView
Rows CheckBoxes
中的任何一个 CheckBox
时,就会触发这个 event
。在这个 event
中,首先会更新 CheckedCheckBoxes
计数器,并相应地改变标题 CheckBox
的状态。之后,包含该特定 CheckBox
的 Row-Id
的条目会被维护在/从 SelectedItems 数组
中。然后,SelectedValues HiddenField
的值会从 SelectedItems 数组
中更新。
function ChildClick(CheckBox, HCheckBox, Id)
{
//Modify 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('|');
}
RestoreState 方法
此方法在 window.onload event
中调用。此方法主要用于恢复 GridView 中不同页面上特定列的所有 CheckBox
的先前状态。如果 SelectedItems 数组
中找到了特定 CheckBox
的条目,则其状态会变为选中。之后,标题 CheckBox
的状态也会被更新。
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;
}
DeleteItem 方法
此方法用于从 SelectedItems 数组
中移除特定 CheckBox
的条目。
function DeleteItem(Text)
{
var n = IsItemExists(Text);
if( n > -1)
SelectedItems.splice(n,1);
}
IsItemExists 方法
此方法用于检查特定 CheckBox
的条目是否存在于 SelectedItems 数组
中。
function IsItemExists(Text)
{
for(var n = 0; n < SelectedItems.length; ++n)
if(SelectedItems[n] == Text)
return n;
return -1;
}
从不同页面删除选中的项目
现在,最后,为了删除所有不同页面中选中的 CheckBox
,只需获取所有选中的 ID,并在 Link
/Button
的 delete event
handler 中使用适当的方法删除选中的项目,如下所示:
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 appropriate method for deletion operation.
}
}
结论
这就是我的解决方案。如果您对这个功能有其他想法,请与我分享。
支持的浏览器
我使用以下浏览器测试了这个功能:

历史
- 2008年12月18日 -- 发布原始版本
- 2008年12月26日 -- 文章更新