Denominazione degli ID di controllo nelle pagine di contenuto (VB)
Illustra come i controlli ContentPlaceHolder fungono da contenitore di denominazione e quindi rendono difficile l'uso di un controllo a livello di codice (tramite FindControl). Esamina questo problema e le soluzioni alternative. Viene inoltre illustrato come accedere a livello di codice al valore ClientID risultante.
Introduzione
Tutti i controlli server ASP.NET includono una ID
proprietà che identifica in modo univoco il controllo ed è il mezzo con cui il controllo è accessibile a livello di codice nella classe code-behind. Analogamente, gli elementi di un documento HTML possono includere un id
attributo che identifica in modo univoco l'elemento. Questi id
valori vengono spesso usati nello script lato client per fare riferimento a un particolare elemento HTML a livello di codice. Dato questo, è possibile presupporre che quando viene eseguito il rendering di un controllo server ASP.NET in HTML, il relativo ID
valore viene usato come id
valore dell'elemento HTML sottoposto a rendering. Questo non è necessariamente il caso perché in determinate circostanze un singolo controllo con un singolo ID
valore può apparire più volte nel markup sottoposto a rendering. Si consideri un controllo GridView che include un oggetto TemplateField con un controllo Web Label con un ID
valore .ProductName
Quando GridView è associato all'origine dati in fase di esecuzione, questa etichetta viene ripetuta una volta per ogni riga gridView. Ogni etichetta sottoposta a rendering richiede un valore univoco id
.
Per gestire questi scenari, ASP.NET consente di innominare determinati controlli come contenitori di denominazione. Un contenitore di denominazione funge da nuovo ID
spazio dei nomi. Tutti i controlli server visualizzati all'interno del contenitore di denominazione hanno il relativo valore di cui è stato ID
eseguito il rendering id
con il prefisso del controllo contenitore di denominazione. Ad esempio, le GridView
classi e GridViewRow
sono entrambi contenitori di denominazione. Di conseguenza, a un controllo Label definito in un oggetto GridView TemplateField con ID
ProductName
viene assegnato un valore di cui è stato id
eseguito il rendering.GridViewID_GridViewRowID_ProductName
Poiché GridViewRowID è univoco per ogni riga gridView, i valori risultanti sono univoci id
.
Nota
L'interfaccia INamingContainer
viene usata per indicare che un particolare controllo server ASP.NET deve funzionare come contenitore di denominazione. L'interfaccia INamingContainer
non specifica alcun metodo che il controllo server deve implementare, ma viene usato come marcatore. Nella generazione del markup sottoposto a rendering, se un controllo implementa questa interfaccia, il motore di ASP.NET antepone automaticamente il ID
valore ai valori degli attributi visualizzati id
dai discendenti. Questo processo viene illustrato in modo più dettagliato nel passaggio 2.
I contenitori di denominazione non solo modificano il valore dell'attributo sottoposto a rendering id
, ma influiscono anche sulla modalità di riferimento del controllo a livello di codice dalla classe code-behind della pagina ASP.NET. Il FindControl("controlID")
metodo viene comunemente usato per fare riferimento a un controllo Web a livello di codice. Tuttavia, FindControl
non penetra attraverso i contenitori di denominazione. Di conseguenza, non è possibile usare direttamente il Page.FindControl
metodo per fare riferimento ai controlli all'interno di un controllo GridView o in un altro contenitore di denominazione.
Come si può supporre, le pagine master e ContentPlaceHolders vengono entrambe implementate come contenitori di denominazione. In questa esercitazione viene esaminato il modo in cui le pagine master influiscono sui valori degli elementi id
HTML e sui modi per fare riferimento a livello di codice ai controlli Web all'interno di una pagina del contenuto usando FindControl
.
Passaggio 1: Aggiunta di una nuova pagina ASP.NET
Per illustrare i concetti illustrati in questa esercitazione, aggiungere una nuova pagina ASP.NET al sito Web. Creare una nuova pagina di contenuto denominata IDIssues.aspx
nella cartella radice, associandola alla Site.master
pagina master.
Figura 01: Aggiungere la pagina IDIssues.aspx
contenuto alla cartella radice
Visual Studio crea automaticamente un controllo Contenuto per ognuno dei quattro ContentPlaceHolders della pagina master. Come indicato nell'esercitazione Su più contentPlaceHolders e contenuto predefinito, se un controllo Contenuto non è presente, il contenuto ContentPlaceHolder predefinito della pagina master viene generato. Poiché i QuickLoginUI
e LeftColumnContent
ContentPlaceHolders contengono markup predefiniti adatti per questa pagina, procedere e rimuovere i controlli Contenuto corrispondenti da IDIssues.aspx
. A questo punto, il markup dichiarativo della pagina del contenuto dovrebbe essere simile al seguente:
<%@ 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>
Nell'esercitazione Specifica del titolo, dei meta tag e di altre intestazioni HTML nell'esercitazione Pagina master è stata creata una classe di pagina di base personalizzata (BasePage
) che configura automaticamente il titolo della pagina se non è impostata in modo esplicito. Affinché la IDIssues.aspx
pagina usi questa funzionalità, la classe code-behind della pagina deve derivare dalla BasePage
classe ( anziché System.Web.UI.Page
). Modificare la definizione della classe code-behind in modo che abbia un aspetto simile al seguente:
Partial Class IDIssues
Inherits BasePage
End Class
Aggiornare infine il Web.sitemap
file in modo da includere una voce per questa nuova lezione. Aggiungere un <siteMapNode>
elemento e impostarne title
gli attributi e url
rispettivamente su "Control ID Naming Issues" e ~/IDIssues.aspx
. Dopo aver apportato questa aggiunta, il Web.sitemap
markup del file dovrebbe essere simile al seguente:
<?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>
Come illustrato nella figura 2, la nuova voce della mappa del sito in Web.sitemap
viene immediatamente riflessa nella sezione Lezioni nella colonna a sinistra.
Figura 02: La sezione Lezioni include ora un collegamento a "Problemi di denominazione degli ID di controllo"
Passaggio 2: Esame delle modifiche sottoposte aID
rendering
Per comprendere meglio le modifiche apportate dal motore di ASP.NET ai valori di cui è stato eseguito id
il rendering dei controlli server, aggiungere alcuni controlli Web alla IDIssues.aspx
pagina e quindi visualizzare il markup sottoposto a rendering inviato al browser. In particolare, digitare il testo "Please enter your age:" seguito da un controllo Web TextBox. Più in basso nella pagina aggiungere un controllo Web Button e un controllo Web Etichetta. Impostare rispettivamente le proprietà Age
e e Columns
di ID
TextBox su e 3. Impostare le proprietà e ID
del Text
pulsante su "Invia" e SubmitButton
. Cancellare la proprietà dell'etichetta Text
e impostarla ID
su Results
.
A questo punto il markup dichiarativo del controllo Contenuto dovrebbe essere simile al seguente:
<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>
La figura 3 mostra la pagina quando viene visualizzata tramite la finestra di progettazione di Visual Studio.
Figura 03: La pagina include tre controlli Web: un controllo TextBox, un pulsante e un'etichetta (fare clic per visualizzare l'immagine a dimensione intera)
Visitare la pagina tramite un browser e quindi visualizzare l'origine HTML. Come illustrato nel markup seguente, i id
valori degli elementi HTML per i controlli Web TextBox, Button e Label sono una combinazione dei ID
valori dei controlli Web e dei ID
valori dei contenitori di denominazione nella pagina.
<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>
Come indicato in precedenza in questa esercitazione, sia la pagina master che i relativi ContentPlaceHolders fungono da contenitori di denominazione. Di conseguenza, entrambi contribuiscono ai valori visualizzati dei relativi controlli annidati ID
. Prendere l'attributo di id
TextBox, ad esempio : ctl00_MainContent_Age
. Tenere presente che il valore del ID
controllo TextBox era Age
. È preceduto dal valore del ID
controllo ContentPlaceHolder, MainContent
. Inoltre, questo valore è preceduto dal valore della ID
pagina master, ctl00
. L'effetto netto è un id
valore di attributo costituito dai ID
valori della pagina master, del controllo ContentPlaceHolder e del controllo TextBox stesso.
La figura 4 illustra questo comportamento. Per determinare il rendering id
del Age
controllo TextBox, iniziare con il ID
valore del controllo TextBox, Age
. Successivamente, è possibile modificare la gerarchia dei controlli. In ogni contenitore di denominazione (questi nodi con un colore pesca), anteporre id
al rendering corrente il rendering con il contenitore di denominazione .id
Figura 04: Gli attributi sottoposti a id
rendering sono basati sui ID
valori dei contenitori di denominazione
Nota
Come illustrato, la ctl00
parte dell'attributo di cui è stato id
eseguito il rendering costituisce il ID
valore della pagina master, ma ci si potrebbe chiedere come è venuto questo ID
valore. Non è stato specificato in nessun punto della pagina master o del contenuto. La maggior parte dei controlli server in una pagina ASP.NET viene aggiunta in modo esplicito tramite il markup dichiarativo della pagina. Il MainContent
controllo ContentPlaceHolder è stato specificato in modo esplicito nel markup di Site.master
. Il Age
markup di TextBox è stato definito IDIssues.aspx
. È possibile specificare i ID
valori per questi tipi di controlli tramite il Finestra Proprietà o dalla sintassi dichiarativa. Altri controlli, come la pagina master stessa, non sono definiti nel markup dichiarativo. Di conseguenza, i relativi ID
valori devono essere generati automaticamente. Il motore ASP.NET imposta i ID
valori in fase di esecuzione per i controlli i cui ID non sono stati impostati in modo esplicito. Usa il modello ctlXX
di denominazione , dove XX è un valore intero che aumenta in sequenza.
Poiché la pagina master stessa funge da contenitore di denominazione, anche i controlli Web definiti nella pagina master hanno modificato i valori degli attributi di cui è stato id
eseguito il rendering. Ad esempio, l'etichetta DisplayDate
aggiunta alla pagina master nell'esercitazione Creazione di un layout a livello di sito con pagine master include il markup sottoposto a rendering seguente:
<span id="ctl00_DateDisplay">current date</span>
Si noti che l'attributo id
include sia il valore della ID
pagina master (ctl00
) che il ID
valore del controllo Web Etichetta (DateDisplay
).
Passaggio 3: Riferimento a controlli Web a livello di codice tramiteFindControl
Ogni ASP.NET controllo server include un FindControl("controlID")
metodo che cerca nei discendenti del controllo un controllo denominato controlID. Se viene trovato un controllo di questo tipo, viene restituito; se non viene trovato alcun controllo corrispondente, FindControl
restituisce Nothing
.
FindControl
è utile negli scenari in cui è necessario accedere a un controllo, ma non si dispone di un riferimento diretto. Quando si usano controlli Web dati come GridView, ad esempio, i controlli all'interno dei campi di GridView vengono definiti una volta nella sintassi dichiarativa, ma in fase di esecuzione viene creata un'istanza del controllo per ogni riga gridView. Di conseguenza, i controlli generati in fase di esecuzione esistono, ma non è disponibile un riferimento diretto dalla classe code-behind. Di conseguenza, è necessario usare per lavorare FindControl
a livello di codice con un controllo specifico all'interno dei campi di GridView. Per altre informazioni sull'uso FindControl
di per accedere ai controlli all'interno dei modelli di un controllo Web dati, vedere Formattazione personalizzata basata su dati. Questo stesso scenario si verifica quando si aggiungono dinamicamente controlli Web a un Web Form, un argomento descritto in Creazione di interfacce utente di immissione dati dinamica.
Per illustrare l'uso del FindControl
metodo per cercare i controlli all'interno di una pagina del contenuto, creare un gestore eventi per l'evento dell'oggetto SubmitButton
Click
. Nel gestore eventi aggiungere il codice seguente, che fa riferimento Age
a textBox e Results
Label a livello di codice usando il FindControl
metodo e quindi visualizza un messaggio in Results
in base all'input dell'utente.
Nota
Naturalmente, non è necessario usare FindControl
per fare riferimento ai controlli Label e TextBox per questo esempio. È possibile farvi riferimento direttamente tramite i valori ID
delle proprietà. Uso FindControl
qui per illustrare cosa accade quando si usa FindControl
da una pagina di contenuto.
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
Mentre la sintassi usata per chiamare il FindControl
metodo è leggermente diversa nelle prime due righe di SubmitButton_Click
, sono semanticamente equivalenti. Tenere presente che tutti i controlli server ASP.NET includono un FindControl
metodo . Include la Page
classe , da cui tutte le classi code-behind ASP.NET devono derivare. Pertanto, la chiamata equivale a chiamare FindControl("controlID")
Page.FindControl("controlID")
, presupponendo che non sia stato eseguito l'override del FindControl
metodo nella classe code-behind o in una classe di base personalizzata.
Dopo aver immesso questo codice, visitare la IDIssues.aspx
pagina tramite un browser, immettere l'età e fare clic sul pulsante "Invia". Quando si fa clic sul pulsante "Invia" viene generato un NullReferenceException
oggetto (vedere la figura 5).
Figura 05: Viene generato un oggetto (NullReferenceException
fare clic per visualizzare l'immagine a dimensione intera)
Se si imposta un punto di interruzione nel SubmitButton_Click
gestore eventi, si noterà che entrambe le chiamate per FindControl
restituire Nothing
. Viene NullReferenceException
generato quando si tenta di accedere alla Age
proprietà di Text
TextBox.
Il problema è che Control.FindControl
cerca solo i discendenti di Control che si trovano nello stesso contenitore di denominazione. Poiché la pagina master costituisce un nuovo contenitore di denominazione, una chiamata a Page.FindControl("controlID")
non permea mai l'oggetto ctl00
pagina master . Fare riferimento alla figura 4 per visualizzare la gerarchia dei controlli, che mostra l'oggetto Page
come padre dell'oggetto ctl00
pagina master. Pertanto, l'etichetta e il Results
controllo TextBox non vengono trovati e ResultsLabel
AgeTextBox
vengono assegnati valori di .Nothing
Age
Esistono due soluzioni alternative a questa sfida: è possibile eseguire il drill-down, un contenitore di denominazione alla volta, al controllo appropriato; oppure è possibile creare un metodo personalizzato FindControl
che permea i contenitori di denominazione. Esaminiamo ognuna di queste opzioni.
Drill-in del contenitore di denominazione appropriato
Per fare FindControl
riferimento Results
a Label o Age
TextBox, è necessario chiamare FindControl
da un controllo predecessore nello stesso contenitore di denominazione. Come illustrato nella figura 4, il MainContent
controllo ContentPlaceHolder è l'unico predecessore di o Age
che si trova nello stesso contenitore di Results
denominazione. In altre parole, la chiamata del FindControl
MainContent
metodo dal controllo , come illustrato nel frammento di codice seguente, restituisce correttamente un riferimento ai Results
controlli o Age
.
Dim ResultsLabel As Label = CType(MainContent.FindControl("Results"), Label)
Dim AgeTextBox As TextBox = CType(MainContent.FindControl("Age"), TextBox)
Tuttavia, non è possibile usare contentPlaceHolder MainContent
dalla classe code-behind della pagina del contenuto usando la sintassi precedente perché ContentPlaceHolder è definito nella pagina master. È invece necessario usare FindControl
per ottenere un riferimento a MainContent
. Sostituire il codice nel SubmitButton_Click
gestore eventi con le modifiche seguenti:
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
Se si visita la pagina tramite un browser, immettere l'età e fare clic sul pulsante "Invia", viene generato un oggetto NullReferenceException
. Se si imposta un punto di interruzione nel SubmitButton_Click
gestore eventi, si noterà che questa eccezione si verifica quando si tenta di chiamare il MainContent
metodo dell'oggetto FindControl
. L'oggetto MainContent
è uguale a Nothing
perché il FindControl
metodo non è in grado di individuare un oggetto denominato "MainContent". Il motivo sottostante è lo stesso dei Results
controlli Label e Age
TextBox: FindControl
avvia la ricerca dall'inizio della gerarchia dei controlli e non penetra nei contenitori di denominazione, ma MainContent
ContentPlaceHolder si trova all'interno della pagina master, ovvero un contenitore di denominazione.
Prima di poter usare FindControl
per ottenere un riferimento a MainContent
, è necessario innanzitutto un riferimento al controllo pagina master. Dopo aver ottenuto un riferimento alla pagina master, è possibile ottenere un riferimento a MainContent
ContentPlaceHolder tramite FindControl
e, da qui, i riferimenti all'etichetta Results
e Age
al controllo TextBox (anche in questo caso tramite ).FindControl
Ma come si ottiene un riferimento alla pagina master? Esaminando gli id
attributi nel markup sottoposto a rendering, è evidente che il valore della ID
pagina master è ctl00
. Pertanto, è possibile usare Page.FindControl("ctl00")
per ottenere un riferimento alla pagina master, quindi usare tale oggetto per ottenere un riferimento a MainContent
e così via. Il frammento di codice seguente illustra questa logica:
'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)
Anche se questo codice funzionerà certamente, presuppone che la pagina master generata automaticamente ID
sia ctl00
sempre . Non è mai consigliabile fare ipotesi sui valori generati automaticamente.
Fortunatamente, un riferimento alla pagina master è accessibile tramite la Page
proprietà della Master
classe. Pertanto, invece di dover usare FindControl("ctl00")
per ottenere un riferimento alla pagina master per accedere MainContent
a ContentPlaceHolder, è invece possibile usare Page.Master.FindControl("MainContent")
. Aggiornare il SubmitButton_Click
gestore eventi con il codice seguente:
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
Questa volta, visitando la pagina tramite un browser, immettendo l'età e facendo clic sul pulsante "Invia" viene visualizzato il messaggio nell'etichetta Results
, come previsto.
Figura 06: l'età dell'utente viene visualizzata nell'etichetta (fare clic per visualizzare l'immagine a dimensione intera)
Ricerca ricorsiva tramite contenitori di denominazione
Il motivo per cui l'esempio di codice precedente ha fatto riferimento al MainContent
controllo ContentPlaceHolder dalla pagina master e quindi ai Results
controlli Label e Age
TextBox da MainContent
è dovuto al fatto che il Control.FindControl
metodo cerca solo all'interno del contenitore di denominazione di Control. La FindControl
presenza all'interno del contenitore di denominazione ha senso nella maggior parte degli scenari perché due controlli in due contenitori di denominazione diversi possono avere gli stessi ID
valori. Si consideri il caso di un controllo GridView che definisce un controllo Web Label denominato ProductName
all'interno di uno dei relativi Campi Template. Quando i dati sono associati a GridView in fase di esecuzione, viene creata un'etichetta ProductName
per ogni riga gridView. Se FindControl
viene eseguita la ricerca in tutti i contenitori di denominazione e viene chiamato Page.FindControl("ProductName")
, quale istanza di Label deve restituire FindControl
? Etichetta ProductName
nella prima riga gridView? Quello nell'ultima riga?
Pertanto, la Control.FindControl
ricerca del contenitore di denominazione di Control ha senso nella maggior parte dei casi. Esistono tuttavia altri casi, ad esempio quello che ci si trova di fronte, in cui è presente un oggetto univoco ID
in tutti i contenitori di denominazione e si vuole evitare di dover fare riferimento meticolosamente a ogni contenitore di denominazione nella gerarchia di controllo per accedere a un controllo. Anche la presenza di una FindControl
variante che esegue ricerche ricorsive in tutti i contenitori di denominazione ha senso. Sfortunatamente, .NET Framework non include tale metodo.
La buona notizia è che è possibile creare un metodo personalizzato FindControl
che esegue ricerche ricorsive in tutti i contenitori di denominazione. Infatti, usando i metodi di estensione è possibile modificare un FindControlRecursive
metodo per la classe per accompagnarne il Control
metodo esistenteFindControl
.
Nota
I metodi di estensione sono una novità di C# 3.0 e Visual Basic 9, ovvero i linguaggi forniti con .NET Framework versione 3.5 e Visual Studio 2008. In breve, i metodi di estensione consentono a uno sviluppatore di creare un nuovo metodo per un tipo di classe esistente tramite una sintassi speciale. Per altre informazioni su questa funzionalità utile, vedere l'articolo Estensione della funzionalità del tipo di base con i metodi di estensione.
Per creare il metodo di estensione, aggiungere un nuovo file alla App_Code
cartella denominata PageExtensionMethods.vb
. Aggiungere un metodo di estensione denominato FindControlRecursive
che accetta come parametro di String
input denominato controlID
. Affinché i metodi di estensione funzionino correttamente, è fondamentale che la classe sia contrassegnata come e Module
che i metodi di estensione siano preceduti dall'attributo <Extension()>
. Inoltre, tutti i metodi di estensione devono accettare come primo parametro un oggetto del tipo a cui si applica il metodo di estensione.
Aggiungere il codice seguente al PageExtensionMethods.vb
file per definire questo Module
e il FindControlRecursive
metodo di estensione:
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
Con questo codice sul posto, tornare alla IDIssues.aspx
classe code-behind della pagina e impostare come commento le chiamate al metodo corrente FindControl
. Sostituirli con le chiamate a Page.FindControlRecursive("controlID")
. Ciò che è chiaro sui metodi di estensione è che vengono visualizzati direttamente negli elenchi a discesa IntelliSense. Come illustrato nella figura 7, quando si digita Page
e quindi si raggiunge il punto, il FindControlRecursive
metodo viene incluso nell'elenco a discesa IntelliSense insieme agli altri Control
metodi di classe.
Figura 07: I metodi di estensione sono inclusi negli elenchi a discesa IntelliSense (fare clic per visualizzare l'immagine a dimensione intera)
Immettere il codice seguente nel SubmitButton_Click
gestore eventi e quindi testarlo visitando la pagina, immettendo l'età e facendo clic sul pulsante "Invia". Come illustrato nella figura 6, l'output risultante sarà il messaggio "You are age years!"
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
Nota
Poiché i metodi di estensione non hanno familiarità con C# 3.0 e Visual Basic 9, se si usa Visual Studio 2005 non è possibile usare metodi di estensione. Sarà invece necessario implementare il FindControlRecursive
metodo in una classe helper. Rick Strahl ha un esempio nel suo post di blog, ASP.NET Maser Pages e FindControl
.
Passaggio 4: Uso del valore dell'attributo correttoid
nello script lato client
Come indicato nell'introduzione di questa esercitazione, l'attributo sottoposto a rendering id
di un controllo Web viene spesso usato nello script lato client per fare riferimento a un particolare elemento HTML a livello di codice. Ad esempio, il codice JavaScript seguente fa riferimento a un elemento HTML in base al relativo id
e quindi visualizza il relativo valore in una finestra di messaggio modale:
var elem = document.getElementById("Age");
if (elem != null)
alert("You entered " + elem.value + " into the Age text box.");
Tenere presente che nelle pagine ASP.NET che non includono un contenitore di denominazione, l'attributo dell'elemento id
HTML sottoposto a rendering è identico al valore della proprietà del ID
controllo Web. Per questo motivo, si tenta di impostare come hardcoded nei valori degli attributi nel id
codice JavaScript. Ciò significa che, se si sa di voler accedere al Age
controllo Web TextBox tramite script sul lato client, eseguire questa operazione tramite una chiamata a document.getElementById("Age")
.
Il problema con questo approccio è che quando si usano pagine master (o altri controlli contenitore di denominazione), il codice HTML id
sottoposto a rendering non è sinonimo della proprietà del ID
controllo Web. La prima inclinazione può essere quella di visitare la pagina tramite un browser e visualizzare l'origine per determinare l'attributo effettivo id
. Dopo aver appreso il valore di cui è stato eseguito id
il rendering, è possibile incollarlo nella chiamata a per accedere all'elemento getElementById
HTML che è necessario usare tramite lo script sul lato client. Questo approccio è inferiore all'ideale perché alcune modifiche alla gerarchia di controllo della pagina o alle modifiche alle ID
proprietà dei controlli di denominazione modificheranno l'attributo risultante id
, interrompendo così il codice JavaScript.
La buona notizia è che il valore dell'attributo di cui viene eseguito il id
rendering è accessibile nel codice lato server tramite la proprietà del ClientID
controllo Web. È consigliabile usare questa proprietà per determinare il valore dell'attributo id
usato nello script sul lato client. Ad esempio, per aggiungere una funzione JavaScript alla pagina che, quando viene chiamata, visualizza il valore di Age
TextBox in una finestra di messaggio modale, aggiungere il codice seguente al Page_Load
gestore eventi:
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)
Il codice precedente inserisce il valore della Age
proprietà di ClientID
TextBox nella chiamata JavaScript a getElementById
. Se si visita questa pagina tramite un browser e si visualizza l'origine HTML, si troverà il codice JavaScript seguente:
<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>
Si noti che il valore dell'attributo corretto id
, ctl00_MainContent_Age
, viene visualizzato all'interno della chiamata a getElementById
. Poiché questo valore viene calcolato in fase di esecuzione, funziona indipendentemente dalle modifiche successive alla gerarchia dei controlli pagina.
Nota
Questo esempio JavaScript mostra semplicemente come aggiungere una funzione JavaScript che fa riferimento correttamente all'elemento HTML sottoposto a rendering da un controllo server. Per usare questa funzione, è necessario creare codice JavaScript aggiuntivo per chiamare la funzione quando il documento viene caricato o quando viene eseguita un'azione utente specifica. Per altre informazioni su questi argomenti e correlati, vedere Uso dello script sul lato client.
Riepilogo
Alcuni controlli server ASP.NET fungono da contenitori di denominazione, che influiscono sui valori degli attributi sottoposti a rendering id
dei relativi controlli discendenti, nonché sull'ambito dei controlli di cui è stato eseguito il FindControl
canvas dal metodo . Per quanto riguarda le pagine master, sia la pagina master stessa che i relativi controlli ContentPlaceHolder sono contenitori di denominazione. Di conseguenza, è necessario eseguire un po' di lavoro per fare riferimento a controlli a livello di codice all'interno della pagina del contenuto usando FindControl
. In questa esercitazione sono state esaminate due tecniche: drill-in the ContentPlaceHolder controllo e chiamata del relativo FindControl
metodo e rollover dell'implementazione personalizzata FindControl
che esegue ricerche ricorsive in tutti i contenitori di denominazione.
Oltre ai problemi sul lato server, i contenitori di denominazione introducono per quanto riguarda il riferimento ai controlli Web, esistono anche problemi sul lato client. In assenza di denominazione dei contenitori, il valore della proprietà del ID
controllo Web e il valore dell'attributo di cui è stato id
eseguito il rendering sono uno nello stesso. Tuttavia, con l'aggiunta del contenitore di denominazione, l'attributo sottoposto a id
rendering include sia i ID
valori del controllo Web che i contenitori di denominazione nella gerarchia di controllo. Questi problemi di denominazione sono un problema a condizione che si usi la proprietà del ClientID
controllo Web per determinare il valore dell'attributo sottoposto id
a rendering nello script sul lato client.
Buon programmatori!
Altre informazioni
Per altre informazioni sugli argomenti illustrati in questa esercitazione, vedere le risorse seguenti:
- ASP.NET pagine master e
FindControl
- Creazione di interfacce utente di immissione dati dinamica
- Procedura: Fare riferimento al contenuto della pagina master ASP.NET
- Mater Pages: suggerimenti, trucchi e trappole
- Uso dello script sul lato client
Informazioni sull'autore
Scott Mitchell, autore di più libri ASP/ASP.NET e fondatore di 4GuysFromRolla.com, ha lavorato con le tecnologie Web Microsoft dal 1998. Scott lavora come consulente indipendente, formatore e scrittore. Il suo ultimo libro è Sams Teach Yourself ASP.NET 3.5 in 24 ore. Scott può essere raggiunto all'indirizzo mitchell@4GuysFromRolla.com o tramite il suo blog all'indirizzo http://ScottOnWriting.NET.
Grazie speciale a
Questa serie di esercitazioni è stata esaminata da molti revisori utili. I revisori potenziali per questa esercitazione erano Zack Jones e Suchi Barnerjee. Si è interessati a esaminare i prossimi articoli MSDN? In tal caso, rilasciarmi una riga in mitchell@4GuysFromRolla.com.