Sdílet prostřednictvím


Pojmenovávání ID ovládacích prvků na stránkách obsahu (C#)

Scott Mitchell

Stáhnout PDF

Ukazuje, jak ovládací prvky ContentPlaceHolder slouží jako názvový kontejner, a proto ztěžují programovou práci s ovládacím prvku (prostřednictvím FindControl). Řeší tento problém a alternativní řešení. Také popisuje, jak programově získat přístup k výsledné hodnotě ClientID.

Úvod

Všechny ASP.NET serverové ID ovládací prvky obsahují vlastnost, která jednoznačně identifikuje ovládací prvek a je prostředkem, pomocí kterého je ovládací prvek programově přístupný ve třídě kódu na pozadí. Podobně elementy v dokumentu HTML mohou obsahovat id atribut, který prvek jednoznačně identifikuje; tyto id hodnoty se často používají ve skriptu na straně klienta k programovému odkazu na konkrétní element HTML. Vzhledem k tomu můžete předpokládat, že při vykreslení serverového ovládacího prvku ASP.NET do html se jeho ID hodnota použije jako id hodnota vykreslovaného elementu HTML. Nemusí tomu tak nutně být, protože za určitých okolností se jeden ovládací prvek s jednou ID hodnotou může ve vykreslené značce objevit vícekrát. Zvažte GridView ovládací prvek, který obsahuje TemplateField s Label Web ovládací prvek ID s hodnotou ProductName. Když GridView je vázán na zdroj dat za běhu, tento popisek se opakuje jednou pro každý řádek GridView. Každý vykreslený popisek potřebuje jedinečnou id hodnotu.

Aby bylo možné takové scénáře zpracovat, ASP.NET umožňuje, aby se určité ovládací prvky označovaly jako kontejnery pojmenování. Kontejner pojmenování slouží jako nový ID obor názvů. Všechny serverové ovládací prvky, které se zobrazí v názvovém kontejneru, mají vykreslenou id hodnotu s ID předponou ovládacího prvku názvového kontejneru. Například GridView třídy a GridViewRow jsou obě kontejnery pojmenování. V důsledku toho se ovládacímu prvku Label definovanému v GridView TemplateField s ID ProductName přidělí vykreslená id hodnota GridViewID_GridViewRowID_ProductName. Vzhledem k tomu , GridViewRowID je jedinečný pro každý řádek GridView, výsledné id hodnoty jsou jedinečné.

Poznámka

RozhraníINamingContainer slouží k označení, že určitý ASP.NET serverový ovládací prvek by měl fungovat jako kontejner názvů. Rozhraní INamingContainer nevytáčí žádné metody, které musí serverový ovládací prvek implementovat, ale používá se jako značka. Při generování vykresleného kódu, pokud ovládací prvek implementuje toto rozhraní, modul ASP.NET automaticky předponu své ID hodnoty před hodnoty vykreslených id atributů jeho potomků. Tento proces je podrobněji popsán v kroku 2.

Kontejnery pojmenování nejen mění hodnotu vykresleného id atributu, ale také ovlivňují způsob, jakým lze na ovládací prvek programově odkazovat z třídy kódu na pozadí ASP.NET stránky. Metoda se FindControl("controlID") běžně používá k programovému odkazu na webový ovládací prvek. FindControl Nepronikne však přes názvové kontejnery. V důsledku toho nelze přímo použít metodu Page.FindControl k odkazování na ovládací prvky v rámci GridView nebo jiného kontejneru pojmenování.

Jak jste se mohli zdát, stránky předlohy a ContentPlaceHolders se implementují jako kontejnery pojmenování. V tomto kurzu prozkoumáme, jak stránky předlohy ovlivňují hodnoty elementů id HTML, a způsoby, jak programově odkazovat na webové ovládací prvky v rámci stránky obsahu pomocí FindControl.

Krok 1: Přidání nové stránky ASP.NET

Abychom si ukázali koncepty probírané v tomto kurzu, přidáme na náš web novou stránku ASP.NET. V kořenové složce vytvořte novou stránku obsahu s názvem IDIssues.aspx a vytvořte ji vazbu se stránkou Site.master předlohy.

Přidání IDIssues.aspx stránky obsahu do kořenové složky

Obrázek 01: Přidání stránky IDIssues.aspx obsahu do kořenové složky

Visual Studio automaticky vytvoří ovládací prvek obsahu pro každý ze čtyř ContentPlaceHolders stránky předlohy. Jak je uvedeno v kurzu Multiple ContentPlaceHolders a Výchozí obsah , pokud ovládací prvek Obsahu není k dispozici, bude místo toho generován výchozí obsah ContentPlaceHolder stránky předlohy. Protože objekty QuickLoginUI a LeftColumnContent ContentPlaceHolders obsahují vhodné výchozí značky pro tuto stránku, odeberte jejich odpovídající ovládací prvky Obsahu z IDIssues.aspx. V tomto okamžiku by deklarativní kód stránky obsahu měl vypadat takto:

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

V kurzu Určení názvu, metaznačky a dalších hlaviček HTML v rámci stránky předlohy jsme vytvořili vlastní základní třídu stránky (BasePage), která automaticky konfiguruje název stránky, pokud není explicitně nastavený. IDIssues.aspx Aby stránka tuto funkci využívala, třída kódu na pozadí stránky musí být odvozena z BasePage třídy (místo z System.Web.UI.Page). Upravte definici třídy kódu na pozadí tak, aby vypadala takto:

public partial class IDIssues : BasePage
{
}

Nakonec soubor aktualizujte Web.sitemap tak, aby obsahoval položku pro tuto novou lekci. <siteMapNode> Přidejte element a nastavte jeho title atributy a url na "Problémy s pojmenováním ID ovládacího prvku" a ~/IDIssues.aspx, v uvedeném pořadí. Po tomto přidání Web.sitemap by měl kód souboru vypadat nějak takto:

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

Jak znázorňuje obrázek 2, nová položka mapy webu v souboru Web.sitemap se okamžitě projeví v oddílu Lekce v levém sloupci.

Oddíl Lekce teď obsahuje odkaz na problémy s pojmenováním ID ovládacího prvku.

Obrázek 02: Oddíl lekce teď obsahuje odkaz na problémy s pojmenováním ID ovládacího prvku

Krok 2: Prozkoumání vykreslenýchIDzměn

Abychom lépe porozuměli změnám, které modul ASP.NET provádí ve vykreslených id hodnotách serverových ovládacích prvků, přidáme na IDIssues.aspx stránku několik webových ovládacích prvků a pak zobrazíme vykreslené značky odeslané do prohlížeče. Konkrétně zadejte text "Please enter your age:" (Zadejte prosím svůj věk) a potom ovládací prvek TextBox Web. Dále na stránce přidejte webový ovládací prvek Tlačítko a ovládací prvek Label Web. Nastavte vlastnosti TextBox ID a Columns na Age hodnotu a 3. Nastavte vlastnosti a ID tlačítka Text na "Submit" a SubmitButton. Vymažte vlastnost Label Text a nastavte ji ID na Results.

V tomto okamžiku by deklarativní kód ovládacího prvku Obsahu měl vypadat nějak takto:

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

Obrázek 3 znázorňuje stránku při zobrazení prostřednictvím návrháře sady Visual Studio.

Stránka obsahuje tři webové ovládací prvky: textové pole, tlačítko a popisek.

Obrázek 03: Stránka obsahuje tři webové ovládací prvky: Textové pole, tlačítko a popisek (kliknutím zobrazíte obrázek v plné velikosti).

Přejděte na stránku v prohlížeči a pak zobrazte zdroj HTML. Jak ukazuje níže uvedený kód, id hodnoty elementů HTML pro ovládací prvky TextBox, Button a Label Web jsou kombinací hodnot webových ID ovládacích prvků a ID hodnot názvových kontejnerů na stránce.

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

Jak bylo uvedeno dříve v tomto kurzu, stránka předlohy i její ContentPlaceHolders slouží jako kontejnery pojmenování. V důsledku toho oba přispívají vykreslenými ID hodnotami svých vnořených ovládacích prvků. Vezměte atribut TextBox id , například: ctl00_MainContent_Age. Vzpomeňte si, že hodnota ovládacího prvku ID TextBox byla Age. Má předponu s hodnotou ovládacího prvku ID ContentPlaceHolder . MainContent Kromě toho má tato hodnota předponu s hodnotou stránky ID předlohy ctl00. Efekt net je id hodnota atributu ID , která se skládá z hodnot stránky předlohy, ContentPlaceHolder ovládací prvek a TextBox sám.

Toto chování znázorňuje obrázek 4. Pokud chcete určit vykreslení idAge TextBox, začněte ID hodnotou ovládacího prvku TextBox . Age V dalším kroku se propracovávejte v hierarchii ovládacích prvků směrem nahoru. U každého názvového kontejneru (uzly s brosví) předponu aktuální vykreslené id kontejneru názvového idkontejneru .

Vykreslené atributy ID jsou založené na hodnotách ID pojmenování kontejnerů.

Obrázek 04: Vykreslené id atributy jsou založené na ID hodnotách pojmenování kontejnerů.

Poznámka

Jak jsme probrali, ctl00 část vykresleného id atributu představuje hodnotu stránky předlohy ID , ale možná vás zajímá, jak tato ID hodnota vznikla. Neurčili jsme ho nikde na stránce předlohy nebo obsahu. Většina serverových ovládacích prvků na ASP.NET stránce se přidává explicitně prostřednictvím deklarativního kódu stránky. Ovládací MainContent prvek ContentPlaceHolder byl explicitně zadán ve značce Site.master; Age TextBox byl definován IDIssues.aspxznačky . Hodnoty pro tyto typy ovládacích prvků můžeme zadat ID prostřednictvím okno Vlastnosti nebo z deklarativní syntaxe. Jiné ovládací prvky, například samotná stránka předlohy, nejsou definovány v deklarativním kódu. V důsledku toho musí být jejich ID hodnoty automaticky generovány pro nás. Modul ASP.NET nastaví ID za běhu hodnoty pro ty ovládací prvky, jejichž ID nebyla explicitně nastavena. Používá model ctlXXpojmenování , kde XX je sekvenčně rostoucí celočíselná hodnota.

Vzhledem k tomu, že samotná stránka předlohy slouží jako kontejner názvů, mají webové ovládací prvky definované na stránce předlohy také změněné vykreslené id hodnoty atributů. Například popisek, který DisplayDate jsme přidali na stránku předlohy v kurzu Vytvoření rozložení Site-Wide se stránkami předlohy , obsahuje následující vykreslené značky:

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

Všimněte si id , že atribut zahrnuje hodnotu stránky předlohy ID (ctl00) i ID hodnotu ovládacího prvku Label Web (DateDisplay).

Krok 3: Odkazování na webové ovládací prvky prostřednictvím kódu programuFindControl

Každý ASP.NET serverový ovládací prvek obsahuje metodu FindControl("controlID") , která hledá v descendentech ovládacího prvku s názvem controlID. Pokud je takový ovládací prvek nalezen, je vrácen; Pokud není nalezen žádný odpovídající ovládací prvek, FindControl vrátí .null

FindControl je užitečná ve scénářích, kdy potřebujete získat přístup k ovládacímu prvku, ale nemáte na něj přímý odkaz. Při práci s webovými ovládacími prvky dat, jako je GridView, například ovládací prvky v polích GridView jsou definovány jednou v deklarativní syntaxi, ale za běhu je vytvořena instance ovládacího prvku pro každý gridView řádek. V důsledku toho existují ovládací prvky generované za běhu, ale nemáme k dispozici přímý odkaz z třídy kódu na pozadí. V důsledku toho musíme použít FindControl programovou práci s konkrétním ovládacím prvku v polích GridView. (Další informace o použití FindControl pro přístup k ovládacím prvkům v šablonách webového ovládacího prvku dat najdete v tématu Vlastní formátování založené na datech.) K tomuto stejnému scénáři dochází při dynamickém přidávání webových ovládacích prvků do webového formuláře, což je téma popsané v tématu Vytváření uživatelských rozhraní dynamického zadávání dat.

Pro ilustraci FindControl použití metody k hledání ovládacích prvků na stránce obsahu vytvořte obslužnou rutinu SubmitButtonClick události pro událost . Do obslužné rutiny události přidejte následující kód, který programově odkazuje na Age TextBox a Results Label pomocí FindControl metody a pak zobrazí zprávu v Results na základě vstupu uživatele.

Poznámka

V tomto příkladu samozřejmě nemusíme odkazovat FindControl na ovládací prvky Label a TextBox. Mohli bychom na ně odkazovat přímo prostřednictvím jejich ID hodnot vlastností. Tady se používám FindControl k ilustraci toho, co se stane při použití FindControl ze stránky obsahu.

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);
}

