Contrôler le nommage des ID dans les pages de contenu (C#)
par Scott Mitchell
Illustre la façon dont les contrôles ContentPlaceHolder servent de conteneur de noms et rendent donc difficile l’utilisation programmatique 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 qui 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 manière 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. Dans ce cas, 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 Label Web avec une ID
valeur 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 de tels scénarios, ASP.NET permet de désigner certains contrôles comme des conteneurs de nommage. Un conteneur 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éfixée avec le ID
du contrôle conteneur de nommage. Par exemple, les GridView
classes et GridViewRow
sont toutes deux des conteneurs de nommage. 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 résultantes id
sont uniques.
Notes
L’interfaceINamingContainer
est utilisée pour indiquer qu’un contrôle serveur ASP.NET particulier doit fonctionner comme un conteneur de noms. L’interface INamingContainer
n’indique pas les méthodes que le contrôle serveur doit implémenter ; elle est plutôt utilisée 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 sur les valeurs d’attribut rendues id
de ses descendants. Ce processus est décrit plus en détail à l’étape 2.
Les conteneurs 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 par le biais de conteneurs de nommage. 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 de noms.
Comme vous l’avez peut-être supposé, master pages et ContentPlaceHolders sont tous deux implémentés en tant que conteneurs de nommage. Dans ce tutoriel, nous examinons comment master pages affectent les valeurs des éléments id
HTML et comment référencer programmatiquement des contrôles web au sein d’une page de contenu à l’aide FindControl
de .
Étape 1 : Ajout d’une nouvelle page ASP.NET
Pour illustrer les concepts abordés dans ce tutoriel, ajoutons une nouvelle page ASP.NET à notre site web. Créez une page de contenu nommée IDIssues.aspx
dans le dossier racine, en la liant à la Site.master
page master.
Figure 01 : Ajouter la page IDIssues.aspx
de contenu au dossier racine
Visual Studio crée automatiquement un contrôle Content pour chacun des quatre ContentPlaceHolders de la page master. Comme indiqué dans le tutoriel ContentPlaceHolders multiples et contenu par défaut, si un contrôle Content n’est pas présent, le contenu contentPlaceHolder par défaut de la page master est émis à la place. Étant donné que les QuickLoginUI
LeftColumnContent
et ContentPlaceHolders contiennent un balisage par défaut approprié pour cette page, continuez et supprimez leurs contrôles de contenu correspondants de IDIssues.aspx
. À ce stade, le balisage déclaratif de la page de contenu doit ressembler à ce qui suit :
<%@ Page Language="C#" MasterPageFile="~/Site.master" AutoEventWireup="true" CodeFile="IDIssues.aspx.cs" Inherits="IDIssues" Title="Untitled Page" %>
<asp:Content ID="Content1" ContentPlaceHolderID="head" Runat="Server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" Runat="Server">
</asp:Content>
Dans le didacticiel Spécification du titre, des balises meta et d’autres en-têtes HTML du master Page , 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 :
public partial class IDIssues : BasePage
{
}
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 title
attributs et url
sur « Problèmes de nommage d’ID de contrôle » 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 plan de site dans Web.sitemap
est 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 « Veuillez entrer 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 les propriétés et textbox ID
Columns
sur Age
et 3, respectivement. Définissez les propriétés et ID
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 via le concepteur de Visual Studio.
Figure 03 : La page comprend trois contrôles web : une zone de texte, un bouton et une étiquette (cliquer pour afficher une image en taille réelle)
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 pour les contrôles TextBox, Button et Label Web sont une combinaison des valeurs des ID
contrôles Web et ID
des valeurs des conteneurs de nommage 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 tutoriel, la page master et ses ContentPlaceHolders servent de conteneurs de nommage. Par conséquent, les deux contribuent aux valeurs rendues ID
de leurs contrôles imbriqués. Prenez l’attribut TextBoxid
, pour instance : ctl00_MainContent_Age
. Rappelez-vous que la valeur du ID
contrôle TextBox était Age
. Il 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 master, ctl00
. L’effet net est une valeur d’attribut id
composée des ID
valeurs de la page master, du contrôle ContentPlaceHolder et du TextBox lui-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, accédez à la hiérarchie de contrôle. À chaque conteneur de nommage (ces nœuds avec une couleur pêche), préfixez le rendu id
actuel avec le nommage du conteneur d’affectation de id
noms.
Figure 04 : Les attributs rendus id
sont basés sur les ID
valeurs des conteneurs de nommage
Notes
Comme nous l’avons vu, la ctl00
partie de l’attribut rendu id
constitue la ID
valeur de la page master, mais vous vous demandez peut-être comment cette ID
valeur est arrivée. Nous ne l’avons pas spécifié nulle part dans notre page de master ou de contenu. La plupart des contrôles serveur d’une page ASP.NET sont ajoutés explicitement via le balisage déclaratif de la page. Le MainContent
contrôle ContentPlaceHolder a été explicitement spécifié dans le balisage de Site.master
; le Age
balisage TextBox a été défini IDIssues.aspx
. Nous pouvons spécifier les ID
valeurs de ces types de contrôles via le Fenêtre Propriétés ou à partir de la syntaxe déclarative. D’autres contrôles, comme la page master 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 valeurs au moment de l’exécution ID
pour les contrôles dont les ID n’ont pas été définis explicitement. Il utilise le modèle ctlXX
de nommage , où XX est une valeur entière qui augmente séquentiellement.
Étant donné que la page master sert elle-même de conteneur de noms, les contrôles Web définis dans la page master ont également modifié les valeurs d’attribut renduesid
. Par exemple, l’étiquette DisplayDate
que nous avons ajoutée à la page master dans le didacticiel Création d’une disposition Site-Wide avec des pages maîtres présente 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 master (ctl00
) et la ID
valeur du contrôle Label Web (DateDisplay
).
Étape 3 : Référencement programmatique de contrôles web viaFindControl
Chaque contrôle serveur ASP.NET inclut une FindControl("controlID")
méthode qui recherche un contrôle nommé controlID dans les descendants du contrôle. Si un tel contrôle est trouvé, il est retourné ; si aucun contrôle correspondant n’est trouvé, FindControl
retourne null
.
FindControl
est utile dans les scénarios où vous devez accéder à un contrôle, mais où vous n’avez pas de référence directe à celui-ci. Lors de l’utilisation de contrôles Web de données tels que 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
pour accéder aux 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, rubrique abordée 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
de Click
. Dans le gestionnaire d’événements, ajoutez le code suivant, qui fait référence par programmation aux Age
éléments TextBox et Results
Label à l’aide de la FindControl
méthode , puis affiche un message dans en Results
fonction de l’entrée de l’utilisateur.
Notes
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 pouvons les référencer directement via leurs ID
valeurs de propriété. Je l’utilise FindControl
ici pour illustrer ce qui se passe lors de l’utilisation FindControl
à partir d’une page de contenu.
protected void SubmitButton_Click(object sender, EventArgs e)
{
Label ResultsLabel = FindControl("Results") as Label;
TextBox AgeTextBox = Page.FindControl("Age") as TextBox;
ResultsLabel.Text = string.Format("You are {0} years old!", AgeTextBox.Text);
}
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, appeler 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, accédez à la IDIssues.aspx
page via un navigateur, entrez votre âge, puis cliquez sur le bouton « Envoyer ». Lorsque vous cliquez sur le bouton « Envoyer », un message NullReferenceException
est déclenché (voir la figure 5).
Figure 05 : A NullReferenceException
est déclenché (cliquer pour afficher l’image en taille réelle)
Si vous définissez un point d’arrêt dans le SubmitButton_Click
gestionnaire d’événements, vous verrez que les deux appels pour FindControl
retourner une null
valeur. Le NullReferenceException
est déclenché lorsque nous tentons d’accéder à la Age
propriété de Text
TextBox.
Le problème est que Control.FindControl
recherche uniquement les descendants de Control qui se trouvent dans le même conteneur d’affectation de noms. Étant donné que la page master constitue un nouveau conteneur d’affectation de noms, un appel à Page.FindControl("controlID")
n’imprègne jamais l’objet ctl00
de page master . (Reportez-vous à la figure 4 pour afficher la hiérarchie de contrôle, qui montre l’objet Page
en tant que parent de l’objet ctl00
de page master .) Par conséquent, les Results
valeurs Label et Age
TextBox sont introuvables et ResultsLabel
et se AgeTextBox
voient attribuer des valeurs de null
.
Il existe deux solutions de contournement à ce défi : nous pouvons explorer, un conteneur de noms à la fois, jusqu’au contrôle approprié ; ou nous pouvons créer notre propre FindControl
méthode qui imprègne les conteneurs de nommage. Examinons chacune de ces options.
Exploration dans le conteneur d’affectation de noms approprié
Pour utiliser 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 de Results
ou Age
qui se trouve dans le même conteneur de noms. En d’autres termes, l’appel de la FindControl
méthode à partir du MainContent
contrôle, comme indiqué dans l’extrait de code ci-dessous, retourne correctement une référence aux Results
contrôles ou Age
.
Label ResultsLabel = MainContent.FindControl("Results") as Label;
TextBox AgeTextBox = MainContent.FindControl("Age") as TextBox;
Toutefois, nous ne pouvons pas utiliser le ContentPlaceHolder de la MainContent
classe code-behind de notre page de contenu à l’aide de la syntaxe ci-dessus, car le ContentPlaceHolder est défini dans la page master. Au lieu de cela, nous devons utiliser FindControl
pour obtenir une référence à MainContent
. Remplacez le code dans le SubmitButton_Click
gestionnaire d’événements par les modifications suivantes :
protected void SubmitButton_Click(object sender, EventArgs e)
{
ContentPlaceHolder MainContent = FindControl("MainContent") as ContentPlaceHolder;
Label ResultsLabel = MainContent.FindControl("Results") as Label;
TextBox AgeTextBox = MainContent.FindControl("Age") as TextBox;
ResultsLabel.Text = string.Format("You are {0} years old!", AgeTextBox.Text);
}
Si vous visitez la page par le biais d’un navigateur, entrez votre âge, puis cliquez sur le bouton « Envoyer », une NullReferenceException
valeur est déclenchée. 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 FindControl
l’objetMainContent
. L’objet MainContent
est null
dû au fait que la FindControl
méthode ne peut pas localiser un objet nommé « MainContent ». La raison sous-jacente est la même que pour les Results
contrôles Label et Age
TextBox : FindControl
démarre sa recherche à partir du haut de la hiérarchie de contrôles et ne pénètre pas les conteneurs de noms, mais le MainContent
ContentPlaceHolder se trouve dans la page master, qui est un conteneur 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 master. Une fois que nous avons une référence à la page master, nous pouvons obtenir une référence à MainContent
ContentPlaceHolder via FindControl
et, à partir de là, des références à Label Results
et Age
TextBox (à nouveau, en utilisant FindControl
). Mais comment obtenir une référence à la page master ? En inspectant les id
attributs dans le balisage rendu, il est évident que la valeur de ID
la page master est ctl00
. Par conséquent, nous pouvons utiliser Page.FindControl("ctl00")
pour obtenir une référence à la page master, 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
MasterPage ctl00 = FindControl("ctl00") as MasterPage;
// Get a reference to the ContentPlaceHolder
ContentPlaceHolder MainContent = ctl00.FindControl("MainContent") as ContentPlaceHolder;
// Reference the Label and TextBox controls
Label ResultsLabel = MainContent.FindControl("Results") as Label;
TextBox AgeTextBox = MainContent.FindControl("Age") as TextBox;
Bien que ce code fonctionne certainement, il part du principe que le master page généré 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 master 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 master afin d’accéder au ContentPlaceHolder, nous pouvons utiliser Page.Master.FindControl("MainContent")
à la MainContent
place . Mettez à jour le SubmitButton_Click
gestionnaire d’événements avec le code suivant :
protected void SubmitButton_Click(object sender, EventArgs e)
{
ContentPlaceHolder MainContent = Page.Master.FindControl("MainContent") as ContentPlaceHolder;
Label ResultsLabel = MainContent.FindControl("Results") as Label;
TextBox AgeTextBox = MainContent.FindControl("Age") as TextBox;
ResultsLabel.Text = string.Format("You are {0} years old!", AgeTextBox.Text);
}
Cette fois, la visite de la page par le biais d’un navigateur, l’entrée de votre âge et le fait de cliquer 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 (cliquer pour afficher l’image en taille réelle)
Recherche récursive via des conteneurs de nommage
La raison pour laquelle l’exemple de code précédent a référencé le MainContent
contrôle ContentPlaceHolder à partir de la page master, puis les Results
contrôles Label et Age
TextBox de MainContent
, est que la méthode recherche uniquement dans le Control.FindControl
conteneur d’affectation de noms de Control. 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. Prenons le cas d’un GridView qui définit un contrôle Label Web 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 recherchez tous les conteneurs de noms et que nous avons appelé Page.FindControl("ProductName")
, quel label instance doit-il FindControl
retourner ? L’étiquette ProductName
dans la première ligne GridView ? Celui de la dernière ligne ?
Control.FindControl
Il est donc logique de rechercher uniquement le conteneur d’affectation de noms de Control dans la plupart des cas. Mais il existe d’autres cas, comme celui auquel nous sommes confrontés, où nous avons un unique ID
sur tous les conteneurs de nommage 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. Il est également judicieux d’avoir une FindControl
variante qui recherche de manière récursive tous les conteneurs d’affectation de noms. 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 de nommage. En fait, à l’aide de méthodes d’extension , nous pouvons utiliser une FindControlRecursive
méthode à la Control
classe pour accompagner sa méthode existante FindControl
.
Notes
Les méthodes d’extension sont une nouvelle fonctionnalité de 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, consultez mon article Extension des fonctionnalités de type de base avec des méthodes d’extension.
Pour créer la méthode d’extension, ajoutez un nouveau fichier au App_Code
dossier nommé PageExtensionMethods.cs
. 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 elle-même et ses méthodes d’extension soient marquées static
. En outre, toutes les méthodes d’extension doivent accepter comme premier paramètre un objet du type auquel la méthode d’extension s’applique, et ce paramètre d’entrée doit être précédé de la mot clé this
.
Ajoutez le code suivant au PageExtensionMethods.cs
fichier de classe pour définir cette classe et la méthode d’extension FindControlRecursive
:
using System;
using System.Web;
using System.Web.UI;
public static class PageExtensionMethods
{
public static Control FindControlRecursive(this Control ctrl, string controlID)
{
if (string.Compare(ctrl.ID, controlID, true) == 0)
{
// We found the control!
return ctrl;
}
else
{
// Recurse through ctrl's Controls collections
foreach (Control child in ctrl.Controls)
{
Control lookFor = FindControlRecursive(child, controlID);
if (lookFor != null)
return lookFor; // We found the control
}
// If we reach here, control was not found
return null;
}
}
}
Une fois 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 soigné avec les méthodes d’extension, c’est qu’elles apparaissent directement dans les listes déroulantes IntelliSense. Comme le montre la figure 7, lorsque vous tapez Page, puis période d’accès, la FindControlRecursive
méthode est incluse dans la liste déroulante IntelliSense avec les autres Control
méthodes de classe.
Figure 07 : Les méthodes d’extension sont incluses dans la Drop-Downs IntelliSense (cliquez pour afficher l’image en taille réelle)
Entrez le code suivant dans le SubmitButton_Click
gestionnaire d’événements, puis testez-le en visitant la page, en entrant votre âge et en cliquant sur le bouton « Envoyer ». Comme illustré dans la figure 6, la sortie résultante sera le message « Vous avez des années d’âge ! »
protected void SubmitButton_Click(object sender, EventArgs e)
{
Label ResultsLabel = Page.FindControlRecursive("Results") as Label;
TextBox AgeTextBox = Page.FindControlRecursive("Age") as TextBox;
ResultsLabel.Text = string.Format("You are {0} years old!", AgeTextBox.Text);
}
Notes
Étant donné que les méthodes d’extension sont nouvelles dans 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 Client-Side script
Comme indiqué dans l’introduction de ce tutoriel, 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 référence un élément HTML par son 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 de noms, l’attribut de id
l’élément HTML rendu est identique à la valeur de propriété du ID
contrôle Web. Pour cette raison, il est tentant de coder en dur des valeurs d’attribut dans id
du code JavaScript. Autrement dit, si vous savez que vous souhaitez accéder au Age
contrôle Web TextBox via un script côté client, faites-le via un appel à document.getElementById("Age")
.
Le problème avec cette approche est que lors de l’utilisation de pages master (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 tendance 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 à getElementById
pour accéder à l’élément HTML que vous devez utiliser via un script côté client. Cette approche n’est pas idéale, car certaines modifications apportées à la hiérarchie de contrôle de la page ou aux ID
propriétés des contrôles d’affectation de noms modifient l’attribut résultant id
, ce qui casse 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 id
utilisée dans le script côté client. Par exemple, pour ajouter une fonction JavaScript à la page qui, lorsqu’elle est appelée, affiche la valeur de textBox Age
dans une zone de message modale, ajoutez le code suivant au gestionnaire d’événements Page_Load
:
ClientScript.RegisterClientScriptBlock(this.GetType(), "ShowAgeTextBoxScript",
string.Format(@"function ShowAge()
{{
var elem = document.getElementById('{0}');
if (elem != null)
alert('You entered ' + elem.value + ' into the Age text box.');
}}", AgeTextBox.ClientID), true);
Le code ci-dessus injecte la valeur de la Age
propriété ClientID de 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 quelles que soient les modifications apportées ultérieurement à la hiérarchie de contrôle de page.
Notes
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 lorsqu’une action utilisateur spécifique se produit. Pour plus d’informations sur ces rubriques et sur les rubriques connexes, consultez Utilisation du script Client-Side.
Résumé
Certains contrôles serveur ASP.NET agissent comme des conteneurs de nommage, ce qui affecte les valeurs d’attribut rendues id
de leurs contrôles descendants ainsi que l’étendue des contrôles canevasés par la FindControl
méthode. En ce qui concerne les pages master, la page master elle-même et ses contrôles ContentPlaceHolder nomment des conteneurs. Par conséquent, nous devons mettre en avant un peu plus de travail pour référencer les contrôles par programmation dans la page de contenu à l’aide de FindControl
. Dans ce tutoriel, nous avons examiné deux techniques : exploration du contrôle ContentPlaceHolder et appel de sa FindControl
méthode ; et déploiement de notre propre FindControl
implémentation qui recherche de manière récursive tous les conteneurs de nommage.
Outre les problèmes de nommage côté serveur 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 de nommage, la valeur de propriété du ID
contrôle Web et la valeur de l’attribut rendu id
sont identiques. Toutefois, avec l’ajout d’un conteneur de noms, l’attribut rendu id
inclut à la fois les ID
valeurs du contrôle Web et les conteneurs de nommage 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 de l’attribut rendu id
dans votre script côté client.
Bonne programmation !
En savoir plus
Pour plus d’informations sur les sujets abordés dans ce tutoriel, reportez-vous aux 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 la page maître
- Pages Mater : trucs, astuces et pièges
- Utilisation du script Client-Side
À 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 comme consultant indépendant, formateur et écrivain. Son dernier livre est Sams Teach Yourself ASP.NET 3.5 in 24 Heures. Scott peut être contacté à mitchell@4GuysFromRolla.com ou via son blog à l’adresse http://ScottOnWriting.NET.
Un merci spécial à
Cette série de tutoriels a été examinée par de nombreux réviseurs utiles. Les principaux réviseurs 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.