程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> 細說FindControl

細說FindControl

編輯:C#入門知識

今天幫朋友解決一個問題ListView中怎麼FindControl不到子控件。
直接調用ListView1.FindControl("idLable") 報個錯未將對象實例內個錯抱著好奇的心態我百度了下。大概有4種辦法我就不說了。


 其中一種辦法是


[csharp]  Response.Write(ListView1.FindControl("ListView1$ctrl0$idLabel")); 

Response.Write(ListView1.FindControl("ListView1$ctrl0$idLabel"));

主要問題是id變了。ID變成Control.UniqueID了。為什麼會出現這種情況呢。

抱著好奇的心態我查了下msdn原來ListView實現了INamingContainer接口子控件的Control.UniqueID變成了父容器加子容器的形式了!難怪

Response.Write(ListView1.FindControl("ListView1$ctrl0$idLabel"))可以找到這個控件。現在看似問題解決了。可是還是有個問題

[csharp]  protected void ListView1_ItemDataBound(object sender, ListViewItemEventArgs e) 
    { 
        //這裡和Repeater稍有不同  
 
        if (e.Item.ItemType == ListViewItemType.DataItem) 
        { 
 
            Label txtName = (Label)e.Item.FindControl("idLable"); 
 
            txtName.Text = "我是ListView中被查找的子控件"; 
 
        } 
    } 

protected void ListView1_ItemDataBound(object sender, ListViewItemEventArgs e)
    {
        //這裡和Repeater稍有不同

        if (e.Item.ItemType == ListViewItemType.DataItem)
        {

            Label txtName = (Label)e.Item.FindControl("idLable");

            txtName.Text = "我是ListView中被查找的子控件";

        }
    }

這個方法也能找到Lable不是說FindControl傳的是Control.UniqueID麼?這裡傳idLable怎麼可以?經過我和獅虎仔細討論之後終於得出了結論。

我們可以看e.Item的類型


[csharp]  namespace System.Web.UI.WebControls 

    // 摘要:  
    //     表示 System.Web.UI.WebControls.ListView 控件中的單個項。  
    [ToolboxItem(false)] 
    public class ListViewItem : Control, IDataItemContainer, INamingContainer 
    { 
        // 摘要:  
        //     初始化 System.Web.UI.WebControls.ListViewItem 類的新實例。  
        //  
        // 參數:  
        //   itemType:  
        //     System.Web.UI.WebControls.ListViewItemType 枚舉值之一。  
        [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] 
        public ListViewItem(ListViewItemType itemType); 
 
        // 摘要:  
        //     獲取或設置 System.Web.UI.WebControls.ListViewItem 對象綁定到的基礎數據對象。  
        //  
        // 返回結果:  
        //     System.Web.UI.WebControls.ListViewItem 對象綁定到的基礎數據對象。  
        public virtual object DataItem { get; set; } 
        //  
        // 摘要:  
        //     獲取綁定到 System.Web.UI.WebControls.ListViewItem 控件的數據項的索引。  
        //  
        // 返回結果:  
        //     綁定到 System.Web.UI.WebControls.ListViewItem 控件的數據項的索引。  
        public virtual int DataItemIndex { get; } 
        //  
        // 摘要:  
        //     獲取數據項在 System.Web.UI.WebControls.ListView 控件中顯示的位置。  
        //  
        // 返回結果:  
        //     數據項在 System.Web.UI.WebControls.ListView 控件中顯示的位置。  
        public virtual int DisplayIndex { get; } 
        //  
        // 摘要:  
        //     獲取 System.Web.UI.WebControls.ListViewItem 對象的項類型。  
        //  
        // 返回結果:  
        //     System.Web.UI.WebControls.ListViewItemType 值之一。  
        public ListViewItemType ItemType { get; } 
 
        // 摘要:  
        //     確定是否將事件沿頁面的 ASP.NET 服務器控件層次結構向上傳遞。  
        //  
        // 參數:  
        //   source:  
        //     事件源。  
        //  
        //   e:  
        //     事件數據。  
        //  
        // 返回結果:  
        //     如果事件已被取消,則為 true;否則為 false。  
        protected override bool OnBubbleEvent(object source, EventArgs e); 
    } 

