Bagikan melalui


Penamaan ID Kontrol di Halaman Konten (VB)

oleh Scott Mitchell

Unduh PDF

Menggambarkan bagaimana kontrol ContentPlaceHolder berfungsi sebagai kontainer penamaan dan oleh karena itu membuat bekerja secara terprogram dengan kontrol yang sulit (melalui FindControl). Lihat masalah dan solusinya. Juga membahas cara mengakses nilai ClientID yang dihasilkan secara terprogram.

Pendahuluan

Semua kontrol server ASP.NET mencakup ID properti yang secara unik mengidentifikasi kontrol dan merupakan cara kontrol diakses secara terprogram di kelas code-behind. Demikian pula, elemen dalam dokumen HTML dapat menyertakan id atribut yang secara unik mengidentifikasi elemen; nilai-nilai ini id sering digunakan dalam skrip sisi klien untuk mereferensikan elemen HTML tertentu secara terprogram. Mengingat ini, Anda dapat berasumsi bahwa ketika kontrol server ASP.NET dirender ke dalam HTML, nilainya ID digunakan sebagai id nilai elemen HTML yang dirender. Ini belum tentu terjadi karena dalam keadaan tertentu kontrol tunggal dengan satu ID nilai mungkin muncul beberapa kali dalam markup yang dirender. Pertimbangkan kontrol GridView yang menyertakan TemplateField dengan kontrol Label Web dengan ID nilai ProductName. Saat GridView terikat ke sumber datanya saat runtime, Label ini diulang sekali untuk setiap baris GridView. Setiap Label yang dirender membutuhkan nilai yang unik id .

Untuk menangani skenario tersebut, ASP.NET memungkinkan kontrol tertentu ditandai sebagai kontainer penamaan. Kontainer penamaan berfungsi sebagai namespace baru ID . Kontrol server apa pun yang muncul dalam kontainer penamaan memiliki nilai yang dirender id diawali dengan ID kontrol kontainer penamaan. Misalnya, GridView kelas dan GridViewRow keduanya adalah penamaan kontainer. Akibatnya, kontrol Label yang ditentukan dalam GridView TemplateField dengan ID ProductName diberikan nilai yang dirender id dari GridViewID_GridViewRowID_ProductName. Karena GridViewRowID unik untuk setiap baris GridView, nilai yang id dihasilkan unik.

Catatan

Antarmuka INamingContainer digunakan untuk menunjukkan bahwa kontrol server ASP.NET tertentu harus berfungsi sebagai kontainer penamaan. Antarmuka INamingContainer tidak mengeja metode apa pun yang harus diterapkan kontrol server; melainkan, digunakan sebagai penanda. Dalam menghasilkan markup yang dirender, jika kontrol mengimplementasikan antarmuka ini, mesin ASP.NET secara otomatis mengawali nilainya ID ke nilai atribut yang dirender id keturunannya. Proses ini dibahas secara lebih rinci di Langkah 2.

Penamaan kontainer tidak hanya mengubah nilai atribut yang dirender id , tetapi juga memengaruhi bagaimana kontrol dapat direferensikan secara terprogram dari kelas code-behind halaman ASP.NET. Metode FindControl("controlID") ini umumnya digunakan untuk mereferensikan kontrol Web secara terprogram. Namun, FindControl tidak menembus melalui penamaan kontainer. Akibatnya, Anda tidak dapat langsung menggunakan Page.FindControl metode untuk mereferensikan kontrol dalam GridView atau kontainer penamaan lainnya.

Seperti yang mungkin telah Anda surmised, halaman master dan ContentPlaceHolders keduanya diimplementasikan sebagai penamaan kontainer. Dalam tutorial ini kami memeriksa bagaimana halaman master memengaruhi nilai elemen id HTML dan cara untuk mereferensikan kontrol Web secara terprogram dalam halaman konten menggunakan FindControl.

Langkah 1: Menambahkan Halaman ASP.NET Baru

Untuk menunjukkan konsep yang dibahas dalam tutorial ini, mari kita tambahkan halaman ASP.NET baru ke situs web kami. Buat halaman konten baru bernama IDIssues.aspx di folder akar, mengikatnya ke Site.master halaman master.

Tambahkan IDIssues.aspx Halaman Konten ke Folder Akar