I když se syntaxe použitá k volání FindControl metody mírně liší v prvních dvou řádcích , SubmitButton_Clickjsou sémanticky ekvivalentní. Vzpomeňte si, že všechny ovládací prvky ASP.NET serveru zahrnují metodu FindControl . To zahrnuje Page třídu, ze které musí být odvozeny všechny ASP.NET třídy kódu na pozadí. Proto je volání FindControl("controlID") ekvivalentní volání Page.FindControl("controlID"), za předpokladu, že jste nepřepsali metodu FindControl ve třídě kódu na pozadí nebo ve vlastní základní třídě.

Po zadání tohoto kódu navštivte IDIssues.aspx stránku v prohlížeči, zadejte svůj věk a klikněte na tlačítko Odeslat. Po kliknutí na tlačítko NullReferenceException Odeslat se vyvolá hodnota (viz Obrázek 5).

Výjimka NullReferenceException je vyvolána.

Obrázek 05: A NullReferenceException je vyvolaný (kliknutím zobrazíte obrázek v plné velikosti)

Pokud nastavíte zarážku v obslužné rutině SubmitButton_Click události, uvidíte, že obě volání FindControl vrátí null hodnotu. Vyvolá NullReferenceException se při pokusu Age o přístup k vlastnosti TextBox Text .

