.FindControl总是返回null

问题描述:

我有两种方法。第一个动态地创建一个表,然后将该表添加到PlaceHolder中。.FindControl总是返回null

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。

为什么会发生这种情况?

+1

@Shyju - 肯定。这里是:[真正理解动态控制](http://tinyurl.com/yfc66o) – Oded

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

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

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

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

+0

我试过了,但我有一个巨大的问题。当我通过我的holder_info时,他是空的!如果我做holder_info.Controls.Count它返回0! – oteal

+0

然后,您需要更具体地说明您在哪里调用FindControl()。它不是在你添加这些项目的方法中,而是在你的问题中隐含的,而是在回发期间,那么它将是空的。 –

+0

yap。这就是我在帖子中说的!如果我用同样的方法做,我可以得到控制权,但是如果它不是我有空... – oteal

正如Pranay解释的,这是因为您正在动态添加控件。您需要重建页面,因为它在回发之前。此外,当涉及到记住之前显示的信息时,表格控件不是一个好的网页控件。使用Repeater,DataList或DataGrid可能会更好。比较可在Deciding When to Use the DataGrid, DataList or Repeater(MSDN)中获得。

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

因此,带复选框的中继器的基本标记如下。您可以看到,该表是手动构建的(如果您不想这样做,可以使用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 
}