Contrôler le nommage des ID dans les pages de contenu (VB)
par Scott Mitchell
Illustre la façon dont les contrôles ContentPlaceHolder servent de conteneur d’affectation de noms et facilitent donc l’utilisation par programme d’un contrôle (via FindControl). Examine ce problème et les solutions de contournement. Explique également comment accéder par programmation à la valeur ClientID résultante.
Introduction
Tous les contrôles serveur ASP.NET incluent une ID
propriété qui identifie de manière unique le contrôle et est le moyen par lequel le contrôle est accessible par programmation dans la classe code-behind. De même, les éléments d’un document HTML peuvent inclure un id
attribut qui identifie de façon unique l’élément ; ces id
valeurs sont souvent utilisées dans le script côté client pour référencer par programmation un élément HTML particulier. Étant donné cela, vous pouvez supposer que lorsqu’un contrôle serveur ASP.NET est rendu en HTML, sa ID
valeur est utilisée comme id
valeur de l’élément HTML rendu. Ce n’est pas nécessairement le cas, car dans certaines circonstances, un seul contrôle avec une seule ID
valeur peut apparaître plusieurs fois dans le balisage rendu. Considérez un contrôle GridView qui inclut un TemplateField avec un contrôle Web Label avec une ID
valeur de ProductName
. Lorsque GridView est lié à sa source de données au moment de l’exécution, cette étiquette est répétée une fois pour chaque ligne GridView. Chaque étiquette rendue a besoin d’une valeur unique id
.
Pour gérer ces scénarios, ASP.NET permet à certains contrôles d’être indiqués comme des conteneurs d’affectation de noms. Un conteneur d’affectation de noms sert d’espace ID
de noms. Tous les contrôles serveur qui apparaissent dans le conteneur d’affectation de noms ont leur valeur rendue id
précédée du ID
contrôle de conteneur d’affectation de noms. Par exemple, les classes et GridViewRow
les GridView
classes nomment les conteneurs. Par conséquent, un contrôle Label défini dans un GridView TemplateField avec ID
ProductName
reçoit une valeur rendue id
de GridViewID_GridViewRowID_ProductName
. Étant donné que GridViewRowID est unique pour chaque ligne GridView, les valeurs obtenues id
sont uniques.
Remarque
L’interface INamingContainer
est utilisée pour indiquer qu’un contrôle serveur ASP.NET particulier doit fonctionner comme un conteneur d’affectation de noms. L’interface INamingContainer
n’indique pas les méthodes que le contrôle serveur doit implémenter ; il est plutôt utilisé comme marqueur. Lors de la génération du balisage rendu, si un contrôle implémente cette interface, le moteur ASP.NET préfixe automatiquement sa ID
valeur aux valeurs d’attribut rendues id
de ses descendants. Ce processus est abordé plus en détail à l’étape 2.
Les conteneurs d’affectation de noms modifient non seulement la valeur de l’attribut rendu id
, mais affectent également la façon dont le contrôle peut être référencé par programmation à partir de la classe code-behind de la page ASP.NET. La FindControl("controlID")
méthode est couramment utilisée pour référencer par programmation un contrôle Web. Toutefois, FindControl
ne pénètre pas dans les conteneurs d’affectation de noms. Par conséquent, vous ne pouvez pas utiliser directement la Page.FindControl
méthode pour référencer des contrôles au sein d’un gridView ou d’un autre conteneur d’affectation de noms.
Comme vous l’avez peut-être remarqué, les pages maîtres et Les ContentPlaceHolders sont tous deux implémentés comme conteneurs d’affectation de noms. Dans ce tutoriel, nous examinons comment les pages maîtres affectent les valeurs des éléments id
HTML et les façons de référencer par programmation des contrôles Web au sein d’une page de contenu à l’aide FindControl
de .
Étape 1 : Ajout d’une nouvelle page de ASP.NET
Pour illustrer les concepts abordés dans ce tutoriel, nous allons ajouter une nouvelle page ASP.NET à notre site web. Créez une page de contenu nommée IDIssues.aspx
dans le dossier racine, la liant à la Site.master
page maître.
Figure 01 : Ajouter la page IDIssues.aspx
de contenu au dossier racine
Visual Studio crée automatiquement un contrôle de contenu pour chacun des quatre ContentPlaceHolders de la page maître. Comme indiqué dans le didacticiel Multiple ContentPlaceHolders et Contenu par défaut, si un contrôle de contenu n’est pas présent, le contenu ContentPlaceHolder par défaut de la page maître est émis à la place. Étant donné que les QuickLoginUI
espaces réservés ContentPlaceHolders LeftColumnContent
contiennent un balisage par défaut approprié pour cette page, passez en avant et supprimez leurs contrôles de IDIssues.aspx
contenu correspondants. À ce stade, le balisage déclaratif de la page de contenu doit ressembler à ce qui suit :
<%@ 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>
Dans le didacticiel Spécification du titre, des balises meta et d’autres en-têtes HTML dans le didacticiel de page maître, nous avons créé une classe de page de base personnalisée (BasePage
) qui configure automatiquement le titre de la page s’il n’est pas défini explicitement. Pour que la IDIssues.aspx
page utilise cette fonctionnalité, la classe code-behind de la page doit dériver de la BasePage
classe (au lieu de System.Web.UI.Page
). Modifiez la définition de la classe code-behind pour qu’elle ressemble à ce qui suit :
Partial Class IDIssues
Inherits BasePage
End Class
Enfin, mettez à jour le Web.sitemap
fichier pour inclure une entrée pour cette nouvelle leçon. Ajoutez un <siteMapNode>
élément et définissez ses url
title
attributs sur « Control ID Naming Issues » et ~/IDIssues.aspx
, respectivement. Après avoir effectué cet ajout, le balisage de votre Web.sitemap
fichier doit ressembler à ce qui suit :
<?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>
Comme l’illustre la figure 2, la nouvelle entrée de carte de site est Web.sitemap
immédiatement reflétée dans la section Leçons de la colonne de gauche.
Figure 02 : La section Leçons inclut désormais un lien vers « Problèmes de nommage d’ID de contrôle »
Étape 2 : Examen des modifications renduesID
Pour mieux comprendre les modifications apportées par le moteur ASP.NET aux valeurs rendues id
des contrôles serveur, nous allons ajouter quelques contrôles Web à la IDIssues.aspx
page, puis afficher le balisage rendu envoyé au navigateur. Plus précisément, tapez le texte « Entrez votre âge : » suivi d’un contrôle Web TextBox. Plus loin dans la page, ajoutez un contrôle Web Button et un contrôle Label Web. Définissez respectivement les propriétés et Columns
les propriétés Age
de ID
TextBox sur 3. Définissez les propriétés et ID
les propriétés du Text
bouton sur « Envoyer » et SubmitButton
. Effacez la propriété de Text
l’étiquette et définissez-la ID
sur Results
.
À ce stade, le balisage déclaratif de votre contrôle de contenu doit ressembler à ce qui suit :
<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 figure 3 montre la page lorsqu’elle est consultée par le biais du concepteur de Visual Studio.
Figure 03 : La page comprend trois contrôles Web : un TextBox, un bouton et une étiquette (cliquez pour afficher l’image de taille complète)
Visitez la page via un navigateur, puis affichez la source HTML. Comme le montre le balisage ci-dessous, les id
valeurs des éléments HTML des contrôles TextBox, Button et Label Web sont une combinaison des ID
valeurs des contrôles Web et des ID
valeurs des conteneurs d’affectation de noms dans la page.
<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>
Comme indiqué précédemment dans ce didacticiel, la page maître et ses ContentPlaceHolders servent de conteneurs d’affectation de noms. Par conséquent, les deux contribuent aux valeurs rendues ID
de leurs contrôles imbriqués. Prenez l’attribut de id
TextBox, par exemple : ctl00_MainContent_Age
. Rappelez-vous que la valeur du ID
contrôle TextBox était Age
. Ceci est précédé de la valeur de ID
son contrôle ContentPlaceHolder. MainContent
En outre, cette valeur est précédée de la valeur de ID
la page maître. ctl00
L’effet net est une valeur d’attribut id
composée des ID
valeurs de la page maître, du contrôle ContentPlaceHolder et de la zone de texte elle-même.
La figure 4 illustre ce comportement. Pour déterminer le rendu id
de la Age
zone de texte, commencez par la ID
valeur du contrôle TextBox. Age
Ensuite, effectuez votre chemin vers la hiérarchie de contrôle. À chaque conteneur d’affectation de noms (ces nœuds avec une couleur de pêche), préfixez le rendu id
actuel avec le conteneur d’affectation de id
noms.
Figure 04 : Les attributs rendus id
sont basés sur les ID
valeurs des conteneurs d’affectation de noms
Remarque
Comme nous l’avons vu, la ctl00
partie de l’attribut rendu id
constitue la ID
valeur de la page maître, mais vous vous demandez peut-être comment cette ID
valeur est arrivée. Nous ne l’avons pas spécifié n’importe où dans notre page maître ou contenu. La plupart des contrôles serveur d’une page ASP.NET sont ajoutés explicitement par le biais du balisage déclaratif de la page. Le MainContent
contrôle ContentPlaceHolder a été explicitement spécifié dans le balisage de Site.master
; le Age
contrôle TextBox a été défini IDIssues.aspx
sur le balisage . Nous pouvons spécifier les ID
valeurs de ces types de contrôles via la Fenêtre Propriétés ou à partir de la syntaxe déclarative. D’autres contrôles, comme la page maître elle-même, ne sont pas définis dans le balisage déclaratif. Par conséquent, leurs ID
valeurs doivent être générées automatiquement pour nous. Le moteur ASP.NET définit les ID
valeurs au moment de l’exécution pour ces contrôles dont les ID n’ont pas été définis explicitement. Il utilise le modèle ctlXX
d’affectation de noms, où XX est une valeur entière en augmentation séquentielle.
Étant donné que la page maître elle-même sert de conteneur d’affectation de noms, les contrôles Web définis dans la page maître ont également modifié les valeurs d’attribut rendues id
. Par exemple, l’étiquette DisplayDate
que nous avons ajoutée à la page maître dans le didacticiel Création d’une disposition à l’échelle du site avec le didacticiel Pages maîtres comporte le balisage rendu suivant :
<span id="ctl00_DateDisplay">current date</span>
Notez que l’attribut id
inclut à la fois la valeur de ID
la page maître (ctl00
) et la ID
valeur du contrôle Web Label (DateDisplay
).
Étape 3 : Référencer par programmation des contrôles web viaFindControl
Chaque contrôle de serveur ASP.NET inclut une FindControl("controlID")
méthode qui recherche les descendants du contrôle pour un contrôle nommé controlID. Si un tel contrôle est trouvé, il est retourné ; si aucun contrôle correspondant n’est trouvé, FindControl
retourne Nothing
.
FindControl
est utile dans les scénarios où vous devez accéder à un contrôle, mais que vous n’avez pas de référence directe à celui-ci. Lorsque vous utilisez des contrôles Web de données comme GridView, par exemple, les contrôles dans les champs de GridView sont définis une fois dans la syntaxe déclarative, mais au moment de l’exécution, une instance du contrôle est créée pour chaque ligne GridView. Par conséquent, les contrôles générés au moment de l’exécution existent, mais nous n’avons pas de référence directe disponible à partir de la classe code-behind. Par conséquent, nous devons utiliser FindControl
pour travailler par programmation avec un contrôle spécifique dans les champs de GridView. (Pour plus d’informations sur l’utilisation FindControl
des contrôles dans les modèles d’un contrôle Web de données, consultez Mise en forme personnalisée basée sur les données.) Ce même scénario se produit lors de l’ajout dynamique de contrôles Web à un formulaire Web, une rubrique décrite dans Création d’interfaces utilisateur d’entrée de données dynamiques.
Pour illustrer l’utilisation de la FindControl
méthode pour rechercher des contrôles dans une page de contenu, créez un gestionnaire d’événements pour l’événement SubmitButton
« .Click
Dans le gestionnaire d’événements, ajoutez le code suivant, qui référence par programmation la Age
zone de texte et Results
l’étiquette à l’aide de la FindControl
méthode, puis affiche un message en Results
fonction de l’entrée de l’utilisateur.
Remarque
Bien sûr, nous n’avons pas besoin d’utiliser FindControl
pour référencer les contrôles Label et TextBox pour cet exemple. Nous pourrions les référencer directement via leurs ID
valeurs de propriété. J’utilise FindControl
ici pour illustrer ce qui se passe lors de l’utilisation FindControl
à partir d’une page de contenu.
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
Bien que la syntaxe utilisée pour appeler la FindControl
méthode diffère légèrement dans les deux premières lignes de SubmitButton_Click
, elles sont sémantiquement équivalentes. Rappelez-vous que tous les contrôles serveur ASP.NET incluent une FindControl
méthode. Cela inclut la Page
classe à partir de laquelle toutes les classes code-behind ASP.NET doivent dériver. Par conséquent, l’appel FindControl("controlID")
équivaut à appeler Page.FindControl("controlID")
, en supposant que vous n’avez pas remplacé la FindControl
méthode dans votre classe code-behind ou dans une classe de base personnalisée.
Après avoir entré ce code, visitez la IDIssues.aspx
page via un navigateur, entrez votre âge, puis cliquez sur le bouton « Envoyer ». Lorsque vous cliquez sur le bouton « Envoyer », un NullReferenceException
bouton est déclenché (voir la figure 5).
Figure 05 : A NullReferenceException
est déclenché (cliquez pour afficher l’image de taille complète)
Si vous définissez un point d’arrêt dans le SubmitButton_Click
gestionnaire d’événements, vous verrez que les deux appels à FindControl
retourner Nothing
. Le NullReferenceException
message est déclenché lorsque nous tentons d’accéder à la Age
propriété de Text
TextBox.
Le problème est que Control.FindControl
seules les descendants de Control se trouvent dans le même conteneur d’affectation de noms. Étant donné que la page maître constitue un nouveau conteneur d’affectation de noms, un appel pour Page.FindControl("controlID")
ne jamais perméer l’objet ctl00
de page maître . (Reportez-vous à la figure 4 pour afficher la hiérarchie de contrôles, qui affiche l’objet Page
en tant que parent de l’objet ctl00
de page maître.) Par conséquent, l’étiquette et la Results
zone de texte ne sont pas trouvées et AgeTextBox
ResultsLabel
sont affectées aux valeurs de Nothing
.Age
Il existe deux solutions de contournement à ce défi : nous pouvons explorer, un conteneur d’affectation de noms à la fois, au contrôle approprié ; ou nous pouvons créer notre propre FindControl
méthode qui imprègne les conteneurs d’affectation de noms. Examinons chacune de ces options.
Exploration dans le conteneur d’affectation de noms approprié
FindControl
Pour référencer l’étiquette ou Age
textBoxResults
, nous devons appeler FindControl
à partir d’un contrôle ancêtre dans le même conteneur d’affectation de noms. Comme le montre la figure 4, le MainContent
contrôle ContentPlaceHolder est le seul ancêtre du conteneur d’affectation de Results
noms ou Age
qui se trouve dans le même conteneur d’affectation de noms. En d’autres termes, l’appel de la FindControl
méthode à partir du MainContent
contrôle, comme illustré dans l’extrait de code ci-dessous, retourne correctement une référence aux contrôles ou Age
aux Results
contrôles.
Dim ResultsLabel As Label = CType(MainContent.FindControl("Results"), Label)
Dim AgeTextBox As TextBox = CType(MainContent.FindControl("Age"), TextBox)
Toutefois, nous ne pouvons pas utiliser ContentPlaceHolder MainContent
à partir de la classe code-behind de notre page de contenu à l’aide de la syntaxe ci-dessus, car ContentPlaceHolder est défini dans la page maître. Au lieu de cela, nous devons utiliser FindControl
pour obtenir une référence à MainContent
. Remplacez le code dans le gestionnaire d’événements SubmitButton_Click
par les modifications suivantes :
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
Si vous visitez la page via un navigateur, entrez votre âge, puis cliquez sur le bouton « Envoyer », un NullReferenceException
élément est déclenché. Si vous définissez un point d’arrêt dans le SubmitButton_Click
gestionnaire d’événements, vous verrez que cette exception se produit lors de la tentative d’appel de la méthode de l’objet MainContent
FindControl
. L’objet MainContent
est égal au Nothing
fait que la FindControl
méthode ne peut pas localiser un objet nommé « MainContent ». La raison sous-jacente est identique à celle Results
des contrôles Label et Age
TextBox : FindControl
démarre sa recherche en haut de la hiérarchie de contrôles et ne pénètre pas dans les conteneurs d’affectation de noms, mais contentPlaceHolder MainContent
se trouve dans la page maître, qui est un conteneur d’affectation de noms.
Avant de pouvoir utiliser FindControl
pour obtenir une référence MainContent
, nous avons d’abord besoin d’une référence au contrôle de page maître. Une fois que nous avons une référence à la page maître, nous pouvons obtenir une référence à ContentPlaceHolder via FindControl
et, à partir de là, des références à l’étiquette et Age
à la Results
zone de texte (à nouveau, via l’utilisationFindControl
).MainContent
Mais comment obtenir une référence à la page maître ? En inspectant les id
attributs dans le balisage rendu, il est évident que la valeur de ID
la page maître est ctl00
. Par conséquent, nous pourrions utiliser Page.FindControl("ctl00")
pour obtenir une référence à la page maître, puis utiliser cet objet pour obtenir une référence à MainContent
, et ainsi de suite. L’extrait de code suivant illustre cette logique :
'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)
Bien que ce code fonctionne certainement, il suppose que la page maître générée automatiquement ID
sera toujours ctl00
. Il n’est jamais judicieux de faire des hypothèses sur les valeurs générées automatiquement.
Heureusement, une référence à la page maître est accessible via la propriété de Master
la Page
classe. Par conséquent, au lieu d’avoir à utiliser FindControl("ctl00")
pour obtenir une référence de la page maître afin d’accéder MainContent
à ContentPlaceHolder, nous pouvons utiliser Page.Master.FindControl("MainContent")
à la place . Mettez à jour le gestionnaire d’événements SubmitButton_Click
avec le code suivant :
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
Cette fois, en accédant à la page via un navigateur, en entrant votre âge, puis en cliquant sur le bouton « Envoyer » affiche le message dans l’étiquette Results
, comme prévu.
Figure 06 : L’âge de l’utilisateur est affiché dans l’étiquette (cliquez pour afficher l’image de taille complète)
Recherche récursive via des conteneurs d’affectation de noms
La raison pour laquelle l’exemple de code précédent a référencé le MainContent
contrôle ContentPlaceHolder à partir de la page maître, puis les Results
contrôles Label et Age
TextBox à partir de MainContent
, est parce que la méthode recherche uniquement dans le Control.FindControl
conteneur d’affectation de noms du contrôle. Le fait de FindControl
rester dans le conteneur d’affectation de noms est logique dans la plupart des scénarios, car deux contrôles dans deux conteneurs d’affectation de noms différents peuvent avoir les mêmes ID
valeurs. Considérez le cas d’un GridView qui définit un contrôle Web Label nommé ProductName
dans l’un de ses TemplateFields. Lorsque les données sont liées à GridView au moment de l’exécution, une ProductName
étiquette est créée pour chaque ligne GridView. Si FindControl
vous effectuez une recherche dans tous les conteneurs d’affectation de noms et que nous avons appelé Page.FindControl("ProductName")
, quelle instance d’étiquette doit-elle FindControl
retourner ? Étiquette ProductName
dans la première ligne GridView ? Celui de la dernière ligne ?
Par conséquent, la Control.FindControl
recherche du conteneur d’affectation de noms de Control est logique dans la plupart des cas. Mais il existe d’autres cas, tels que celui qui nous fait face, où nous avons un unique ID
dans tous les conteneurs d’affectation de noms et que nous voulons éviter d’avoir à référencer méticuleusement chaque conteneur d’affectation de noms dans la hiérarchie de contrôle pour accéder à un contrôle. La présence d’une FindControl
variante qui recherche de manière récursive tous les conteneurs d’affectation de noms est également logique. Malheureusement, le .NET Framework n’inclut pas une telle méthode.
La bonne nouvelle est que nous pouvons créer notre propre FindControl
méthode qui recherche de manière récursive tous les conteneurs d’affectation de noms. En fait, à l’aide de méthodes d’extension, nous pouvons mettre en place une FindControlRecursive
méthode à la Control
classe pour accompagner sa méthode existanteFindControl
.
Remarque
Les méthodes d’extension sont une fonctionnalité nouvelle pour C# 3.0 et Visual Basic 9, qui sont les langages fournis avec .NET Framework version 3.5 et Visual Studio 2008. En bref, les méthodes d’extension permettent à un développeur de créer une méthode pour un type de classe existant via une syntaxe spéciale. Pour plus d’informations sur cette fonctionnalité utile, reportez-vous à mon article, Extension des fonctionnalités de type de base avec les méthodes d’extension.
Pour créer la méthode d’extension, ajoutez un nouveau fichier au App_Code
dossier nommé PageExtensionMethods.vb
. Ajoutez une méthode d’extension nommée FindControlRecursive
qui prend comme entrée un String
paramètre nommé controlID
. Pour que les méthodes d’extension fonctionnent correctement, il est essentiel que la classe soit marquée comme une Module
et que les méthodes d’extension soient précédées de l’attribut <Extension()>
. De plus, toutes les méthodes d’extension doivent accepter comme premier paramètre un objet du type auquel la méthode d’extension s’applique.
Ajoutez le code suivant au PageExtensionMethods.vb
fichier pour définir ceci Module
et la méthode d’extension FindControlRecursive
:
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
Avec ce code en place, revenez à la classe code-behind de la IDIssues.aspx
page et commentez les appels de méthode actuels FindControl
. Remplacez-les par des appels à Page.FindControlRecursive("controlID")
. Ce qui est clair sur les méthodes d’extension est qu’elles apparaissent directement dans les listes déroulantes IntelliSense. Comme le montre la figure 7, lorsque vous tapez Page
, puis la période d’accès, la FindControlRecursive
méthode est incluse dans la liste déroulante IntelliSense, ainsi que les autres Control
méthodes de classe.
Figure 07 : Les méthodes d’extension sont incluses dans les listes déroulantes IntelliSense (cliquez pour afficher l’image de taille complète)
Entrez le code suivant dans le SubmitButton_Click
gestionnaire d’événements, puis testez-le en accédant à la page, en entrant votre âge, puis en cliquant sur le bouton « Envoyer ». Comme le montre la figure 6, la sortie résultante sera le message « Vous avez des années d’âge ! »
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
Remarque
Étant donné que les méthodes d’extension sont nouvelles pour C# 3.0 et Visual Basic 9, si vous utilisez Visual Studio 2005, vous ne pouvez pas utiliser de méthodes d’extension. Au lieu de cela, vous devez implémenter la FindControlRecursive
méthode dans une classe d’assistance. Rick Strahl a un tel exemple dans son billet de blog, ASP.NET Maser Pages et FindControl
.
Étape 4 : Utilisation de la valeur d’attribut correcteid
dans le script côté client
Comme indiqué dans l’introduction de ce didacticiel, l’attribut rendu id
d’un contrôle Web est souvent utilisé dans le script côté client pour référencer par programmation un élément HTML particulier. Par exemple, le code JavaScript suivant fait référence à un élément HTML, id
puis affiche sa valeur dans une boîte de message modale :
var elem = document.getElementById("Age");
if (elem != null)
alert("You entered " + elem.value + " into the Age text box.");
Rappelez-vous que dans ASP.NET pages qui n’incluent pas de conteneur d’affectation de noms, l’attribut de id
l’élément HTML rendu est identique à la valeur de propriété du ID
contrôle Web. En raison de cela, il est tentant de code dur dans les valeurs d’attribut dans id
le code JavaScript. Autrement dit, si vous savez que vous souhaitez accéder au contrôle Web TextBox via un Age
script côté client, procédez ainsi via un appel à document.getElementById("Age")
.
Le problème avec cette approche est que lors de l’utilisation de pages maîtres (ou d’autres contrôles de conteneur d’affectation de noms), le code HTML id
rendu n’est pas synonyme de la propriété du ID
contrôle Web. Votre première inclinaison peut être de visiter la page via un navigateur et d’afficher la source pour déterminer l’attribut réel id
. Une fois que vous connaissez la valeur rendue id
, vous pouvez la coller dans l’appel pour accéder à getElementById
l’élément HTML avec lequel vous devez utiliser le script côté client. Cette approche est inférieure à l’idéal, car certaines modifications apportées à la hiérarchie de contrôle de la page ou les modifications apportées aux ID
propriétés des contrôles d’affectation de noms modifient l’attribut résultant id
, ce qui interrompt votre code JavaScript.
La bonne nouvelle est que la id
valeur d’attribut rendue est accessible dans le code côté serveur via la propriété du ClientID
contrôle Web. Vous devez utiliser cette propriété pour déterminer la valeur d’attribut utilisée dans le id
script côté client. Par exemple, pour ajouter une fonction JavaScript à la page qui, lorsqu’elle est appelée, affiche la valeur de la Age
zone de texte dans une boîte de message modale, ajoutez le code suivant au Page_Load
gestionnaire d’événements :
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)
Le code ci-dessus injecte la valeur de la Age
propriété de ClientID
TextBox dans l’appel JavaScript à getElementById
. Si vous visitez cette page via un navigateur et affichez la source HTML, vous trouverez le code JavaScript suivant :
<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>
Notez comment la valeur d’attribut correcte id
, , ctl00_MainContent_Age
apparaît dans l’appel à getElementById
. Étant donné que cette valeur est calculée au moment de l’exécution, elle fonctionne indépendamment des modifications ultérieures apportées à la hiérarchie des contrôles de page.
Remarque
Cet exemple JavaScript montre simplement comment ajouter une fonction JavaScript qui référence correctement l’élément HTML rendu par un contrôle serveur. Pour utiliser cette fonction, vous devez créer un code JavaScript supplémentaire pour appeler la fonction lorsque le document se charge ou quand une action utilisateur spécifique transpire. Pour plus d’informations sur ces rubriques et les rubriques connexes, consultez Utilisation du script côté client.
Résumé
Certains contrôles serveur ASP.NET agissent comme des conteneurs d’affectation de noms, ce qui affecte les id
valeurs d’attribut rendues de leurs contrôles décroissants ainsi que l’étendue des contrôles mis en forme par la FindControl
méthode. En ce qui concerne les pages maîtres, la page maître elle-même et ses contrôles ContentPlaceHolder nomment des conteneurs. Par conséquent, nous devons mettre en place un peu plus de travail pour référencer des contrôles par programmation dans la page de contenu à l’aide FindControl
. Dans ce tutoriel, nous avons examiné deux techniques : l’exploration du contrôle ContentPlaceHolder et l’appel de sa FindControl
méthode ; et la déploiement de notre propre FindControl
implémentation qui effectue des recherches récursives dans tous les conteneurs d’affectation de noms.
En plus des problèmes côté serveur qui nomment les conteneurs introduits en ce qui concerne le référencement des contrôles Web, il existe également des problèmes côté client. En l’absence de conteneurs d’affectation de noms, la valeur de propriété du ID
contrôle Web et la valeur d’attribut rendue id
sont identiques. Toutefois, avec l’ajout d’un conteneur d’affectation de noms, l’attribut rendu id
inclut à la fois les ID
valeurs du contrôle Web et les conteneurs d’affectation de noms dans l’ancêtre de sa hiérarchie de contrôle. Ces problèmes de nommage ne sont pas un problème tant que vous utilisez la propriété du ClientID
contrôle Web pour déterminer la valeur d’attribut rendue id
dans votre script côté client.
Bonne programmation !
Pour aller plus loin
Pour plus d’informations sur les sujets abordés dans ce tutoriel, consultez les ressources suivantes :
- ASP.NET pages maîtres et
FindControl
- Création d’interfaces utilisateur d’entrée de données dynamiques
- Guide pratique pour référencer ASP.NET contenu de page maître
- Pages Mater : conseils, astuces et pièges
- Utilisation du script côté client
À propos de l’auteur
Scott Mitchell, auteur de plusieurs livres ASP/ASP.NET et fondateur de 4GuysFromRolla.com, travaille avec les technologies Web Microsoft depuis 1998. Scott travaille en tant que consultant indépendant, formateur et écrivain. Son dernier livre est Sams Teach Yourself ASP.NET 3,5 en 24 heures. Scott peut être accessible à l’adresse mitchell@4GuysFromRolla.com ou via son blog à .http://ScottOnWriting.NET
Merci spécial à
Cette série de tutoriels a été examinée par de nombreux réviseurs utiles. Les réviseurs principaux de ce tutoriel étaient Zack Jones et Suchi Barnerjee. Vous souhaitez consulter mes prochains articles MSDN ? Si c’est le cas, déposez-moi une ligne à mitchell@4GuysFromRolla.com.