Problém je v tom, že Control.FindControl prohledává pouze potomky ovládacího prvku, které jsou ve stejném kontejneru pojmenování. Vzhledem k tomu, že stránka předlohy představuje nový kontejner názvů, volání nikdy Page.FindControl("controlID") neprostupuje objekt ctl00stránky předlohy . (Vraťte se na obrázek 4 a zobrazte hierarchii ovládacích prvků, která zobrazuje Page objekt jako nadřazený objekt ctl00stránky předlohy.) Results Proto se hodnoty Label a Age TextBox nenašly a ResultsLabelAgeTextBox jsou jim přiřazeny nullhodnoty .

Existují dvě alternativní řešení této výzvy: můžeme přejít k podrobnostem, jeden kontejner pojmenování po druhém, k příslušnému ovládacímu prvku; nebo můžeme vytvořit vlastní FindControl metodu, která prostupuje kontejnery názvů. Pojďme se podívat na každou z těchto možností.

Přechod k příslušnému kontejneru názvů

Abychom mohli odkazovat FindControl na Results Label nebo Age TextBox, musíme volat FindControl z nadřazeného ovládacího prvku ve stejném kontejneru názvů. Jak ukazuje obrázek 4, MainContent ovládací prvek ContentPlaceHolder je jediným nadřazeným objektem Results nebo Age , který je ve stejném kontejneru pojmenování. Jinými slovy, volání metody z MainContent ovládacího prvku, jak je znázorněno v následujícím fragmentu kódu, správně vrátí odkaz na Results ovládací prvky neboAge.FindControl

