[ASP.NET] 透析FindControl

  • 11687
  • 0
  • 2011-11-11

Control.FindControl:在目前命名容器搜尋具有指定 id 參數的伺服器控制項

換句話說是以NamingContainer來搜尋,而非Parent的關係去搜尋(重點觀念)

一般來說NamingContainer的階層數目會比Parent的關係數目來的少,因為只有Implements INamingContainer 的Control

才能成為NamingContaine

FindControl,我想大部份的人應該都不陌生,尤其在一些可以自訂Template的Control裡,例如GridView、DataList等

討論區中常常也可以看到一些有關FindControl的一些提問,最近在一些機會下針對FindControl有一些Code上的討論

,主要是針對GridView的,這也促使我好奇的去探究FindControl的實際運作原理

 

首先MSDN寫道:

Control.FindControl:在目前命名容器搜尋具有指定 id 參數的伺服器控制項

換句話說是以NamingContainer來搜尋,而非Parent的關係去搜尋(重點觀念

一般來說NamingContainer的階層數目會比Parent的關係數目來的少,因為只有Implements INamingContainer 的Control

才能成為NamingContainer

 

以GridView為例,在ItemTemplate裡放入一個Button及TextBox,如下圖

image

 

若Button Click時取得各個TextBox所填的值,則在GridView RowCommand Event中可以給予以下的Code

Button button = e.CommandSource as Button;

TextBox tb = button.Parent.Parent.FindControl("TextBox1") as TextBox;   //A寫法

TextBox tb = button.Parent.FindControl("TextBox1") as TextBox;   //B寫法

TextBox tb = button.FindControl("TextBox1") as TextBox;   //C寫法

 

這三種寫法均可以Find到TextBox Control,有趣的是以往我都是採用A寫法

主要是因為之前的認知是Button位於Cell裡,若要取得同Row裡的其它Control

得回到Row層再去Find,然而這樣的認知並不完全正確

原因就在於這個例子裡的Button或TextBox,其NamingContainer都是GridViewRow

因此C寫法即可Find到同Row列中的其它Control,利用檢視原始碼可以發現顯示在前端的Button及TextBox其Name的值會是

name="GridView1$ctl02$TextBox2"

name="GridView1$ctl02$Button1"

,這表明了在Naming的Container,是GridViewRow而非Cell,在MSDN文件可以看到GridViewRow有 Implements INamingContainer

 

B寫法會成立的原因,進一步利用Reflector分析FindControl(因程式碼可能涉及法律問題,在此就不列上來了),其中具有幾個判斷

1.判斷目前的Control是否有Implements INamingContainer

2.當目前的Control不具Implements INamingContainer時,依據Control Tree得到目前Control的NamingContainer Control

3.依找到的NamingContainer Control進行FindControl

至此真相就很明顯了

因button.Parent會是指向DataControlFieldCell,而DataControlFieldCell並不具Implements INamingContainer(MSDN)

故最後仍會找到具Implements INamingContainer的GridViewRow

 

經過這個分析之後,對於FindControl有了更正確的認知,也解開了不同寫法上的疑惑

 

最後再測試以Row[i].FindControl與Row[i].Cell[j].FindControl在執行效率上是否有差

以一個2000筆Row的GridView,在Cell放入TextBox,然後在外面以一個Button模擬儲存2000筆RowData的動作

image

以Stopwatch.Start()及Stopwatch.Stop()測試處理時間,二者寫法上均為2毫秒即可Find完全部Row裡的TextBox Control

顯示執行效率上並未有顯著的差別

 

以上若有錯誤,歡迎不吝指正囉

 

參考資料:

Control.NamingContainer

GridViewRow Class

使用 NamingContainer 屬性決定控制項的命名容器

DataControlFieldCell 類別

Control.FindControl Method

 

若本文對您有所幫助,歡迎轉貼,但請在加註【轉貼】及來源出處,並在附上本篇的超連結,感恩您的配合囉。

By No.18