Gambar 01: Tambahkan Halaman IDIssues.aspx Konten ke Folder Akar

Visual Studio secara otomatis membuat kontrol Konten untuk masing-masing empat ContentPlaceHolder halaman master. Seperti yang disebutkan dalam tutorial Beberapa ContentPlaceHolders dan Konten Default, jika kontrol Konten tidak menyajikan konten ContentPlaceHolder default halaman master dipancarkan sebagai gantinya. QuickLoginUI Karena ContentPlaceHolders dan LeftColumnContent berisi markup default yang sesuai untuk halaman ini, lanjutkan dan hapus kontrol Konten yang sesuai dari IDIssues.aspx. Pada titik ini, markup deklaratif halaman konten akan terlihat seperti berikut ini:

<%@ 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>

Dalam tutorial Menentukan Judul, Tag Meta, dan Header HTML Lainnya dalam tutorial Halaman Master, kami membuat kelas halaman dasar kustom (BasePage) yang secara otomatis mengonfigurasi judul halaman jika tidak diatur secara eksplisit. IDIssues.aspx Agar halaman menggunakan fungsionalitas ini, kelas code-behind halaman harus berasal dari BasePage kelas (bukan System.Web.UI.Page). Ubah definisi kelas code-behind sehingga terlihat seperti berikut:

Partial Class IDIssues
 Inherits BasePage

End Class

Terakhir, perbarui Web.sitemap file untuk menyertakan entri untuk pelajaran baru ini. <siteMapNode> Tambahkan elemen dan atur title atribut dan url ke "Kontrol Masalah Penamaan ID" dan ~/IDIssues.aspx, masing-masing. Setelah membuat penambahan ini, markup file Anda Web.sitemap akan terlihat mirip dengan yang berikut ini:

<?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>

Seperti yang diilustrasikan Gambar 2, entri peta situs baru di Web.sitemap segera tercermin di bagian Pelajaran di kolom kiri.

Bagian Pelajaran Sekarang Menyertakan Tautan ke

Gambar 02: Bagian Pelajaran Sekarang Menyertakan Tautan ke "Masalah Penamaan ID Kontrol"

Langkah 2: Memeriksa Perubahan yang DirenderID

Untuk lebih memahami modifikasi yang dilakukan mesin ASP.NET pada nilai kontrol server yang dirender id , mari kita tambahkan beberapa kontrol Web ke IDIssues.aspx halaman lalu lihat markup yang dirender yang dikirim ke browser. Secara khusus, ketik teks "Silakan masukkan usia Anda:" diikuti dengan kontrol Web TextBox. Selanjutnya di halaman tambahkan kontrol Web Tombol dan kontrol Label Web. Atur TextBox ID dan Columns properti masing-masing ke Age dan 3. Atur Properti dan ID Tombol Text ke "Kirim" dan SubmitButton. Hapus properti Label Text dan atur ID ke Results.

Pada titik ini markup deklaratif kontrol Konten Anda akan terlihat mirip dengan yang berikut ini:

<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>

Gambar 3 memperlihatkan halaman saat dilihat melalui perancang Visual Studio.

Halaman Menyertakan Tiga Kontrol Web: Kotak Teks, Tombol, dan Label

Gambar 03: Halaman Menyertakan Tiga Kontrol Web: Kotak Teks, Tombol, dan Label (Klik untuk melihat gambar ukuran penuh)

Kunjungi halaman melalui browser lalu lihat sumber HTML. Seperti yang ditunjukkan markup di bawah ini, id nilai elemen HTML untuk kontrol TextBox, Button, dan Label Web adalah kombinasi dari ID nilai kontrol Web dan ID nilai kontainer penamaan di halaman.

<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>

Seperti disebutkan sebelumnya dalam tutorial ini, halaman master dan ContentPlaceHolders berfungsi sebagai penamaan kontainer. Akibatnya, keduanya berkontribusi nilai yang dirender ID dari kontrol berlapis mereka. Ambil atribut TextBox id , misalnya: ctl00_MainContent_Age. Ingat bahwa nilai kontrol ID TextBox adalah Age. Ini diawali dengan nilai kontrol ContentPlaceHolder-nya ID , MainContent. Selain itu, nilai ini diawali dengan nilai halaman ID master, ctl00. Efek bersih adalah nilai atribut yang id terdiri dari ID nilai halaman master, kontrol ContentPlaceHolder, dan TextBox itu sendiri.