Label ResultsLabel = MainContent.FindControl("Results") as Label;
TextBox AgeTextBox = MainContent.FindControl("Age") as TextBox;

Nemůžeme však pracovat s MainContent ContentPlaceHolder z naší třídy kódu na pozadí stránky obsahu pomocí výše uvedené syntaxe, protože ContentPlaceHolder je definován na stránce předlohy. Místo toho musíme použít FindControl k získání odkazu na MainContent. Nahraďte kód v obslužné rutině SubmitButton_Click události následujícími úpravami:

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);
}

Pokud stránku navštívíte prostřednictvím prohlížeče, zadejte svůj věk a klikněte na tlačítko Odeslat, NullReferenceException zobrazí se vyvolání. Pokud nastavíte zarážku v obslužné rutině SubmitButton_Click události, uvidíte, že k této výjimce dochází při pokusu o volání metody objektu MainContentFindControl . Objekt MainContent je null ten, FindControl že metoda nemůže najít objekt s názvem "MainContent". Základní důvod je stejný jako u Results ovládacích prvků Label a Age TextBox: FindControl zahájí vyhledávání od horní části hierarchie ovládacích prvků a nepronikne do kontejnerů názvů, ale MainContent ContentPlaceHolder je v rámci stránky předlohy, což je kontejner názvů.

