如何更好的理解控件的层次关系

今天做项目,在做到dataGrid嵌套dataGrid时,做成了二个模板列,在用FindControl()时,却找不到对应名字的控件。其实还是没有弄清楚理解里面的层次关系。
偶尔想起网上看到的一篇博客调用一个方法可以解决这个问题,与大家分享一下。
  大部分ASP.NET控件都实现INamingContainer接口,包括 DataGrid,  Repeater, 和 the DataList.
下例是建一个带有
DataGrid的form 。以HTML格式输出.

<form id="Form1" method="post" runat="server">

   <asp:DataGrid id=DataGrid1 runat="server" DataSource="<%# employees1 %>"

        AutoGenerateColumns="False"

        OnSelectedIndexChanged="DataGrid1_SelectedIndexChanged"

        OnEditCommand="DataGrid1_EditCommand">

     <Columns>

       <asp:BoundColumn DataField="emp_id" SortExpression="emp_id" HeaderText="emp_id"/>

       <asp:BoundColumn DataField="fname" SortExpression="fname" HeaderText="fname"/>

       <asp:BoundColumn DataField="lname" SortExpression="lname" HeaderText="lname"/>

       <asp:TemplateColumn>

         <ItemTemplate>

           <asp:TextBox Runat="server" ID="TextBox1" />

         </ItemTemplate>

       </asp:TemplateColumn>

       <asp:ButtonColumn Text="Select" CommandName="Select"></asp:ButtonColumn>

       <asp:EditCommandColumn ButtonType="LinkButton" UpdateText="Update"

               CancelText="Cancel" EditText="Edit">

       </asp:EditCommandColumn>

     </Columns>

   </asp:DataGrid>

</form>

form中的DataGird将从一个已知的table里显示数据。使用模板列,在DataGird的每一行增加一个带有ID的TextBox。下面是ASP.NET形成的HTML的内容(浏览器上的源文件):

<table cellspacing="0" rules="all" border="1" id="DataGrid1">

    <tr>

    <td>emp_id</td><td>fname</td><td>lname</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td>

  </tr>

  <tr>

    <td>A-C71970F</td><td>Aria</td><td>Cruz</td><td>

      <input name="DataGrid1:_ctl2:TextBox1" type="text" id="DataGrid1__ctl2_TextBox1" />

    </td><td>

  </tr>

  <tr>

    <td>A-R89858F</td><td>Annette</td><td>Roulet</td><td>

      <input name="DataGrid1:_ctl3:TextBox1" type="text" id="DataGrid1__ctl3_TextBox1" />

    </td><td>

  </tr>

public class FindUtil

{

   public static string DumpParents(Control c)

   {

      StringBuilder sb = new StringBuilder();

      sb.Append(c.ID + " (" + c.GetType().ToString() + ")");

      while(c.Parent != null)

      {

         c = c.Parent;

         sb.Append(" -><br>");

         sb.Append(c.ID + " (" + c.GetType().ToString() + ")");

      }

      return sb.ToString();

   }

}

这里我们可以看到有很多TextBox1的实例,但是每个ID都预先有增加一些的标识符信息的处理。这个行为是因为有INamingContainer在工作。DataGrid实现INamingContainer接口,并且以每个子控件的ID再加上DataGrid1来描述此控件。因此我们可以很马上看出来,DataGrid是使用一个DataGridItem集合控件来呈现每一行的数据。一个DataGridItem 控件也实现INamingContainer接口,用子控件的名字和它自己产生的标识符来描述自己(‘_ctrl2’, ‘_ctrl3’等等)。现在,如果我们使用如下的代码,FindControl将返回一个空值

Control c = Page.FindControl(“TextBox1”)

Page控件找不到TextBox1,因为TextBox控件把自己隐藏在INamingContainer控件集合中。另外,哪个控件是我们真正想要返回的控件呢?是页上的TextBox控件?最后的TextBox控件?有代表性的例子是,当你想要找到一个在DataGrid中TextBox,将会在客户已经选择的指定的行上找TextBox.例如:我们增加一个选择列来允许用户点击一个Hyperlink来选择已选择的列。让我们来试下捕获下TextBox控件SelectedIndexChanged事件吧

以下代码是在选择DataGridItem对象时调用FindControl方法

private void DataGrid1_SelectedIndexChanged(object sender, System.EventArgs e)

{

   TextBox b;

   b = DataGrid1.Items[DataGrid1.SelectedIndex].FindControl("TextBox1") as TextBox;

   if(b != null)

   {

      Response.Write("Sender = " + sender.GetType().ToString() + "<br>");

      Response.Write("Found Textbox1 in SelectedIndexChanged event<br>");

      Response.Write(FindUtil.DumpParent(b));  

}}

我们可以增加一些额外的输出来更清楚地看下TextBox的关系链。 TextBox1控件有个TableCell对象作为父控件,返回一个DataGridItem对象的子控件,这个链一直到Page控件。代码演示如下(运行结果见页末)

public class FindUtil

{

   public static string DumpParents(Control c)

   {

      StringBuilder sb = new StringBuilder();

      sb.Append(c.ID + " (" + c.GetType().ToString() + ")");

      while(c.Parent != null)

      {

         c = c.Parent;

         sb.Append(" -><br>");

         sb.Append(c.ID + " (" + c.GetType().ToString() + ")");

      }

 

      return sb.ToString();

   }

}

  以上代码将使父类控件引用建立一个控件IDS的string对象(当一个控件ID存在---不是所有的在form中的控件都有一个服务端的ID)和控件类型

我们也可以增加一个EditCommandColumn在DataGrid中,便于用户选择一行来编辑。EditCommand event handler 是较简单的,因为第二个参数对于Handler来讲是DataGridCommandEventArgs类型,其包含一个用户已经选择的DataGridItem的引用。

protected void DataGrid1_EditCommand(object source,

                                     DataGridCommandEventArgs e)

{

   TextBox b;

   b = e.Item.FindControl("TextBox1") as TextBox;

   if(b != null)

   {

      Response.Write("Found Textbox1 in EditCommand event<br>");

   }       

}

运行结果如下:
Sender = System.Web.UI.WebControls.DataGrid
Found TextBox1 in SelectedIndexChanged event
TestBox1(System.Web.UI.WebControls.TextBox)->
(System.Web.UI.WebControls.TableCell)->
(System.Web.UI.WebControls.DataGridItem)->
(System.Web.UI.WebControls.DataGridTable)->
DataGrid1(System.Web.UI.WebControls.DataGrid)->
Form1(System.Web.UI.HtmlControls.HtmlForm)->
(ASP.FindControl4pre_aspx)

英文网址如下:
http://www.odetocode.com/Articles/116.aspx

posted on 2007-09-12 22:25  appleMay  阅读(357)  评论(0编辑  收藏  举报

导航