Gambar 4 menggambarkan perilaku ini. Untuk menentukan yang dirender id dari Age TextBox, mulailah dengan ID nilai kontrol TextBox, Age. Selanjutnya, jalankan hierarki kontrol. Pada setiap kontainer penamaan (node tersebut dengan warna persik), awali saat ini yang dirender id dengan kontainer idpenamaan .

Atribut Id yang Dirender Didasarkan pada Nilai ID Kontainer Penamaan

Gambar 04: Atribut yang Dirender id Didasarkan pada ID Nilai Kontainer Penamaan

Catatan

Seperti yang kita bahas, ctl00 bagian dari atribut yang dirender id merupakan ID nilai halaman master, tetapi Anda mungkin bertanya-tanya bagaimana nilai ini ID muncul. Kami tidak menentukannya di mana pun di halaman master atau konten kami. Sebagian besar kontrol server di halaman ASP.NET ditambahkan secara eksplisit melalui markup deklaratif halaman. Kontrol MainContent ContentPlaceHolder secara eksplisit ditentukan dalam markup Site.master; Age TextBox ditentukan IDIssues.aspxmarkup. Kita dapat menentukan ID nilai untuk jenis kontrol ini melalui jendela Properti atau dari sintaks deklaratif. Kontrol lain, seperti halaman master itu sendiri, tidak didefinisikan dalam markup deklaratif. Akibatnya, nilai-nilainya ID harus dibuat secara otomatis untuk kita. Mesin ASP.NET mengatur ID nilai pada runtime untuk kontrol yang ID-nya belum diatur secara eksplisit. Ini menggunakan pola ctlXXpenamaan , di mana XX adalah nilai bilangan bulat yang meningkat secara berurutan.

Karena halaman master itu sendiri berfungsi sebagai kontainer penamaan, kontrol Web yang ditentukan di halaman master juga memiliki nilai atribut yang dirender id yang diubah. Misalnya, Label yang DisplayDate kami tambahkan ke halaman master dalam tutorial Membuat Tata Letak Seluruh Situs dengan Halaman Master memiliki markup yang dirender berikut ini:

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

Perhatikan bahwa id atribut menyertakan nilai halaman ID master (ctl00) dan ID nilai kontrol Web Label (DateDisplay).

Langkah 3: Mereferensikan Kontrol Web secara Terprogram melaluiFindControl

Setiap kontrol server ASP.NET menyertakan FindControl("controlID") metode yang mencari turunan kontrol untuk kontrol bernama controlID. Jika kontrol seperti itu ditemukan, kontrol tersebut dikembalikan; jika tidak ada kontrol yang cocok yang ditemukan, FindControl mengembalikan Nothing.

FindControl berguna dalam skenario di mana Anda perlu mengakses kontrol tetapi Anda tidak memiliki referensi langsung ke dalamnya. Saat bekerja dengan kontrol Web data seperti GridView, misalnya, kontrol dalam bidang GridView ditentukan sekali dalam sintaks deklaratif, tetapi pada runtime instans kontrol dibuat untuk setiap baris GridView. Akibatnya, kontrol yang dihasilkan pada runtime ada, tetapi kami tidak memiliki referensi langsung yang tersedia dari kelas code-behind. Akibatnya, kita perlu menggunakan FindControl untuk bekerja secara terprogram dengan kontrol tertentu dalam bidang GridView. (Untuk informasi selengkapnya tentang penggunaan FindControl untuk mengakses kontrol dalam templat kontrol Web data, lihat Pemformatan Kustom Berdasarkan Data.) Skenario yang sama ini terjadi ketika secara dinamis menambahkan kontrol Web ke Formulir Web, topik yang dibahas dalam Membuat Antarmuka Pengguna Entri Data Dinamis.

Untuk mengilustrasikan menggunakan FindControl metode untuk mencari kontrol dalam halaman konten, buat penanganan aktivitas untuk SubmitButtonClick peristiwa. Di penanganan aktivitas, tambahkan kode berikut, yang secara terprogram mereferensikan Age TextBox dan Results Label menggunakan FindControl metode lalu menampilkan pesan Results berdasarkan input pengguna.