Než budeme moct použít FindControl k získání odkazu na MainContent, potřebujeme nejprve odkaz na ovládací prvek stránky předlohy. Jakmile budeme mít odkaz na stránku předlohy, můžeme získat odkaz na MainContent ContentPlaceHolder prostřednictvím FindControl a odtud odkazy na Results Label a Age TextBox (opět pomocí ).FindControl Ale jak získáme odkaz na stránku předlohy? Při kontrole id atributů v vykreslené značek je zřejmé, že hodnota stránky ID předlohy je ctl00. Proto bychom mohli použít Page.FindControl("ctl00") k získání odkazu na stránku předlohy, pak tento objekt použít k získání odkazu na MainContentatd. Následující fragment kódu znázorňuje tuto logiku:

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

I když tento kód bude určitě fungovat, předpokládá se, že automaticky vygenerovaná ID stránka předlohy bude ctl00vždy . Nikdy není vhodné vytvářet předpoklady o automaticky vygenerovaných hodnotách.

Odkaz na stránku předlohy je naštěstí přístupný prostřednictvím Page vlastnosti třídy Master . Proto místo FindControl("ctl00") použití k získání odkazu na stránku předlohy pro přístup MainContent k ContentPlaceHolder, můžeme místo toho použít Page.Master.FindControl("MainContent"). Aktualizujte obslužnou rutinu SubmitButton_Click události následujícím kódem:

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);
}

Tentokrát navštívíte stránku v prohlížeči, zadáte svůj věk a kliknete na tlačítko Odeslat, zobrazí se zpráva v popisku Results podle očekávání.

V popisku se zobrazí věk uživatele.

Obrázek 06: V popisku se zobrazí věk uživatele (kliknutím zobrazíte obrázek v plné velikosti)

Rekurzivní vyhledávání v kontejnerech pro vytváření názvů

Důvod, proč předchozí příklad kódu odkazoval na MainContent ovládací prvek ContentPlaceHolder ze stránky předlohy a pak Results na ovládací prvky Label a Age TextBox z MainContent, je to, že Control.FindControl metoda hledá pouze v názvovém kontejneru ovládacího prvku. Zůstat FindControl v kontejneru názvů dává ve většině scénářů smysl, protože dva ovládací prvky ve dvou různých kontejnerech pojmenování můžou mít stejné ID hodnoty. Vezměte v úvahu případ GridView, který definuje popisek webového ovládacího prvku s názvem ProductName v jednom z jeho TemplateFields. Když jsou data svázaná s objektem GridView za běhu, ProductName vytvoří se popisek pro každý řádek GridView. Pokud FindControl jsme prohledali všechny kontejnery názvů a volali Page.FindControl("ProductName")jsme , jakou instanci Label by měla FindControl vrátit? Popisek ProductName v prvním řádku GridView? Ten v poslední řadě?

Takže hledání Control.FindControl jen názvových kontejnerů v Controlu dává ve většině případů smysl. Existují ale i jiné případy, například ten, který se nachází před námi, kdy máme ve všech názvových kontejnerech jedinečný objekt ID a chceme se vyhnout tomu, abychom nemuseli pro přístup k ovládacímu prvku přesně odkazovat na každý kontejner názvů v hierarchii ovládacích prvků. Smysl dává i varianta FindControl , která rekurzivně prohledává všechny kontejnery názvů. Rozhraní .NET Framework bohužel takovou metodu neobsahuje.

Dobrou zprávou je, že můžeme vytvořit vlastní FindControl metodu, která rekurzivně prohledá všechny kontejnery pojmenování. Ve skutečnosti pomocí rozšiřujících metod můžeme metodu FindControlRecursive připojit ke Control třídě, která doprovází její stávající FindControl metodu.

Poznámka

