.FindControl总是返回null

时间:2012-08-22 15:54:21

标签: c# asp.net findcontrol

我有两种方法。第一个动态创建一个表,然后将该表添加到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");

没关系,但不是我假装的。

在第二种方法中,我想检查用户是否检查了checkBox并做了一些事情,但我找不到控件(它总是返回null)。

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

另外,如果我试图找到控件“table1”,我会得到null。

为什么会这样?

3 个答案:

答案 0 :(得分:5)

这是因为您正在向页面动态添加控件,当您单击按钮页面时获取回发并删除动态添加的控件。这就是为什么它无法在按钮点击事件中找到复选框控件。

对于动态控件,请查看文章 Retaining State for Dynamically Created Controls in ASP.NET applications (代码项目)。

答案 1 :(得分:3)

FindControl()只找到直接的孩子,而不是那些孩子的孩子。

要做你想做的事,你需要写一个例程给recursively find child controls

答案 2 :(得分:1)

正如Pranay解释的那样,这是因为你是动态添加控件。您需要在回发之前重建页面。此外,在记住之前显示的信息时,Table控件不是一个好的web控件。使用Repeater,DataList或DataGrid可能会更好。 Deciding When to Use the DataGrid, DataList or Repeater (MSDN)中提供了对比。

为了演示,我可以展示一个关于如何实现Repeater的简短示例,因为这是IMO的简单控制之一。因此,不要在回发中添加表(例如按钮单击),只需在标记中添加转发器,并在要显示数据时将其设置为可见。通过这种方式,您甚至无需担心动态控件,它就在您需要的时候。

因此,具有复选框的转发器的基本标记如下。

<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,它不应该是模型的一部分(如何检查一个人?),但它非常适合viewmodel类。

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
}