Catatan

Tentu saja, kita tidak perlu menggunakan FindControl untuk mereferensikan kontrol Label dan TextBox untuk contoh ini. Kita dapat mereferensikannya langsung melalui nilai properti mereka ID . Saya menggunakan FindControl di sini untuk mengilustrasikan apa yang terjadi saat menggunakan FindControl dari halaman konten.

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

Sementara sintaks yang digunakan untuk memanggil FindControl metode sedikit berbeda dalam dua baris SubmitButton_Clickpertama , mereka setara secara semantik. Ingat bahwa semua kontrol server ASP.NET menyertakan FindControl metode . Ini termasuk Page kelas, dari mana semua kelas ASP.NET di belakang harus berasal. Oleh karena itu, panggilan setara dengan panggilan , dengan asumsi Anda belum mengesampingkan FindControl("controlID") Page.FindControl("controlID")FindControl metode di kelas code-behind Anda atau di kelas dasar kustom.

Setelah memasukkan kode ini, kunjungi IDIssues.aspx halaman melalui browser, masukkan usia Anda, dan klik tombol "Kirim". Setelah mengklik tombol "Kirim" a NullReferenceException dinaikkan (lihat Gambar 5).

NullReferenceException dimunculkan

Gambar 05: A NullReferenceException dimunculkan (Klik untuk melihat gambar ukuran penuh)

Jika Anda mengatur titik henti di SubmitButton_Click penanganan aktivitas, Anda akan melihat bahwa kedua panggilan untuk FindControl mengembalikan Nothing. NullReferenceException dimunculkan ketika kita mencoba mengakses Age properti TextBoxText.

Masalahnya adalah hanya Control.FindControl mencari turunan Control yang berada dalam kontainer penamaan yang sama. Karena halaman master merupakan kontainer penamaan baru, panggilan untuk Page.FindControl("controlID") tidak pernah meresap objek ctl00halaman master . (Lihat kembali ke Gambar 4 untuk melihat hierarki kontrol, yang memperlihatkan Page objek sebagai induk objek ctl00halaman master .) Oleh karena itu, Label dan Age Kotak Teks tidak ditemukan dan ResultsLabel dan AgeTextBox merupakan nilai yang ditetapkan dari Nothing.Results

Ada dua solusi untuk tantangan ini: kita dapat menelusuri paling detail, satu penamaan kontainer pada satu waktu, ke kontrol yang sesuai; atau kita dapat membuat metode kita sendiri FindControl yang meresap penamaan kontainer. Mari kita periksa masing-masing opsi ini.

Menelusuri Kontainer Penamaan yang Sesuai

Untuk menggunakan FindControl untuk mereferensikan Results Label atau Age TextBox, kita perlu memanggil FindControl dari kontrol leluhur dalam kontainer penamaan yang sama. Seperti yang ditunjukkan Gambar 4, MainContent kontrol ContentPlaceHolder adalah satu-satunya Results leluhur dari atau Age yang berada dalam kontainer penamaan yang sama. Dengan kata lain, memanggil FindControl metode dari MainContent kontrol, seperti yang ditunjukkan pada cuplikan kode di bawah ini, mengembalikan referensi ke Results kontrol atau Age dengan benar.

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

Namun, kami tidak dapat bekerja dengan MainContent ContentPlaceHolder dari kelas code-behind halaman konten kami menggunakan sintaks di atas karena ContentPlaceHolder didefinisikan di halaman master. Sebaliknya, kita harus menggunakan FindControl untuk mendapatkan referensi ke MainContent. Ganti kode di penanganan SubmitButton_Click aktivitas dengan modifikasi berikut:

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

Jika Anda mengunjungi halaman melalui browser, masukkan usia Anda, dan klik tombol "Kirim", akan NullReferenceException dinaikkan. Jika Anda mengatur titik henti di SubmitButton_Click penanganan aktivitas, Anda akan melihat bahwa pengecualian ini terjadi saat mencoba memanggil MainContent metode objek FindControl . Objek MainContent sama dengan Nothing karena FindControl metode tidak dapat menemukan objek bernama "MainContent". Alasan yang mendasar sama dengan Results kontrol Label dan Age TextBox: FindControl memulai pencariannya dari bagian atas hierarki kontrol dan tidak menembus kontainer penamaan, tetapi MainContent ContentPlaceHolder berada dalam halaman master, yang merupakan kontainer penamaan.

