65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.96/5 (57投票s)

2008 年 12 月 17 日

CPOL

4分钟阅读

viewsIcon

227548

downloadIcon

5104

本文介绍如何在 GridView 的不同页面中管理 CheckBox 的状态。

Preview.gif

引言

在这里,我将介绍如何在 GridView 控件的不同页面中维护选中的 CheckBox 的状态。

背景

如果您有 Gmail 账户,您可能已经注意到了在 收件箱 Grid 中跨页面维护选中 CheckBox 状态的强大功能。例如,假设您在 收件箱 的第一页选中了一些邮件,然后移动到第二页。您在那里也选中了一些邮件,然后继续移动到下一页。最后,您返回到第一页/第二页,发现所有之前选中的邮件仍然被选中。这意味着 Gmail收件箱 Grid 的不同页面中维护了所有已选中邮件的状态。现在,如果您在 收件箱 Grid 的不同页面中选中邮件并点击 删除 链接,则只会删除当前页面中选中的邮件。但我的客户想要更高级的功能。实际上,我客户的要求是点击 删除 链接时删除所有页面中选中的邮件。于是我开始着手研究,最终提出了这个解决方案。

实现细节

为了实现这个功能,我将其分为三个部分:

  • 选中/取消选中 GridView 内的所有 CheckBox.
    我使用 HeaderClickChildClick 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" />

我还像这样通过 GridViewRowDataBound 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 的状态。之后,包含该特定 CheckBoxRow-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.
   }
}

结论

这就是我的解决方案。如果您对这个功能有其他想法,请与我分享。

支持的浏览器

我使用以下浏览器测试了这个功能:

Browsers.png

历史

  • 2008年12月18日 -- 发布原始版本
  • 2008年12月26日 -- 文章更新
© . All rights reserved.