Pojmenovávání ID ovládacích prvků na stránkách obsahu (C#)
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.
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.
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ýchID
změ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.
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í id
Age
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 id
kontejneru .
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.aspx
znač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 ctlXX
pojmenová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 SubmitButton
Click
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_Click
jsou 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).
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 ctl00
strá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 ctl00
stránky předlohy.) Results
Proto se hodnoty Label a Age
TextBox nenašly a ResultsLabel
AgeTextBox
jsou jim přiřazeny null
hodnoty .
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 MainContent
FindControl
. 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 MainContent
atd. 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 ctl00
vž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í.
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.
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éid
hodnoty 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 ClientID
ovlá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_Age
jak se ve volání getElementById
zobrazí 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í:
- ASP.NET stránek předlohy a
FindControl
- Vytváření uživatelských rozhraní dynamického zadávání dat
- Postupy: Odkaz ASP.NET obsahu stránky předlohy
- Stránky mater: tipy, triky a pasti
- Práce se skriptem Client-Side
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.