Sebelum kita dapat menggunakan FindControl untuk mendapatkan referensi ke MainContent, pertama-tama kita memerlukan referensi ke kontrol halaman master. Setelah kita memiliki referensi ke halaman master, kita bisa mendapatkan referensi ke MainContent ContentPlaceHolder melalui FindControl dan, dari sana, referensi ke Results Label dan Age TextBox (sekali lagi, melalui menggunakan FindControl). Tapi bagaimana cara mendapatkan referensi ke halaman master? Dengan memeriksa id atribut dalam markup yang dirender, terbukti bahwa nilai halaman ID master adalah ctl00. Oleh karena itu, kita dapat menggunakan Page.FindControl("ctl00") untuk mendapatkan referensi ke halaman master, lalu menggunakan objek tersebut untuk mendapatkan referensi ke MainContent, dan sebagainya. Cuplikan berikut mengilustrasikan logika ini:

'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)

Meskipun kode ini pasti akan berfungsi, ia mengasumsikan bahwa halaman master yang dibuat ID secara otomatis akan selalu ctl00. Tidak ada baiknya membuat asumsi tentang nilai yang dihasilkan secara otomatis.

Untungnya, referensi ke halaman master dapat diakses melalui Page properti kelas Master . Oleh karena itu, alih-alih harus menggunakan FindControl("ctl00") untuk mendapatkan referensi halaman master untuk mengakses MainContent ContentPlaceHolder, kita dapat menggunakan Page.Master.FindControl("MainContent"). Perbarui penanganan SubmitButton_Click aktivitas dengan kode berikut:

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

Kali ini, mengunjungi halaman melalui browser, memasuki usia Anda, dan mengklik tombol "Kirim" menampilkan pesan di Results Label, seperti yang diharapkan.

Usia Pengguna Ditampilkan di Label

Gambar 06: Usia Pengguna Ditampilkan di Label (Klik untuk melihat gambar ukuran penuh)

Mencari Secara Rekursif Melalui Penamaan Kontainer

Alasan contoh kode sebelumnya mereferensikan MainContent kontrol ContentPlaceHolder dari halaman master, lalu Results kontrol Label dan Age TextBox dari MainContent, adalah karena Control.FindControl metode hanya mencari dalam kontainer penamaan Control. Memiliki FindControl tetap dalam kontainer penamaan masuk akal dalam sebagian besar skenario karena dua kontrol dalam dua kontainer penamaan yang berbeda mungkin memiliki nilai yang sama ID . Pertimbangkan kasus GridView yang menentukan kontrol Label Web bernama ProductName dalam salah satu TemplateFields-nya. Saat data terikat ke GridView saat runtime, ProductName Label dibuat untuk setiap baris GridView. Jika FindControl dicari melalui semua kontainer penamaan dan kami memanggil Page.FindControl("ProductName"), instans Label apa yang harus dikembalikan FindControl ? ProductName Label di baris GridView pertama? Yang di baris terakhir?

Jadi memiliki Control.FindControl pencarian hanya kontainer penamaan Control masuk akal dalam banyak kasus. Tetapi ada kasus lain, seperti yang dihadapi kita, di mana kita memiliki keunikan ID di semua kontainer penamaan dan ingin menghindari harus mereferensikan setiap kontainer penamaan dengan cermat dalam hierarki kontrol untuk mengakses kontrol. Memiliki FindControl varian yang secara rekursif mencari semua kontainer penamaan juga masuk akal. Sayangnya, .NET Framework tidak menyertakan metode seperti itu.

Kabar baiknya adalah kita dapat membuat metode kita sendiri FindControl yang secara rekursif mencari semua kontainer penamaan. Bahkan, menggunakan metode ekstensi kita dapat melakukan tack pada FindControlRecursive metode ke Control kelas untuk menyertai metode yang adaFindControl.

Catatan

