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,如下圖
若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的動作
以Stopwatch.Start()及Stopwatch.Stop()測試處理時間,二者寫法上均為2毫秒即可Find完全部Row裡的TextBox Control
顯示執行效率上並未有顯著的差別
以上若有錯誤,歡迎不吝指正囉
參考資料:
使用 NamingContainer 屬性決定控制項的命名容器
By No.18