Partager via


Contrôler le nommage des ID dans les pages de contenu (C#)

par Scott Mitchell

Télécharger le PDF

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

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

Ajouter le IDIssues.aspx de page de contenu au dossier racine

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

La section Leçons inclut désormais un lien vers « Problèmes de nommage d’ID de contrôle »

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

La page comprend trois contrôles web : une zone de texte, un bouton et une étiquette

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

Les attributs d’id rendu sont basés sur les valeurs d’ID des conteneurs de nommage

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 ctlXXde 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 SubmitButtonde 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).

Une exception NullReferenceException est déclenchée

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

L’âge de l’utilisateur s’affiche dans l’étiquette

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.

Les méthodes d’extension sont incluses dans les listes déroulantes IntelliSense

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 correcteiddans 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 ClientIDcontrô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 :

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