Metode ekstensi adalah fitur baru untuk C# 3.0 dan Visual Basic 9, yang merupakan bahasa yang dikirim dengan .NET Framework versi 3.5 dan Visual Studio 2008. Singkatnya, metode ekstensi memungkinkan pengembang membuat metode baru untuk jenis kelas yang ada melalui sintaks khusus. Untuk informasi selengkapnya tentang fitur bermanfaat ini, lihat artikel saya, Memperluas FungsiOnalitas Jenis Dasar dengan Metode Ekstensi.

Untuk membuat metode ekstensi, tambahkan file baru ke App_Code folder bernama PageExtensionMethods.vb. Tambahkan metode ekstensi bernama FindControlRecursive yang mengambil sebagai input String parameter bernama controlID. Agar metode ekstensi berfungsi dengan baik, sangat penting bahwa kelas ditandai sebagai Module dan bahwa metode ekstensi diawali dengan <Extension()> atribut . Selain itu, semua metode ekstensi harus menerima sebagai parameter pertama mereka objek jenis yang diterapkan metode ekstensi.

Tambahkan kode berikut ke PageExtensionMethods.vb file untuk menentukan ini Module dan FindControlRecursive metode ekstensi:

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

Dengan kode ini di tempat, kembali ke IDIssues.aspx kelas code-behind halaman dan komentari panggilan metode saat ini FindControl . Ganti dengan panggilan ke Page.FindControlRecursive("controlID"). Apa yang rapi tentang metode ekstensi adalah bahwa metode tersebut muncul langsung dalam daftar drop-down IntelliSense. Seperti yang ditunjukkan Gambar 7, ketika Anda mengetik Page lalu menekan periode, FindControlRecursive metode disertakan dalam menu drop-down IntelliSense bersama dengan metode kelas lainnya Control .

Metode Ekstensi Disertakan dalam Drop-Down IntelliSense

Gambar 07: Metode Ekstensi Disertakan dalam Menu Drop-Down IntelliSense (Klik untuk melihat gambar ukuran penuh)

Masukkan kode berikut ke SubmitButton_Click dalam penanganan aktivitas lalu uji dengan mengunjungi halaman, memasukkan usia Anda, dan mengklik tombol "Kirim". Seperti yang ditunjukkan kembali pada Gambar 6, output yang dihasilkan akan menjadi pesan, "Anda berusia tahun!"

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

Catatan

Karena metode ekstensi baru untuk C# 3.0 dan Visual Basic 9, jika Anda menggunakan Visual Studio 2005, Anda tidak dapat menggunakan metode ekstensi. Sebagai gantinya FindControlRecursive , Anda harus menerapkan metode di kelas pembantu. Rick Strahl memiliki contoh seperti itu dalam posting blognya, ASP.NET Halaman Maser dan FindControl.

Langkah 4: Menggunakan Nilai Atribut yang Benariddi Skrip Sisi Klien

Seperti yang disebutkan dalam pengenalan tutorial ini, atribut yang dirender id kontrol Web sering kali digunakan dalam skrip sisi klien untuk mereferensikan elemen HTML tertentu secara terprogram. Misalnya, JavaScript berikut mereferensikan elemen HTML berdasarkan elemennya id lalu menampilkan nilainya dalam kotak pesan modal:

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

Ingat bahwa di halaman ASP.NET yang tidak menyertakan kontainer penamaan, atribut elemen id HTML yang dirender identik dengan nilai properti kontrol ID Web. Karena itu, menggoda untuk kode keras dalam id nilai atribut ke dalam kode JavaScript. Artinya, jika Anda tahu bahwa Anda ingin mengakses Age kontrol Web TextBox melalui skrip sisi klien, lakukan melalui panggilan ke document.getElementById("Age").

Masalah dengan pendekatan ini adalah bahwa saat menggunakan halaman master (atau kontrol kontainer penamaan lainnya), HTML id yang dirender tidak identik dengan properti kontrol ID Web. Kenaikan pertama Anda mungkin mengunjungi halaman melalui browser dan melihat sumber untuk menentukan atribut aktual id . Setelah Anda mengetahui nilai yang dirender id , Anda dapat menempelkannya ke panggilan untuk getElementById mengakses elemen HTML yang perlu Anda kerjakan melalui skrip sisi klien. Pendekatan ini kurang ideal karena perubahan tertentu pada hierarki kontrol halaman atau perubahan pada ID properti kontrol penamaan akan mengubah atribut yang dihasilkan id , sehingga merusak kode JavaScript Anda.