namespace System.Web.UI.WebControls
{
    // 摘要:
    //     表示 System.Web.UI.WebControls.ListView 控件中的單個項。
    [ToolboxItem(false)]
    public class ListViewItem : Control, IDataItemContainer, INamingContainer
    {
        // 摘要:
        //     初始化 System.Web.UI.WebControls.ListViewItem 類的新實例。
        //
        // 參數:
        //   itemType:
        //     System.Web.UI.WebControls.ListViewItemType 枚舉值之一。
        [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
        public ListViewItem(ListViewItemType itemType);

        // 摘要:
        //     獲取或設置 System.Web.UI.WebControls.ListViewItem 對象綁定到的基礎數據對象。
        //
        // 返回結果:
        //     System.Web.UI.WebControls.ListViewItem 對象綁定到的基礎數據對象。
        public virtual object DataItem { get; set; }
        //
        // 摘要:
        //     獲取綁定到 System.Web.UI.WebControls.ListViewItem 控件的數據項的索引。
        //
        // 返回結果:
        //     綁定到 System.Web.UI.WebControls.ListViewItem 控件的數據項的索引。
        public virtual int DataItemIndex { get; }
        //
        // 摘要:
        //     獲取數據項在 System.Web.UI.WebControls.ListView 控件中顯示的位置。
        //
        // 返回結果:
        //     數據項在 System.Web.UI.WebControls.ListView 控件中顯示的位置。
        public virtual int DisplayIndex { get; }
        //
        // 摘要:
        //     獲取 System.Web.UI.WebControls.ListViewItem 對象的項類型。
        //
        // 返回結果:
        //     System.Web.UI.WebControls.ListViewItemType 值之一。
        public ListViewItemType ItemType { get; }

        // 摘要:
        //     確定是否將事件沿頁面的 ASP.NET 服務器控件層次結構向上傳遞。
        //
        // 參數:
        //   source:
        //     事件源。
        //
        //   e:
        //     事件數據。
        //
        // 返回結果:
        //     如果事件已被取消,則為 true;否則為 false。
        protected override bool OnBubbleEvent(object source, EventArgs e);
    }
}


ListViewItem繼承了INamingContainer接口。好吧現在讓我們理解為什麼ListView1.FindControl("ldLable")不行而Label txtName = (Label)e.Item.FindControl("idLabel")可以。INamingContainer接口是讓子控件的Control.UniqueID變成類似父容器加子控件的形式。而在Label txtName = (Label)e.Item.FindControl("idLabel")注意這個事件是綁定行的時候發生的也就是說e.Item就代表一行。他是idLable的上一級控件。所以Label txtName = (Label)e.Item.FindControl("idLabel")在FindControl的時候必定會先轉化為Control.UniqueID!這樣就不違反FindControl(Control.UniqueID)的規則了。而ListView1.FindControl("ldLable")很明顯雖然ListView繼承了INamingContainer但是他不是ldLable的上一級控件不是他的父容器。無法將ldLable轉化成父容器加子控件的Control.UniqueID,違反了FindControl(Control.UniqueID)的規則!自然找不到。


由此我推斷出了FindControl工作的大致的流程。先判斷調用他的對象是否繼承INamingContainer如果繼承就轉化為INamingContainer,將控件轉化為父容器加子控件的形式.ListView1這麼調用的時候 沒發現他的子控件有lblable ,然後再看他本身是不是服務器ID 結果發現又不是 ,就拋出異常了.而Label txtName = (Label)e.Item.FindControl("idLabel") 的時候本身就發現idLabel是他的子控件,ListViewItem又繼承了INamingContainer接口,直接轉化成"ListView1$ctrl0$idLabel"這樣當然找的到叻。哈哈。為了驗證我的想法。我自定義了一個控件讓他繼承INamingContainer.

 


[csharp]  [ToolboxData("<{0}:INamingContainerControl runat=server></{0}:INamingContainerControl>")] 
    public class INamingContainerControl : WebControl, INamingContainer //可以將 INamingContainer 去掉, 運行並查看源代碼  
    { 
        protected override void CreateChildControls() 
        { 
            TextBox textbox = new TextBox(); 
            textbox.ID = "btn"; 
            textbox.Text = "我是淡淡蜀黍"; 
            this.Controls.Add(textbox); 
 
 
            Button button = new Button(); 
            button.ID = "btnOK"; 
            button.Text = "確定"; 
            this.Controls.Add(button); 
 
        } 
 
    } 

[ToolboxData("<{0}:INamingContainerControl runat=server></{0}:INamingContainerControl>")]
    public class INamingContainerControl : WebControl, INamingContainer //可以將 INamingContainer 去掉, 運行並查看源代碼
    {
        protected override void CreateChildControls()
        {
            TextBox textbox = new TextBox();
            textbox.ID = "btn";
            textbox.Text = "我是淡淡蜀黍";
            this.Controls.Add(textbox);


            Button button = new Button();
            button.ID = "btnOK";
            button.Text = "確定";
            this.Controls.Add(button);

        }

    }


然後在html裡使用這個控件

[html]  <cc1:INamingContainerControl ID="INamingContainerControl1" runat="server" /> 
<cc1:INamingContainerControl ID="INamingContainerControl2" runat="server" /> 

<cc1:INamingContainerControl ID="INamingContainerControl1" runat="server" />
<cc1:INamingContainerControl ID="INamingContainerControl2" runat="server" />後台cs文件在Page_Load事件裡寫如下代碼通過控件本身的ID搜索

 

[csharp] view plaincopyprint?protected void Page_Load(object sender, EventArgs e) 
    { 
        Response.Write(((TextBox)(INamingContainerControl1.FindControl("btn"))).Text); 
    } 

protected void Page_Load(object sender, EventArgs e)
    {
        Response.Write(((TextBox)(INamingContainerControl1.FindControl("btn"))).Text);
    }
運行結果如圖

 

\

很明顯可以搜到控件。

再查看頁面源html:

 

[html]  <div> 
        <span id="INamingContainerControl1"><input name="INamingContainerControl1$btn" type="text" value="我是淡淡蜀黍" id="INamingContainerControl1_btn" /><input type="submit" name="INamingContainerControl1$btnOK" value="確定" id="INamingContainerControl1_btnOK" /></span> 
        <span id="INamingContainerControl2"><input name="INamingContainerControl2$btn" type="text" value="我是淡淡蜀黍" id="INamingContainerControl2_btn" /><input type="submit" name="INamingContainerControl2$btnOK" value="確定" id="INamingContainerControl2_btnOK" /></span> 
</div> 

<div>
        <span id="INamingContainerControl1"><input name="INamingContainerControl1$btn" type="text" value="我是淡淡蜀黍" id="INamingContainerControl1_btn" /><input type="submit" name="INamingContainerControl1$btnOK" value="確定" id="INamingContainerControl1_btnOK" /></span>
        <span id="INamingContainerControl2"><input name="INamingContainerControl2$btn" type="text" value="我是淡淡蜀黍" id="INamingContainerControl2_btn" /><input type="submit" name="INamingContainerControl2$btnOK" value="確定" id="INamingContainerControl2_btnOK" /></span>
</div>很明顯ID是父容器加子控件的形式的。這說明如果搜索的調用者也就是control.FindControl(string id)的這個control是子控件的父容器且繼承了INamingContainer接口完全可以通過編程是定義的ID通過FindControl搜到控件上面的推論完全成立。。問題終於解決叻。嘎嘎。

 


 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved