FindControl总是返回空值。

5

我有两种方法。第一种是动态创建一个表,并将该表添加到一个PlaceHolder中。

private void generateData(){
    Table tbl = new Table();
    tbl.ID = "table1";
    holder_info.Controls.Add(tbl);
    // ...adding tr's and td's....
    // ...adding CheckBox in tds....
}

如果我在这个方法中使用.FindControl("..."),我可以使用以下代码找到控件:

CheckBox check = (CheckBox)holder_info.FindControl("checkbox1");

可以,但不是我想要的。

在第二种方法中,我想要检查用户是否选中了复选框并执行某些操作,但我找不到控件(它始终返回 null)。

protected void saveInfo_Click(object sender, ImageClickEventArgs e)
{
  CheckBox check = (CheckBox)holder_info.FindControl("checkbox1");
  if(check.checked){ ... }
}

此外,如果我尝试查找控件“table1”,则会得到null。
这是为什么?

1
@Shyju - 当然。这里是:真正理解动态控件 - Oded
3个回答

5
由于您在页面上动态添加了控件,当您单击按钮时,页面会进行回发并删除动态添加的控件。这就是为什么在按钮单击事件中无法找到复选框控件的原因。
对于动态控件,请查看文章在ASP.NET应用程序中保留动态创建的控件的状态(The Code Project)。

3
< p > FindControl() 仅查找直接子元素,而不是那些子元素的子元素。

要实现您想要的功能,您需要编写一个程序来 递归查找子控件


我尝试过了,但是我有一个很大的问题。当我传递我的holder_info时,它是空的!如果我执行holder_info.Controls.Count,它会返回0! - oteal
那么你需要更具体地说明你在哪里调用了 FindControl()。如果它不是在你问题中暗示的添加这些项的同一个方法中,而是在 postback 过程中调用,那么它将为空。 - Jonathan Wood
是的,这就是我在帖子中说的!如果我用相同的方法,我可以获得控制权,但如果不是,则为null... - oteal

1

正如Pranay所解释的那样,这是因为您正在动态添加控件。您需要在postback之前重建页面。此外,当涉及到记住先前显示的信息时,Table控件不是一个好的Web控件。您可能会更幸运地使用Repeater、DataList或DataGrid。可以在Deciding When to Use the DataGrid, DataList or Repeater(MSDN)中进行比较。

为了演示,我可以展示一个简短的例子,说明如何实现Repeater,因为在我看来,这是最简单的控件之一。因此,不要在postback(例如按钮单击)中添加表格,而是在标记中添加repeater,并在需要显示数据时将其设置为可见。这样,您甚至不必担心动态控件,它在您需要时就在那里。

因此,带有复选框的repeater的基本标记如下。

<asp:Repeater ID="myTable" runat="server">
    <HeaderTemplate>
        <table cellpadding="4" cellspacing="0">
        <thead>
            <tr>
                <th></th>
                <th>Name</th>
                <th>Company</th>
            </tr>
        </thead>
        <tbody>
    </HeaderTemplate>
    <ItemTemplate>
    <tr>
        <td>
            <asp:HiddenField ID="uidfield" Value='<%# Eval("Uid") %>' runat="server" />
            <asp:CheckBox ID="valuefield" Checked='<%# Eval("IsChecked") %>' runat="server" />
        </td>
        <td>
            <asp:Label Text='<%# Eval("Name") %>' runat="server" />
        </td>
        <td>
            <asp:Label Text='<%# Eval("Company") %>' runat="server" />
        </td>
    </tr>
    </ItemTemplate>
    <FooterTemplate>
    </tbody> </table>
    </FooterTemplate>
</asp:Repeater>

正如您所看到的,该表是手动构建的(如果您不想这样做,可以使用DataGrid代替)。现在您可以拥有一个类作为您的模型,例如:

public class Person {
  public Person() { }

  public Person(Guid id, string name, string company) {
    this.Uid = id;
    this.Name = name;
    this.Company = company;
  }

  public Guid Uid { get; set; }

  public string Name { get; set; }

  public string Company { get; set; }
}

还有一个视图模型类,它“满足”视图的需求(例如您的网页控件)。请注意额外的属性IsChecked,它不应该是模型的一部分(人如何被检查?),但它很适合于视图模型类。

public class PersonViewModel {
  private Person model;
  public PersonViewModel(Person model) {
      this.model = model;
  }

  public Guid Uid { get { return model.Uid; } }

  public string Name { get { return model.Name; } }

  public string Company { get { return model.Company; } }

  public bool IsChecked { get; set; }
}

好的,接下来是代码部分。当使用重复器控件时,您需要将其绑定到一个列表上。从IEnumerable继承的实例就可以了,所以您需要将它连接起来。

在页面的代码后面,添加这些方法。

protected override void OnInit(EventArgs e) {
    base.OnInit(e);
    mailinglists.DataBinding += bindMyTable;
}

protected override void OnLoad(EventArgs e) {
    base.OnLoad(e);
    if (!Page.IsPostBack) {
        DataBind();
    }
}

private void bindMyTable(object sender, EventArgs e) {
    // Are the conditions set for adding data to the table?
    if (conditionsMet()) {
        myTable.DataSource = getDataSource();
    }
}

private IEnumerable<PersonViewModel> getDataSource() {
     List<PersonViewModel> view = new List<PersonViewModel>();
     view.Add(new PersonViewModel(new Person() { Uid = Guid.NewGuid(), Name = "Example", Company = "Co" }));
     return view;
}

现在只需在条件满足时调用myTable.DataBind(),例如当您单击按钮时。当您单击按钮并需要检查哪些复选框已选中时,您可以使用repeater.Items属性来迭代它们,类似于以下内容:
private void onValidatePage() {
    List<Guid> checks = new List<Guid>();
    foreach (RepeaterItem repeatitem in myTable.Items) {
        string uid = ((HiddenField)repeatitem.FindControl("uidfield")).Value;
        bool value = ((CheckBox)repeatitem.FindControl("valuefield")).Checked;
        if (value) {
            checks.Add(new Guid(uid));
        }
    }
    // Now "checks" hold all the id's of the checked items
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接