Share via


內容頁中的控制項識別碼命名 (C#)

作者 :Scott Mitchell

下載 PDF

說明 ContentPlaceHolder 控制項如何做為命名容器,因此透過 FindControl) ,以程式設計方式使用難以 (的控件。 查看此問題和因應措施。 也討論如何以程序設計方式存取產生的 ClientID 值。

簡介

所有 ASP.NET 伺服器控制項都包含可唯一 ID 識別控制件的屬性,而且是在程式代碼後置類別中以程式設計方式存取控制項的方法。 同樣地,HTML 檔中的元素可能包含可唯一 id 識別元素的屬性;這些 id 值通常用於用戶端腳本中,以程式設計方式參考特定 HTML 元素。 假設當 ASP.NET 伺服器控件轉譯為 HTML 時,其 ID 值會當做 id 轉譯的 HTML 元素的值使用。 這不一定是這種情況,因為在某些情況下,具有單一值的單 ID 一控件可能會在轉譯的標記中出現多次。 請考慮 GridView 控件,其中包含具有 ProductName 值的 Label Web 控制件 ID 的 TemplateField。 當 GridView 在運行時間系結至其數據源時,每個 GridView 數據列都會重複此標籤一次。 每個轉譯的標籤都需要唯 id 一的值。

若要處理這類案例,ASP.NET 允許將某些控件表示為命名容器。 命名容器可作為新的 ID 命名空間。 任何出現在命名容器內的伺服器控制件,其轉譯 id 值前面都會加上 ID 命名容器控制件的 。 例如, GridViewGridViewRow 類別都是命名容器。 因此,使用 ProductName 在 GridView TemplateField ID 中定義的 Label 控件會獲得轉譯 id 的值 GridViewID_GridViewRowID_ProductName。 由於 GridViewRowID 對於每個 GridView 數據列而言都是唯一的,因此產生的 id 值是唯一的。

注意

介面INamingContainer是用來指出特定 ASP.NET 伺服器控制項應該做為命名容器。 介面 INamingContainer 不會拼出伺服器控件必須實作的任何方法,而是用來做為標記。 在產生轉譯的標記中,如果控件實作這個介面,則 ASP.NET 引擎會自動將其值前置至其 ID 子代的轉譯 id 屬性值。 在步驟 2 中會更詳細地討論此程式。

命名容器不僅會變更轉譯的 id 屬性值,也會影響控件如何以程序設計方式從 ASP.NET 頁面的程序代碼後置類別參考。 方法 FindControl("controlID") 通常用來以程式設計方式參考 Web 控制項。 不過, FindControl 不會透過命名容器來滲透。 因此,您無法直接使用 Page.FindControl 方法來參考 GridView 或其他命名容器內的控件。

由於您可能已代理,主版頁面和 ContentPlaceHolders 都會實作為命名容器。 在本教學課程中,我們會檢查主版頁面如何影響 HTML 元素 id 值,以及使用 FindControl以程式設計方式參考內容頁面中 Web 控制件的方式。

步驟 1:新增 ASP.NET 頁面

為了示範本教學課程中所討論的概念,讓我們在網站中新增 ASP.NET 頁面。 在根資料夾中建立名為 IDIssues.aspx 的新內容頁面,並將它系結至 Site.master 主版頁面。

將內容頁面IDIssues.aspx新增至根資料夾

圖 01:將內容頁面 IDIssues.aspx 新增至根資料夾

Visual Studio 會自動為每個主版頁面的四個 ContentPlaceHolders 建立內容控件。 如 多個 ContentPlaceHolders 和預設內容 教學課程中所述,如果內容控件不存在,則會改為發出主版頁面的預設 ContentPlaceHolder 內容。 QuickLoginUI由於和 LeftColumnContent ContentPlaceHolders 包含此頁面的適當預設標記,請繼續並從 中移除其對應的 Content 控件IDIssues.aspx。 此時,內容頁面的宣告式標記看起來應該如下所示:

<%@ Page Language="C#" MasterPageFile="~/Site.master" AutoEventWireup="true" CodeFile="IDIssues.aspx.cs" Inherits="IDIssues" Title="Untitled Page" %>

<asp:Content ID="Content1" ContentPlaceHolderID="head" Runat="Server">
</asp:Content>

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" Runat="Server">
</asp:Content>

在主版頁面教學課程中 指定標題、中繼標籤和其他 HTML 標頭 中,我們建立了自定義基頁類別 () BasePage ,如果未明確設定,就會自動設定頁面的標題。 IDIssues.aspx若要讓頁面採用這項功能,頁面的程式代碼後置類別必須衍生自 BasePage 類別 (,而不是 System.Web.UI.Page) 。 修改程式代碼後置類別的定義,使其看起來如下:

public partial class IDIssues : BasePage
{
}

最後,更新 Web.sitemap 檔案以包含此新課程的專案。 <siteMapNode>新增 元素,並將其 titleurl 屬性分別設定為「控制項識別碼命名問題」和 ~/IDIssues.aspx。 進行此新增之後,檔案 Web.sitemap 的標記看起來應該類似下列:

<?xml version="1.0" encoding="utf-8" ?>
<siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" >
 <siteMapNode url="~/Default.aspx" title="Home">
 <siteMapNode url="~/About.aspx" title="About the Author" />
 <siteMapNode url="~/MultipleContentPlaceHolders.aspx" title="Using Multiple ContentPlaceHolder Controls" />
 <siteMapNode url="~/Admin/Default.aspx" title="Rebasing URLs" />
 <siteMapNode url="~/IDIssues.aspx" title="Control ID Naming Issues" />
 </siteMapNode>
</siteMap>

如圖 2 所示,中的 Web.sitemap 新網站地圖專案會立即反映在左欄的 Lessons 區段中。

課程區段現在包含「控件標識碼命名問題」的連結

圖 02:課程區段現在包含「控件標識碼命名問題」的連結

步驟 2:檢查轉譯的ID變更

若要進一步瞭解 ASP.NET 引擎對伺服器控件的轉譯 id 值所做的修改,讓我們將一些 Web 控件新增至 IDIssues.aspx 頁面,然後檢視傳送至瀏覽器的轉譯標記。 具體而言,輸入文字「請輸入您的年齡:」,後面接著 TextBox Web 控件。 在頁面上進一步新增按鈕 Web 控制件和標籤 Web 控制件。 分別將 TextBox 的 IDColumns 屬性設定為 Age 和 3。 將按鈕的 Text 屬性 ID 設定為「Submit」 與 SubmitButton。 清除 Label 的 屬性, Text 並將設定 IDResults

此時,內容控件的宣告式標記看起來應該如下所示:

<p>
 Please enter your age:
 <asp:TextBox ID="Age" Columns="3" runat="server"></asp:TextBox>
</p>
<p>
 <asp:Button ID="SubmitButton" runat="server" Text="Submit" />
</p>
<p>
 <asp:Label ID="Results" runat="server"></asp:Label>
</p>

圖 3 顯示透過 Visual Studio 設計工具檢視時的頁面。

頁面包含三個 Web 控制件:TextBox、按鈕和標籤

圖 03:頁面包含三個 Web 控件:TextBox、按鈕和標籤 (按鍵即可檢視完整大小的影像)

透過瀏覽器瀏覽頁面,然後檢視 HTML 來源。 如下列標記所示,idTextBox、Button 和 Label Web 控件的 HTML 元素值是 Web 控件的值和ID頁面中命名容器的值的組合ID

<p>
 Please enter your age:
 <input name="ctl00$MainContent$Age" type="text" size="3" id="ctl00_MainContent_Age" />
</p>
<p>

 <input type="submit" name="ctl00$MainContent$SubmitButton" value="Submit" id="ctl00_MainContent_SubmitButton" />
</p>
<p>
 <span id="ctl00_MainContent_Results"></span>
</p>

如本教學課程稍早所述,主版頁面及其 ContentPlaceHolders 都可作為命名容器。 因此,兩者都會貢獻其巢狀控件的轉 ID 譯值。 取得 TextBox 的 id 屬性,例如: ctl00_MainContent_Age。 回想一下,TextBox 控制件的值 IDAge。 其 ContentPlaceHolder 控制件 ID 的值 MainContent前面會加上 。 此外,此值前面會加上主版頁面ID的值 。 ctl00 淨效果是由 id 主版頁面、ContentPlaceHolder 控件和 TextBox 本身的值所組成的 ID 屬性值。

圖 4 說明此行為。 若要判斷 TextBox 的呈現idAge,請從 ID TextBox 控件Age的值開始。 接下來,處理控制階層的方式。 在每個命名容器 (具有 peach 色彩的節點) ,在目前轉譯 id 的前面加上命名容器的 id

轉譯的標識碼屬性是以命名容器的標識碼值為基礎

圖 04:轉譯id的屬性是以命名容器的值為基礎ID

注意

如我們所討論, ctl00 轉譯 id 屬性的部分構成 ID 主版頁面的值,但您可能想知道此值 ID 的產生方式。 我們並未在主版或內容頁面中的任何位置指定它。 ASP.NET 頁面中的大部分伺服器控件都會透過頁面的宣告式標記明確新增。 MainContent ContentPlaceHolder 控件在 的Site.master標記中明確指定;AgeTextBox 已定義的IDIssues.aspx標記。 我們可以透過 屬性視窗 或宣告式語法,指定ID這些控件類型的值。 宣告式標記中未定義其他控件,例如主版頁面本身。 因此, ID 其值必須自動產生給我們。 ASP.NET 引擎會在 ID 運行時間設定標識元尚未明確設定的控件值。 它會使用命名模式 ctlXX,其中 XX 是循序增加的整數值。

因為主版頁面本身會做為命名容器,所以主版頁面中定義的 Web 控件也會改變轉譯 id 的屬性值。 例如, DisplayDate 我們在使用主版 頁面建立 Site-Wide 版 面配置教學課程中新增至主版頁面的標籤具有下列轉譯標記:

<span id="ctl00_DateDisplay">current date</span>

請注意, id 屬性包含主版頁面 ID 的值 () ctl00 ,以及 ID 標籤 Web 控件的值 (DateDisplay) 。

步驟 3:透過程式設計方式參考 Web 控制件FindControl

每個 ASP.NET 伺服器控制項都包含一個 FindControl("controlID") 方法來搜尋控件的子系,以尋找名為 controlID的控制件。 如果找到這類控件,則會傳回它;如果找不到相符的控制件,則 FindControlnull回 。

FindControl 在您需要存取控件但沒有直接參考的案例中,非常有用。 例如,使用 GridView 之類的數據 Web 控件時,GridView 欄位內的控件會在宣告式語法中定義一次,但在運行時間會為每個 GridView 數據列建立控件的實例。 因此,運行時間產生的控件存在,但我們沒有可從程式代碼後置類別取得的直接參考。 因此,我們需要使用 FindControl ,以程序設計方式在 GridView 的欄位中使用特定控制件。 (如需使用 FindControl 來存取數據 Web 控件範本內控件的詳細資訊,請參閱 根據 Data.) 動態新增 Web 控件至 Web Form 時會發生這個相同案例,這是 建立動態數據輸入使用者介面中所討論的主題。

為了說明如何使用 FindControl 方法來搜尋內容頁面中的控件,請為 SubmitButtonClick 事件建立事件處理程式。 在 事件處理程式中,新增下列程式代碼,以程式設計方式使用 方法來參考 Age TextBox 和 Results Label,然後根據使用者的輸入顯示訊息ResultsFindControl

注意

當然,我們不需要使用 FindControl 來參考此範例的 Label 和 TextBox 控制件。 我們可以透過屬性值 ID 直接參考它們。 我在這裡使用 FindControl 來說明從內容頁面使用 FindControl 時會發生什麼情況。

protected void SubmitButton_Click(object sender, EventArgs e)
{
    Label ResultsLabel = FindControl("Results") as Label;
    TextBox AgeTextBox = Page.FindControl("Age") as TextBox;

    ResultsLabel.Text = string.Format("You are {0} years old!", AgeTextBox.Text);
}

雖然用來呼叫 FindControl 方法的 SubmitButton_Click語法在的前兩行稍有不同,但它們在語意上相等。 回想一下,所有 ASP.NET 伺服器控制件都包含 FindControl 方法。 這包括 Page 類別,所有 ASP.NET 程式代碼後置類別都必須衍生自此類別。 因此,呼叫 FindControl("controlID") 相當於呼叫 Page.FindControl("controlID"),假設您尚未覆 FindControl 寫程式代碼後置類別或自定義基類中的方法。

輸入此程式代碼之後,請 IDIssues.aspx 瀏覽瀏覽器的頁面,輸入您的年齡,然後按下 [提交] 按鈕。 按兩下 [提交] 按鈕 NullReferenceException 時,會引發 (請參閱圖 5) 。

引發 NullReferenceException

圖 05NullReferenceException 引發 (按單擊即可檢視完整大小的影像)

如果您在事件處理程式中 SubmitButton_Click 設定斷點,您會看到這兩個呼叫都會傳 FindControlnull 值。 NullReferenceException當我們嘗試存取 Age TextBox 的 Text 屬性時,就會引發 。

問題在於Control.FindControl,只會搜尋位於相同命名容器中的Control子代。 因為主版頁面會構成新的命名容器,所以一律不會滲透主版頁面物件的ctl00呼叫Page.FindControl("controlID")。 (請參閱圖 4 以檢視控件階層,其中會將對象顯示為Page主版頁面物件的父代 ctl00。) 因此,Results找不到 ResultsLabel Label 和 Age TextBox,且AgeTextBox已指派的值null

這項挑戰有兩個因應措施:我們可以向下切入,一次一個命名容器,以取得適當的控件;或者,我們可以建立自己的 FindControl 方法,以滲透命名容器。 讓我們檢查每一個選項。

鑽研適當的命名容器

若要使用 FindControl 來參考 Results Label 或 Age TextBox,我們需要從相同命名容器中的上階控件呼叫 FindControl 。 如圖 4 所示, MainContent ContentPlaceHolder 控件是唯一位於 Results 相同命名容器內的 或 Age 上階。 換句話說,從控件呼叫 FindControl 方法,如下列代碼段所示,正確地傳回 或 Age 控件的ResultsMainContent參考。

Label ResultsLabel = MainContent.FindControl("Results") as Label;
TextBox AgeTextBox = MainContent.FindControl("Age") as TextBox;

不過,我們無法 MainContent 使用上述語法,從內容頁面的程式代碼後置類別使用 ContentPlaceHolder,因為 ContentPlaceHolder 是在主版頁面中定義。 相反地,我們必須使用 FindControl 來取得 的 MainContent參考。 將事件處理程式中的 SubmitButton_Click 程式代碼取代為下列修改:

protected void SubmitButton_Click(object sender, EventArgs e)
{
    ContentPlaceHolder MainContent = FindControl("MainContent") as ContentPlaceHolder;

    Label ResultsLabel = MainContent.FindControl("Results") as Label;
    TextBox AgeTextBox = MainContent.FindControl("Age") as TextBox;

    ResultsLabel.Text = string.Format("You are {0} years old!", AgeTextBox.Text);
}

如果您透過瀏覽器瀏覽頁面,請輸入您的年齡,然後按下 [提交] 按鈕, NullReferenceException 就會引發 。 如果您在事件處理程式中 SubmitButton_Click 設定斷點,就會在嘗試呼叫 MainContent 物件的 FindControl 方法時看到此例外狀況發生。 物件 MainContent 是因為 nullFindControl 方法找不到名為 「MainContent」 的物件。 根本原因是與 Results Label 和 Age TextBox 控制件相同: FindControl 從控件階層的頂端開始搜尋,而且不會包含命名容器,但 MainContent ContentPlaceHolder 位於主版頁面內,這是命名容器。

我們必須先需要主版頁面控件的參考,才能使用 FindControl 來取得的參考 MainContent。 一旦有了主版頁面的參考,就可以透過 FindControl 取得 ContentPlaceHolder 的MainContent參考,然後透過使用 FindControl) ,再次參考 Results Label 和 Age TextBox (。 但如何取得主版頁面的參考? 藉由檢查 id 轉譯標記中的屬性,就很明顯地表示主版頁面 ID 的值是 ctl00。 因此,我們可以使用 Page.FindControl("ctl00") 來取得主版頁面的參考,然後使用該物件來取得 的參考 MainContent等等。 下列代碼段說明此邏輯:

// Get a reference to the master page
MasterPage ctl00 = FindControl("ctl00") as MasterPage;

// Get a reference to the ContentPlaceHolder
ContentPlaceHolder MainContent = ctl00.FindControl("MainContent") as ContentPlaceHolder;

// Reference the Label and TextBox controls
Label ResultsLabel = MainContent.FindControl("Results") as Label;
TextBox AgeTextBox = MainContent.FindControl("Age") as TextBox;

雖然此程式代碼確實可以運作,但假設主版頁面的自動產生 ID 一律為 ctl00。 對自動產生的值做出假設絕不是個不錯的主意。

幸運的是,主版頁面的參考可透過 Page 類別的 Master 屬性存取。 因此,我們不必使用 FindControl("ctl00") 來取得主版頁面的參考,以存取 MainContent ContentPlaceHolder,而是改用 Page.Master.FindControl("MainContent")SubmitButton_Click使用下列程式代碼更新事件處理程式:

protected void SubmitButton_Click(object sender, EventArgs e)
{
    ContentPlaceHolder MainContent = Page.Master.FindControl("MainContent") as ContentPlaceHolder;

    Label ResultsLabel = MainContent.FindControl("Results") as Label;
    TextBox AgeTextBox = MainContent.FindControl("Age") as TextBox;

    ResultsLabel.Text = string.Format("You are {0} years old!", AgeTextBox.Text);
}

這次,透過瀏覽器瀏覽頁面、輸入您的年齡,然後按下 [提交] 按鈕會顯示標籤中的 Results 訊息,如預期般顯示。

用戶的年齡會顯示在標籤中

圖 06:使用者年齡會顯示在標籤 (按兩下以檢視全大小影像)

以遞歸方式搜尋命名容器

上一個程式代碼範例從主版頁面參考 MainContent ContentPlaceHolder 控件,然後ResultsMainContentControl.FindControl 參考 Label 和 Age TextBox 控制件的原因是方法只會在 Control 的命名容器內搜尋。 在大部分情況下,保持 FindControl 命名容器內很合理,因為兩個不同命名容器中的兩個控件可能會有相同的 ID 值。 請考慮 GridView 的案例,其定義其其中一個 TemplateFields 內名為 ProductName 的標籤 Web 控制件。 當數據在運行時間系結至 GridView 時, ProductName 會為每個 GridView 數據列建立標籤。 如果 FindControl 搜尋所有命名容器,且我們呼叫 Page.FindControl("ProductName")了 ,則應該傳 FindControl 回哪個 Label 實例? 第 ProductName 一個 GridView 數據列中的標籤? 最後一個數據列中的哪一個?

因此,在大部分情況下,只要 Control.FindControl 搜尋 Control 的命名容器就有意義。 但還有其他情況,例如我們面向的案例,我們在所有命名容器中都有唯一的 ID ,而且想要避免在控件階層中明確參考每個命名容器,以存取控件。 擁有 FindControl 遞歸搜尋所有命名容器的變體也有意義。 不幸的是,.NET Framework 不包含這類方法。

好消息是我們可以建立自己的 FindControl 方法,以遞歸方式搜尋所有命名容器。 事實上,我們可以使用 擴充方法 將 方法附加 FindControlRecursiveControl 類別,以隨附其現有的 FindControl 方法。

注意

擴充方法是 C# 3.0 和 Visual Basic 9 的新功能,這是隨附於 .NET Framework 3.5 版和 Visual Studio 2008 的語言。 簡單地說,擴充方法可讓開發人員透過特殊語法建立現有類別類型的新方法。 如需這項實用功能的詳細資訊,請參閱我的文章: 使用擴充方法擴充基底類型功能

若要建立擴充方法,請將新檔案新增至 App_Code 名為 PageExtensionMethods.cs的資料夾。 新增名為 FindControlRecursive 的擴充方法,以作為名為 controlID的參數輸入string。 若要讓擴充方法正常運作,請務必將類別本身及其擴充方法標示 static為 。 此外,所有擴充方法都必須接受作為其第一個參數,這是延伸方法所套用之型別的物件,而且這個輸入參數前面必須加上 關鍵詞 this

將下列程式代碼新增至 PageExtensionMethods.cs 類別檔案,以定義此類別和 FindControlRecursive 擴充方法:

using System;
using System.Web;
using System.Web.UI;

public static class PageExtensionMethods
{
    public static Control FindControlRecursive(this Control ctrl, string controlID)
    {
        if (string.Compare(ctrl.ID, controlID, true) == 0)
        {
            // We found the control!
            return ctrl;
        }
        else
        {
            // Recurse through ctrl's Controls collections
            foreach (Control child in ctrl.Controls)
            {
                Control lookFor = FindControlRecursive(child, controlID);

                if (lookFor != null)
                    return lookFor;  // We found the control
            }

            // If we reach here, control was not found
            return null;
        }
    }
}

在此程式代碼就緒后,返回 IDIssues.aspx 頁面的程式代碼後置類別,並批注化目前的 FindControl 方法呼叫。 將它們取代為 對的 Page.FindControlRecursive("controlID")呼叫。 擴充方法很整齊,在於它們直接出現在 IntelliSense 下拉式清單中。 如圖 7 所示,當您輸入 Page 和點擊期間時, FindControlRecursive 方法會包含在 IntelliSense 下拉式清單中, Control 以及其他類別方法。

擴充方法包含在 IntelliSense 下拉式清單中

圖 07:擴充方法包含在 IntelliSense 中,Drop-Downs (按兩下即可檢視完整大小的影像)

在事件處理程式中 SubmitButton_Click 輸入下列程式代碼,然後瀏覽頁面、輸入您的年齡,然後按兩下 [提交] 按鈕來測試它。 如圖 6 所示,產生的輸出會是訊息:「您年齡過年!」

protected void SubmitButton_Click(object sender, EventArgs e)
{
    Label ResultsLabel = Page.FindControlRecursive("Results") as Label;
    TextBox AgeTextBox = Page.FindControlRecursive("Age") as TextBox;

    ResultsLabel.Text = string.Format("You are {0} years old!", AgeTextBox.Text);
}

注意

因為擴充方法不熟悉 C# 3.0 和 Visual Basic 9,所以如果您使用 Visual Studio 2005,則無法使用擴充方法。 相反地,您必須在協助程序類別中實 FindControlRecursive 作 方法。 Rick Strahl 在其部落格文章中具有這類範例, ASP.NET Maser Pages 和 FindControl

步驟 4:在 Client-Side 腳本中使用正確的id屬性值

如本教學課程簡介所述,Web 控件的轉譯 id 屬性通常用於用戶端腳本,以程式設計方式參考特定的 HTML 元素。 例如,下列 JavaScript 會依其 id 參考 HTML 元素,然後在強制回應消息框中顯示其值:

var elem = document.getElementById("Age");
if (elem != null)
    alert("You entered " + elem.value + " into the Age text box.");

回想一下,在不包含命名容器的 ASP.NET 頁面中,轉譯的 HTML 元素 id 的 屬性與 Web 控制件的 ID 屬性值相同。 因此,將屬性值中的 id 硬式程式代碼硬式編碼為 JavaScript 程式代碼。 也就是說,如果您知道想要透過用戶端腳本存取 Age TextBox Web 控制件,請透過呼叫 document.getElementById("Age")來存取 。

此方法的問題在於,使用主版頁面 (或其他命名容器控件) 時,轉譯的 HTML id 與 Web 控件的 ID 屬性不相同。 您的第一個傾斜可能是透過瀏覽器瀏覽頁面,並檢視來源以判斷實際 id 屬性。 一旦您知道轉譯 id 的值,您可以將它貼到 呼叫 getElementById 中,以存取您需要透過用戶端腳本處理的 HTML 元素。 這種方法較不理想,因為頁面控件階層的某些變更或命名控件屬性的變更 ID 將會改變產生的 id 屬性,進而中斷 JavaScript 程式代碼。

好消息是 id ,轉譯的屬性值可透過 Web 控件的 ClientID 屬性,在伺服器端程式代碼中存取。 您應該使用這個屬性來判斷 id 用戶端文本中使用的屬性值。 例如,若要將 JavaScript 函式新增至呼叫時,在強制回應消息框中顯示 TextBox 的值 Age ,請將下列程式代碼新增至 Page_Load 事件處理程式:

ClientScript.RegisterClientScriptBlock(this.GetType(), "ShowAgeTextBoxScript",
 string.Format(@"function ShowAge()
 {{
 var elem = document.getElementById('{0}');
 if (elem != null)
 alert('You entered ' + elem.value + ' into the Age text box.');
 }}", AgeTextBox.ClientID), true);

上述程式代碼會將 TextBox ClientID 屬性的值 Age 插入 JavaScript getElementById呼叫中。 如果您透過瀏覽器瀏覽此頁面並檢視 HTML 來源,您會發現下列 JavaScript 程式代碼:

<script type="text/javascript">
//<![CDATA[
function ShowAge()
{
 var elem = document.getElementById('ctl00_MainContent_Age');
 if (elem != null)
 alert('You entered ' + elem.value + ' into the Age text box.');
}//]]>
</script>

請注意,正確的 id 屬性值 ctl00_MainContent_Age如何出現在 對 getElementById的呼叫內。 因為此值是在運行時間計算,所以不論後續對頁面控件階層所做的變更為何,它都能運作。

注意

這個 JavaScript 範例只會示範如何新增 JavaScript 函式,以正確參考伺服器控件所轉譯的 HTML 元素。 若要使用此函式,您必須撰寫額外的 JavaScript,以在檔載入或某些特定使用者動作轉譯時呼叫函式。 如需這些和相關主題的詳細資訊,請參閱 使用 Client-Side 腳本

摘要

某些 ASP.NET 伺服器控件會作為命名容器,這會影響其子代控件的轉 id 譯屬性值,以及方法畫布的控件 FindControl 範圍。 關於主版頁面,主版頁面本身及其 ContentPlaceHolder 控件都是命名容器。 因此,我們必須更努力使用 FindControl,以程式設計方式參考內容頁面中的控件。 在本教學課程中,我們檢查了兩種技術:鑽研 ContentPlaceHolder 控件並呼叫其 FindControl 方法,並滾動我們自己的 FindControl 實作,以遞歸方式搜尋所有命名容器。

除了命名容器與參考 Web 控制件相關的伺服器端問題之外,還有客戶端問題。 如果沒有命名容器,Web 控件的 ID 屬性值和轉譯 id 的屬性值就是同一個。 但是,新增命名容器時,轉譯 id 的屬性會同時 ID 包含 Web 控件的值和命名容器 (控件階層的) 。 只要您使用 Web 控件的 ClientID 屬性來判斷用戶端腳本中的轉譯 id 屬性值,這些命名考慮就不是問題。

快樂的程序設計!

深入閱讀

如需本教學課程中所討論之主題的詳細資訊,請參閱下列資源:

關於作者

Scott Mitchell 是多個 ASP/ASP.NET 書籍的作者,以及 4GuysFromRolla.com 的建立者,自 1998 年起就與 Microsoft Web 技術合作。 Scott 是獨立的顧問、訓練者和作者。 他的最新書籍是 Sams 在 24 小時內自行 ASP.NET 3.5。 Scott 可以透過 mitchell@4GuysFromRolla.com 在 上的部落格或透過 http://ScottOnWriting.NET其部落格來連線。

特別感謝

本教學課程系列是由許多實用的檢閱者所檢閱。 本教學課程的首席檢閱者是 Zack Jones 和 Suchi Barnerjee。 想要檢閱即將推出的 MSDN 文章嗎? 如果是,請將一行放在 mitchell@4GuysFromRolla.com