【问题标题】:How to programmatically create and use a list of checkboxes from ASP.NET?如何以编程方式创建和使用 ASP.NET 中的复选框列表?
【发布时间】:2010-11-13 21:44:27
【问题描述】:

我有一个包含内容表的页面,我需要允许用户选择要处理的行。我已经想出了如何在表格中添加一列复选框,但我似乎无法弄清楚如何在提交表单时测试它们是否被选中。如果它们是静态元素,我可以只检查 do this.theCheckBox,但它们是通过程序生成的。

此外,我对如何将数据附加到它们(通过将其填充到 ID 属性中)的方式不太满意。

我不确定它是否相关,但我正在查看一个 catch-22,因为我需要知道在我之前检查了 上次创建的复选框中的哪些可以重新运行创建它们的代码。


编辑: 我找到了一个几乎解决方案。通过设置AutoPostBack 属性和CheckedChanged 事件:

checkbox.AutoPostBack = false;
checkbox.CheckedChanged += new EventHandler(checkbox_CheckedChanged);

对于任何已更改的复选框,我可以在回发时调用代码。然而这有两个问题:

  • 在我需要使用此信息的Page_Load 之后(或期间,我不确定)处理回调
  • 不会为页面加载时选中的复选框调用回调。

编辑 2:

我最终做的是用已知前缀标记我所有的 ID,并将其填充到 Form_Load 的顶部:

foreach (string v in this.Request.Form.AllKeys)
{
    if (v.StartsWith(Prefix))
    {
        var data = v.Substring(Prefix.Length);
    }
}

其他一切似乎都来得太晚了。

