共用方式為


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

由斯科特· 米切爾

下載 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 類別都是命名容器。 因此,使用的 GridView TemplateField ID ProductName 中定義的標籤控件會得到轉譯 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="VB" MasterPageFile="~/Site.master" AutoEventWireup="false" CodeFile="IDIssues.aspx.vb" 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)。 修改程式代碼後置類別的定義,使其看起來如下:

Partial Class IDIssues
 Inherits BasePage

End Class

最後,更新 檔案以 Web.sitemap 包含這個新課程的專案。 <siteMapNode>新增 元素,並將其 和 title url 屬性分別設定為「控制項識別碼命名問題」和 ~/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。 將 Button 的 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 的轉譯id,請從 TextBox 控件的值開始IDAgeAge 接下來,請依您的方式提升控件階層。 在每個命名容器(具有桃色的節點)上,將目前呈現 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 我們在使用主版頁面建立網站版面配置教學課程中 新增至主版頁面 的標籤上列轉譯的標記:

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

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

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

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

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

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

注意

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

Protected Sub SubmitButton_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles SubmitButton.Click
 Dim ResultsLabel As Label = CType(FindControl("Results"), Label)
 Dim AgeTextBox As TextBox = CType(Page.FindControl("Age"), TextBox)

 ResultsLabel.Text = String.Format("You are {0} years old!", AgeTextBox.Text)
End Sub

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

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

引發 NullReferenceException

圖 05:引發 A NullReferenceException按兩下以檢視完整大小的影像

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

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

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

鑽研適當的命名容器

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

Dim ResultsLabel As Label = CType(MainContent.FindControl("Results"), Label)
Dim AgeTextBox As TextBox = CType(MainContent.FindControl("Age"), TextBox)

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

Protected Sub SubmitButton_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles SubmitButton.Click
 Dim MainContent As ContentPlaceHolder = CType(FindControl("MainContent"), ContentPlaceHolder)

 Dim ResultsLabel As Label = CType(MainContent.FindControl("Results"), Label)
 Dim AgeTextBox As TextBox = CType(MainContent.FindControl("Age"), TextBox)

 ResultsLabel.Text = String.Format("You are {0} years old!", AgeTextBox.Text)
End Sub

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

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

'Get a reference to the master page
Dim ctl00 As MasterPage = CType(FindControl("ctl00"), MasterPage)

'Get a reference to the ContentPlaceHolder
Dim MainContent As ContentPlaceHolder = CType(ctl00.FindControl("MainContent"), ContentPlaceHolder)

'Reference the Label and TextBox controls
Dim ResultsLabel As Label = CType(MainContent.FindControl("Results"), Label)
Dim AgeTextBox As TextBox = CType(MainContent.FindControl("Age"), TextBox)

雖然此程式代碼肯定會正常運作,但假設主版頁面的自動產生 ID 一律為 ctl00。 對自動產生的值進行假設從來不是個好主意。

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

Protected Sub SubmitButton_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles SubmitButton.Click
 'Get a reference to the ContentPlaceHolder
 Dim MainContent As ContentPlaceHolder = CType(Page.Master.FindControl("MainContent"), ContentPlaceHolder)

 'Reference the Label and TextBox controls
 Dim ResultsLabel As Label = CType(MainContent.FindControl("Results"), Label)
 Dim AgeTextBox As TextBox = CType(MainContent.FindControl("Age"), TextBox)

 ResultsLabel.Text = String.Format("You are {0} years old!", AgeTextBox.Text)
End Sub

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

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

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

以遞歸方式搜尋命名容器

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

因此, 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.vb的資料夾。 新增名為 FindControlRecursive 的擴充方法,以做為名為 controlID的參數輸入String。 若要讓擴充方法正常運作,請務必將 類別標示為 , Module 而且擴充方法前面會加上 <Extension()> 屬性。 此外,所有擴充方法都必須接受做為其第一個參數,這是擴充方法所套用之型別的物件。

將下列程式代碼新增至 PageExtensionMethods.vb 檔案,以定義這個 ModuleFindControlRecursive 擴充方法:

Imports System.Runtime.CompilerServices

Public Module PageExtensionMethods
 <Extension()> _
  Public Function FindControlRecursive(ByVal ctrl As Control, ByVal controlID As String) As Control
 If String.Compare(ctrl.ID, controlID, True) = 0 Then
 ' We found the control!
 Return ctrl
 Else
 ' Recurse through ctrl's Controls collections
 For Each child As Control In ctrl.Controls
 Dim lookFor As Control = FindControlRecursive(child, controlID)

 If lookFor IsNot Nothing Then
 Return lookFor  ' We found the control
 End If
 Next

 ' If we reach here, control was not found
 Return Nothing
 End If
 End Function
End Module

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

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

圖 07:IntelliSense 下拉式清單中包含擴充方法(按兩下以檢視完整大小的影像

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

Protected Sub SubmitButton_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles SubmitButton.Click
 Dim ResultsLabel As Label = CType(Page.FindControlRecursive("Results"), Label)
 Dim AgeTextBox As TextBox = CType(Page.FindControlRecursive("Age"), TextBox)

 ResultsLabel.Text = String.Format("You are {0} years old!", AgeTextBox.Text)
End Sub

注意

因為擴充方法不熟悉 C# 3.0 和 Visual Basic 9,所以如果您使用 Visual Studio 2005,就無法使用擴充方法。 相反地,您必須在協助程序類別中實 FindControlRecursive 作 方法。 裡克·斯特拉爾 在他的部落格文章中有這樣的例子, ASP.NET 馬瑟·頁面和 FindControl

步驟 4:在用戶端文本中使用正確的id屬性值

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

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(Me.GetType(), "ShowAgeTextBoxScript", _
 "function ShowAge() " & vbCrLf & _
 "{" & vbCrLf & _
 " var elem = document.getElementById('" & AgeTextBox.ClientID & "');" & vbCrLf & _
 " if (elem != null)" & vbCrLf & _
 " alert('You entered ' + elem.value + ' into the Age text box.');" & vbCrLf & _
 "}", 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,以在檔載入時呼叫函式,或當某些特定使用者動作發生時呼叫函式。 如需這些和相關主題的詳細資訊,請參閱 使用用戶端腳本

摘要

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

除了針對參考 Web 控件而引進的伺服器端問題之外,還有客戶端問題。 如果沒有命名容器,Web 控件的 ID 屬性值和轉譯 id 的屬性值就是相同的值。 但是,隨著命名容器的新增,轉譯 id 的 屬性會在其 ID 控件階層的祖系中包含 Web 控件的值和命名容器(s)。 只要您使用 Web 控件的 ClientID 屬性來判斷用戶端腳本中轉譯 id 的屬性值,這些命名考慮是非問題。

快樂的程序設計!

深入閱讀

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

關於作者

斯科特·米切爾,多個 ASP/ASP.NET 書籍的作者,4GuysFromRolla.com 的創始人,自1998年以來一直與Microsoft Web 技術合作。 斯科特擔任獨立顧問、教練和作家。 他的最新書是 山姆斯在24小時內 ASP.NET 3.5。 斯科特可以透過 mitchell@4GuysFromRolla.com 他在的部落格聯繫到或通過他的博客 http://ScottOnWriting.NET

特別感謝

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