Rozšiřující metody jsou novinkou v C# 3.0 a Visual Basicu 9, což jsou jazyky, které se dodávají s rozhraním .NET Framework verze 3.5 a Visual Studio 2008. Stručně řečeno, rozšiřující metody umožňují vývojáři vytvořit novou metodu pro existující typ třídy prostřednictvím speciální syntaxe. Další informace o této užitečné funkci najdete v mém článku Rozšíření funkčnosti základního typu pomocí rozšiřujících metod.

Pokud chcete vytvořit metodu rozšíření, přidejte do App_Code složky nový soubor s názvem PageExtensionMethods.cs. Přidejte rozšiřující metodu s názvem FindControlRecursive , která jako vstup přebírá string parametr s názvem controlID. Aby rozšiřující metody správně fungovaly, je důležité, aby samotná třída a její rozšiřující metody byly označeny static. Kromě toho musí všechny rozšiřující metody přijmout jako první parametr objekt typu, na který se vztahuje rozšiřující metoda, a tomuto vstupnímu parametru musí předcházet klíčové slovo this.

Přidejte do PageExtensionMethods.cs souboru třídy následující kód, který definuje tuto třídu a metodu FindControlRecursive rozšíření:

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

S tímto kódem se vraťte do IDIssues.aspx třídy kódu na pozadí stránky a zakomentujte aktuální FindControl volání metody. Nahraďte je voláními .Page.FindControlRecursive("controlID") Na rozšiřujících metodách je to, že se zobrazují přímo v rozevíracích seznamech IntelliSense. Jak ukazuje obrázek 7, když zadáte Page (Stránka) a pak zadáte tečku FindControlRecursive , je metoda zahrnuta v rozevíracím seznamu IntelliSense spolu s dalšími Control metodami třídy.

Rozšiřující metody jsou součástí rozevíracích seznamů IntelliSense.

Obrázek 07: Rozšiřující metody jsou součástí Drop-Downs IntelliSense (kliknutím zobrazíte obrázek v plné velikosti)

Do obslužné SubmitButton_Click rutiny události zadejte následující kód a pak ho otestujte tak, že navštívíte stránku, zadáte svůj věk a kliknete na tlačítko Odeslat. Jak je znázorněno na obrázku 6, výsledným výstupem bude zpráva " Máte věk let!"

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);
}

Poznámka

Vzhledem k tomu, že rozšiřující metody jsou v C# 3.0 a Visual Basicu 9 nové, nemůžete při použití sady Visual Studio 2005 použít rozšiřující metody. Místo toho budete muset implementovat metodu FindControlRecursive v pomocné třídě. Takový příklad má Rick Strahl ve svém blogovém příspěvku, ASP.NET Maser Pages a FindControl.

Krok 4: Použití správnéidhodnoty atributu ve skriptu Client-Side

Jak je uvedeno v úvodu tohoto kurzu, vykreslený id atribut webového ovládacího prvku se často používá ve skriptu na straně klienta k programovému odkazu na konkrétní element HTML. Například následující JavaScript odkazuje na element HTML pomocí jeho id a pak zobrazí jeho hodnotu v modálním okně zprávy:

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

Vzpomeňte si, že na ASP.NET stránkách, které neobsahují kontejner názvů, je atribut vykresleného elementu id HTML identický s hodnotou vlastnosti webového ID ovládacího prvku. Z tohoto důvodu je lákavé pevně zakódovat hodnoty id atributů do kódu JavaScriptu. To znamená, že pokud víte, že chcete získat přístup k ovládacímu Age prvku TextBox Web prostřednictvím skriptu na straně klienta, udělejte to prostřednictvím volání .document.getElementById("Age")

Problém s tímto přístupem spočívá v tom, že při použití stránek předlohy (nebo jiných ovládacích prvků pojmenování kontejneru) není vykreslený kód HTML id synonymem vlastnosti webového ID ovládacího prvku. Vaším prvním sklonem může být navštívit stránku prostřednictvím prohlížeče a zobrazit zdroj, abyste zjistili skutečný id atribut. Jakmile znáte vykreslenou id hodnotu, můžete ji vložit do volání pro getElementById přístup k elementu HTML, se kterým potřebujete pracovat, prostřednictvím skriptu na straně klienta. Tento přístup je méně než ideální, protože určité změny v hierarchii ovládacích prvků stránky nebo změny ID vlastností ovládacích prvků pojmenování změní výsledný id atribut, čímž naruší kód JavaScriptu.