Kabar baiknya adalah bahwa id nilai atribut yang dirender dapat diakses dalam kode sisi server melalui properti kontrol ClientID Web. Anda harus menggunakan properti ini untuk menentukan nilai atribut yang id digunakan dalam skrip sisi klien. Misalnya, untuk menambahkan fungsi JavaScript ke halaman yang, saat dipanggil, menampilkan nilai Age TextBox dalam kotak pesan modal, tambahkan kode berikut ke Page_Load penanganan aktivitas:

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)

Kode di atas menyuntikkan nilai Age properti TextBox ClientID ke dalam panggilan JavaScript ke getElementById. Jika Anda mengunjungi halaman ini melalui browser dan melihat sumber HTML, Anda akan menemukan kode JavaScript berikut:

<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>

Perhatikan bagaimana nilai atribut yang benar id , ctl00_MainContent_Age, muncul dalam panggilan ke getElementById. Karena nilai ini dihitung pada runtime, nilai ini berfungsi terlepas dari perubahan selanjutnya pada hierarki kontrol halaman.

Catatan

Contoh JavaScript ini hanya menunjukkan cara menambahkan fungsi JavaScript yang mereferensikan elemen HTML yang dirender dengan benar oleh kontrol server. Untuk menggunakan fungsi ini, Anda perlu menulis JavaScript tambahan untuk memanggil fungsi saat dokumen dimuat atau ketika beberapa tindakan pengguna tertentu bertranspitasi. Untuk informasi selengkapnya tentang topik ini dan terkait, baca Bekerja dengan Skrip Sisi Klien.

Ringkasan

Kontrol server ASP.NET tertentu bertindak sebagai penamaan kontainer, yang memengaruhi nilai atribut yang dirender id dari kontrol keturunannya serta cakupan kontrol yang dikanvas oleh FindControl metode . Sehubungan dengan halaman master, halaman master itu sendiri dan kontrol ContentPlaceHolder-nya adalah penamaan kontainer. Akibatnya, kita perlu memberikan sedikit lebih banyak pekerjaan untuk mereferensikan kontrol secara terprogram dalam halaman konten menggunakan FindControl. Dalam tutorial ini kami memeriksa dua teknik: menelusuri kontrol ContentPlaceHolder dan memanggil metodenya FindControl ; dan menggulirkan implementasi kami sendiri FindControl yang secara rekursif mencari melalui semua kontainer penamaan.

Selain masalah sisi server penamaan kontainer yang diperkenalkan sehubungan dengan mereferensikan kontrol Web, ada juga masalah sisi klien. Dengan tidak adanya kontainer penamaan, nilai properti kontrol ID Web dan nilai atribut yang dirender id adalah nilai yang sama. Tetapi dengan penamaan kontainer penamaan, atribut yang dirender id mencakup ID nilai kontrol Web dan kontainer penamaan dalam hierarki kontrolnya. Masalah penamaan ini bukan masalah selama Anda menggunakan properti kontrol ClientID Web untuk menentukan nilai atribut yang dirender id dalam skrip sisi klien Anda.

Selamat Pemrograman!

Bacaan lebih lanjut

Untuk informasi selengkapnya tentang topik yang dibahas dalam tutorial ini, lihat sumber daya berikut:

Tentang Penulis

Scott Mitchell, penulis beberapa buku ASP/ASP.NET dan pendiri 4GuysFromRolla.com, telah bekerja dengan teknologi Microsoft Web sejak 1998. Scott bekerja sebagai konsultan, pelatih, dan penulis independen. Buku terbarunya adalah Sams Teach Yourself ASP.NET 3,5 dalam 24 Jam. Scott dapat dijangkau di mitchell@4GuysFromRolla.com atau melalui blognya di http://ScottOnWriting.NET.

Terima kasih khusus untuk

Seri tutorial ini ditinjau oleh banyak peninjau yang bermanfaat. Peninjau utama untuk tutorial ini adalah Zack Jones dan Suchi Barnerjee. Tertarik untuk meninjau artikel MSDN saya yang akan datang? Jika demikian, drop saya baris di mitchell@4GuysFromRolla.com.