【问题标题】:.FindControl always returns null.FindControl 总是返回 null
【发布时间】:2012-08-18 02:27:43
【问题描述】:

我有两种方法。第一个动态创建一个表,然后我将该表添加到 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”,我会得到空值。

为什么会这样?

【问题讨论】:

标签: c# asp.net findcontrol


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

    • 我试过了,但我有一个大问题。当我通过我的 holder_info 时,他是空的!如果我做 holder_info.Controls.Count 它返回 0 !
    • 那么你需要更具体地说明你在哪里打电话给FindControl()。它与您添加问题中暗示的这些项目的方法不同,而是在回发期间,它会是空的。
    • 是的。这就是我在帖子中所说的!如果我用同样的方法做,我可以得到控制,但如果不是,我有空......
    【解决方案3】:

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

    为了演示,我可以展示一个简短的示例,说明如何实施中继器,因为这是 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
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-09-20
      • 1970-01-01
      • 1970-01-01
      • 2019-01-09
      • 2012-11-21
      • 2012-10-31
      • 2013-03-16
      相关资源
      最近更新 更多