搜索*.aspx中找不到的控件

WHY

记得一直都习惯于在*.aspx.cs页面中直接使用control的ID来取值赋值,例如:

string name = textBoxName.Text;
 

这里textBoxName就是定义在TextBox control中的ID:

<asp:TextBox runat="server" ID="textBoxName" />

 

但是,忽然有一天,碰到了意外情况。首先第一个特征是当我输入t字符准备让VS自动弹出control列表让我选择的时候,发现,不起作用了。因为VS时不时的会罢工,所以也并未在意。于是手工输入。结果是,编译时报错说:

Error    1    The name 'textBoxName' does not exist in the current context    C:\Documents and Settings\peisong_xiong\My Documents\Visual Studio 2008\Projects\WebApplication1\WebApplication1\Default.aspx.cs    18    27    WebApplication1

查看*.aspx文件,内容如下:

<asp:Repeater ID="Repeater1" runat="server">    
    <ItemTemplate>        
        <asp:TextBox runat="server" ID="textBoxName" />    
    </ItemTemplate>
</asp:Repeater>
 

WHY?因为Page.Controls中,并不会包含<*Template>里的control。至于为什么,根据我的猜测,动态添加的控件,由于存在runtime时可能生成也可能不生成的逻辑条件,例如上例中的Repeater中可能一个数据都没有,结果就是没有ItemTemplate,自然也就没有textBoxName。另外一种情况是,如果你的模板中有多条数据,那么就会有同一个控件的多个instance出现,这时候怎么可能静态分配一个ID呢?(感谢玄天尊的小屋的提醒 : ) )另外一种情况,比如你代码里这么写:

if(showMenu)
{    
    // Generate Menus    
    HyperLink menu = new HyperLink();    
    menu.ID = "Menu1";    
    // ... other menus
}
 

也就是说,如果showMenu是false,那么一个菜单项都不会生成,结果你引用Menu1.xxx属性怎么会不出错呢?

Solution

.NET提供了Object.FindControl方法,同时也可以通过Object.Controls[i]访问控件列表。例如Page控件下含有Form控件,Form控件下含有Repeater1控件等等以此类推。因此要找到某个确切的控件,需要用递归的方式遍历整个控件树。代码如下:

public static T FindControl<T>(Control root, string id) where T : Control  
{
    if (root.ID == id)       
    {           
        return root as T;
    }       
 
    foreach (Control ctl in root.Controls)       
    {           
        T control = FindControl<T>(ctl, id);           
 
        if (control != null)           
        {               
            return control as T;           
        }       
    }       
    return null;  
}  
 

万能用法当然是调用FindControl<T>(this, id); 这里this代表Page。但是从性能上着想,最好是从其Parent Control ID开始调用。回到上面那个例子,当然就是如此调用了:

TextBox tbName = FindControl<TextBox>(Repeater1, "textBoxName");
posted @ 2009-01-21 11:03  痘痘熊  阅读(1601)  评论(4编辑  收藏  举报