【问题讨论】:

    标签: asp.net forms checkbox


    【解决方案1】:

    我最终做的是用已知前缀标记我所有的 ID,并将其填充到 Form_Load 的顶部:

    foreach (string v in this.Request.Form.AllKeys)
    {
        if (v.StartsWith(Prefix))
        {
            var data = v.Substring(Prefix.Length);
        }
    }
    

    其他一切似乎都来得太晚了。

    【讨论】:

      【解决方案2】:

      在 InitComplete 事件和 PreLoad 事件之间恢复回发数据。如果您的复选框直到稍后才创建,则复选框将“赶上”它们的事件,并且数据将在创建后不久加载到控件中。
      如果这对你来说太晚了,那么你将不得不做一些你已经在做的事情。也就是说,您必须先访问发布数据,然后才能将其提供给控件。
      如果您可以保存您创建的每个CheckBoxUniqueId,则可以直接访问帖子数据,而无需为其指定特殊前缀。您可以通过创建一个字符串列表来做到这一点,您在生成它们时将它们保存在其中,然后将它们保存在视图状态中。当然,这需要启用视图状态并在视图状态中占用更多空间。

      foreach (string uniqueId in UniqueIds)
      {
          bool data = Convert.ToBoolean(Request.Form[uniqueId]);
          //...
      }
      

      【讨论】:

      • 第一位很高兴知道。至于UniqueId 位,我宁愿保持无状态。
      【解决方案3】:

      将它们添加到页面的 CreateChildControls 方法的覆盖中。一定要给他们一个ID!这样,它们就会在正确的时间添加到控制树中。

      恕我直言,最好的方法是使用 DataBound Templated Control,即类似于 ListView(在 .NET 3.5 中)。然后在回发后的页面加载中遍历数据绑定控件中的所有项目并使用 item.FindControl 来获取实际的复选框。

      【讨论】:

      • 第一个选项不起作用,因为我需要在创建复选框之前进行处理,因为处理会影响创建的复选框。 OTOH,我将不得不研究一下这个 DataBound 的东西,看看它是怎么做的。
      【解决方案4】:

      使用CheckBoxList 控件怎么样?我现在没有打开 Visual Studio,但据我所知,它是一个 DataBound 控件,提供DataSourceDataBind(),您可以在运行时提供列表。当页面进行回发时,您可以通过调用myCheckBoxList.Items 之类的方法遍历列表,并通过调用ListItem.Selected 方法检查当前项是否被选中。这应该可以。

      【讨论】:

      • 我从未使用过日期绑定,所以这是一个缺点。另一个问题:您是否碰巧知道它是否可以DateSource 加载数据之前处理内容?这是基于用于上一页加载的数据。
      • 我想我以错误的方式解释了您的问题。 CheckBoxList 不适合您想要实现的目标。但是,DataBinding 机制可以帮助您。 “之前处理内容”...理论上您只需在“!Page.isPostBack”案例中加载您的控件,因此 ViewState 将再次将您以前的项目映射回您的数据绑定控件(Repeater、Grid 或其他)。不幸的是,我目前无法检查它,但应该有办法获取复选框(也可以使用 FindControl(...) 方法)。
      【解决方案5】:

      您的帖子有点含糊。这将有助于了解您如何将控件添加到表格中。它是一个 ASP:Table 还是一个常规的 HTML 表(可能具有 runat="server" 属性,因为您已经成功地向其中添加了项目)?

      如果您打算让用户进行一系列选择,然后点击“提交”按钮,然后您将根据选中的行处理每一行,那么您不应该处理 CheckChanged 事件。否则,正如您所注意到的,您每次都会导致回发,并且不会处理任何其他复选框。因此,当您创建 CheckBox 时,请不要设置事件处理程序,以免导致回发。

      在提交按钮的事件处理程序中,您将遍历每个表格行、单元格,然后确定单元格的子控件是否包含复选框。

      我建议不要使用桌子。根据您的描述,GridView 或 DataList 可能是更好的选择。


      编辑:这里有一个简单的例子来演示。您应该能够在新项目中进行测试。

      标记

          <form id="form1" runat="server">
          <div>
          <table id="tbl" runat="server"></table>
          <asp:Button ID="btnSubmit" runat="server" Text="Submit"
            onclick="btnSubmit_Click" />
          </div>
          </form>
      

      代码隐藏

      protected void Page_Load(object sender, EventArgs e)
      {
          for (int i = 0; i < 10; i++)
          {
              var row = new HtmlTableRow();
              var cell = new HtmlTableCell();
              cell.InnerText = "Row: " + i.ToString();
              row.Cells.Add(cell);
              cell = new HtmlTableCell();
              CheckBox chk = new CheckBox() { ID = "chk" + i.ToString() };
              cell.Controls.Add(chk);
              row.Cells.Add(cell);
              tbl.Rows.Add(row);
          }
      }
      
      protected void btnSubmit_Click(object sender, EventArgs e)
      {
          foreach (HtmlTableRow row in tbl.Rows)
          {
              foreach (HtmlTableCell cell in row.Cells)
              {
                  foreach (Control c in cell.Controls)
                  {
                      if (c is CheckBox)
                      {
                          // do your processing here
                          CheckBox chk = c as CheckBox;
                          if (chk.Checked)
                          {
                              Response.Write(chk.ID + " was checked <br />");
                          }
                      }
                  }
              }
          }
      }
      

      【讨论】:

      • 这是一个 HTML 表格。我只想处理选中的行,但 CheckChanged 也不适用于该行。添加一个带有Click 处理程序的asp:Button 后,我发现它也运行到很晚(在Form_Load 之后)也许我在错误的地方做事。
      • CheckChanged 不会被触发,因为您已将 AutoPostBack 设置为 false。它必须设置为真。如果您可以在每次支票更改时发回,那么您可以这样做。否则,您将在单击提交按钮时立即处理它们。在这种情况下,您将在类似于我发布的内容的循环中处理它们。
      • 我添加了一个示例来演示在给定您的 HTML 表格场景的情况下这将如何工作。
      • 当我尝试它时,CheckChanged 如果AutoPostBack=false 在提交时运行。
      • 当 AutoPostBack 为 true 时,复选框将在您更改其状态时回发。如果检查状态在回发之间发生变化,将调用 CheckChanged。回发是由 AutoPostBack 设置或按钮单击或其他任何生成回发的东西生成的都没有关系。
      【解决方案6】:

      我将假设您使用的是 DataList,但这应该与可以模板化的 Control 一起使用。我还将假设您正在使用 DataBinding。

      代码前端:

      <asp:DataList ID="List" OnItemDataBound="List_ItemDataBound" runat="server">
          <ItemTemplate>
              <asp:CheckBox ID="DeleteMe" runat="server"/>
              <a href="<%# DataBinder.Eval(Container, "DataItem.Url")%>" target="_blank">
                  <%# DataBinder.Eval(Container, "DataItem.Title")%></a>
          </ItemTemplate>
      </asp:DataList>
      <asp:Button ID="DeleteListItem" runat="server" OnClick="DeleteListItem_Click" ></asp:Button>
      

      代码背后:

      public partial class Default : System.Web.UI.Page
      {
          protected void Page_Load(object sender, EventArgs e)
          {
              if (!IsPostBack)
                  LoadList();
          }
      
          protected void DeleteListItem_Click(object sender, EventArgs e)
          {
              foreach (DataListItem li in List.Items)
              {
                  CheckBox delMe = (CheckBox)li.FindControl("DeleteMe");
      
                  if (delMe != null && delMe.Checked)
                          //Do Something
                  }
              }
      
              LoadList();
          }
      
          protected void LoadList()
          {
              DataTable dt = //Something...
              List.DataSource = dt;
              List.DataBind();
          }
      
          protected void List_ItemDataBound(object sender, DataListItemEventArgs e)
          {
              if (e.Item.ItemType == ListItemType.AlternatingItem || e.Item.ItemType == ListItemType.Item)
              {
                  string id = DataBinder.Eval(e.Item.DataItem, "ID").ToString();
                  CheckBox delMe = (CheckBox)e.Item.FindControl("DeleteMe");
      
                  if (delMe != null)
                      delMe.Attributes.Add("value", id);                
              }
          }
      }
      

      【讨论】:

      • 碰巧我没有使用这些东西。 OTOH,我将不得不研究 ItemTemplate 正在做什么,因为它看起来很方便。
      【解决方案7】:

      首先,确保每个 Checkbox 都有一个 ID,并且它的标签中有 'runat="server"'。

      然后使用 FindControl() 函数找到它。

      例如,如果您要遍历 GridView 中的所有行..

      foreach(GridViewRow r in Gridview1.Rows)
      {
      
          object cb = r.FindControl("MyCheckBoxId");
          if(r != null)
          {
            CheckBox chk = (CheckBox)cb;
            bool IsChecked = chk.Checked;
          }
      
      }
      

      【讨论】:

      • 我似乎找不到如何设置runat。我不能只是将它编辑到标签中,因为复选框都是通过new CheckBox()Form_Load 内部生成的@
      • 由于控件是动态添加的,并且是一个 ASP 控件,所以不需要设置 runat 属性。一旦正确设置控件的所有属性并向其添加事件处理程序,它将像在设计时添加的任何其他控件一样运行。您可以通过运行循环并构建 ID 来使用 @David 的 FindControl 方法,前提是您知道添加的复选框的数量,但这比在处理多个控件时直接循环通过父容器效率低。
      • 我没有检查过,但我怀疑它只会在我重新生成它之后才找到东西并且我需要它比那更快。
      • @BCS:然后移动您的重新生成代码或将依赖它的代码移动到页面生命周期的后期。
      • @Chris:该选项的问题是我需要运行以响应复选框的代码可能会更改重新生成代码必须生成的内容。就此而言,由于其他会话发生了变化,再生代码会产生不同的东西。
      猜你喜欢
      • 1970-01-01
      • 2010-11-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-08
      • 2014-03-19
      • 1970-01-01
      相关资源
      最近更新 更多