Dobrou zprávou je, že vykreslená hodnota atributu id je přístupná v kódu na straně serveru prostřednictvím vlastnosti webového ClientIDovládacího prvku. Tuto vlastnost byste měli použít k určení hodnoty atributu id používaného ve skriptu na straně klienta. Pokud například chcete na stránku přidat funkci JavaScriptu, která při zavolání zobrazí hodnotu Age TextBox v poli modální zprávy, přidejte do Page_Load obslužné rutiny události následující kód:

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

Výše uvedený kód vloží hodnotu Age Vlastnosti ClientID TextBoxu do volání JavaScriptu .getElementById Pokud tuto stránku navštívíte v prohlížeči a zobrazíte zdroj HTML, najdete následující kód JavaScriptu:

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

Všimněte si, ctl00_MainContent_Agejak se ve volání getElementByIdzobrazí správná id hodnota atributu . Vzhledem k tomu, že se tato hodnota počítá za běhu, funguje bez ohledu na pozdější změny hierarchie ovládacích prvků stránky.

Poznámka

Tento příklad JavaScriptu pouze ukazuje, jak přidat funkci JavaScriptu, která správně odkazuje na element HTML vykreslený serverovým ovládacím prvkem. Pokud chcete tuto funkci použít, budete muset vytvořit další JavaScript, který funkci zavolá při načtení dokumentu nebo když se objeví nějaká akce konkrétního uživatele. Další informace o těchto a souvisejících tématech najdete v tématu Práce se skriptem Client-Side.

Souhrn

Některé ASP.NET serverové ovládací prvky fungují jako kontejnery pojmenování, což ovlivňuje vykreslené id hodnoty atributů jejich sestupných ovládacích prvků i rozsah ovládacích prvků, které FindControl metoda používá. Pokud jde o stránky předlohy, jak samotná stránka předlohy, tak její ovládací prvky ContentPlaceHolder jsou kontejnery pojmenování. V důsledku toho musíme odložit trochu více práce na programovém odkazu na ovládací prvky v rámci stránky obsahu pomocí FindControl. V tomto kurzu jsme prozkoumali dvě techniky: procházení ovládacího prvku ContentPlaceHolder a volání jeho FindControl metody a zavedení vlastní FindControl implementace, která rekurzivně prohledává všechny názvové kontejnery.

Kromě problémů s pojmenováním kontejnerů na straně serveru, které se týkají odkazování na webové ovládací prvky, dochází také k problémům na straně klienta. Pokud kontejnery pojmenování chybí, hodnota vlastnosti webového ID ovládacího prvku a hodnota vykresleného id atributu jsou stejné. Ale s přidáním kontejneru pojmenování zahrnuje vykreslený id atribut jak ID hodnoty webového ovládacího prvku, tak kontejnery názvů v jeho hierarchii řízení původu. Tyto otázky týkající se pojmenování nejsou problém, pokud použijete vlastnost webového ClientID ovládacího prvku k určení hodnoty vykresleného id atributu ve skriptu na straně klienta.

Všechno nejlepší na programování!

Další čtení

Další informace o tématech probíraných v tomto kurzu najdete v následujících zdrojích informací:

O autorovi

Scott Mitchell, autor několika knih o ASP/ASP.NET a zakladatel 4GuysFromRolla.com, pracuje s webovými technologiemi Microsoftu od roku 1998. Scott pracuje jako nezávislý konzultant, školitel a spisovatel. Jeho poslední kniha je Sams Teach Yourself ASP.NET 3.5 in 24 Hours. Scotta můžete zastihnout na adrese mitchell@4GuysFromRolla.com nebo prostřednictvím svého blogu na adrese http://ScottOnWriting.NET.

Zvláštní poděkování

Tato série kurzů byla zkontrolována mnoha užitečnými recenzenty. Hlavními recenzenty pro tento kurz byli Zack Jones a Suchi Barnerjee. Chtěli byste si projít své nadcházející články na webu MSDN? Pokud ano, dejte mi řádek na mitchell@4GuysFromRolla.com.