Pojmenovávání ID ovládacích prvků na stránkách obsahu (VB)
Scott Mitchell
Ukazuje, jak ovládací prvky ContentPlaceHolder slouží jako kontejner pojmenování, a proto programově pracovat s ovládacím prvkem obtížné (přes FindControl). Podívejte se na tento problém a alternativní řešení. Popisuje také, jak programově přistupovat k výsledné hodnotě ClientID.
Úvod
Všechny ovládací prvky serveru ASP.NET zahrnují ID
vlastnost, která jednoznačně identifikuje ovládací prvek a je prostředky, pomocí kterých je ovládací prvek programově přístupný v kódu za třídou. Podobně mohou elementy v dokumentu HTML obsahovat id
atribut, který jednoznačně identifikuje prvek; tyto id
hodnoty se často používají ve skriptu na straně klienta k programovému odkazování na konkrétní element HTML. Vzhledem k tomu můžete předpokládat, že když se ovládací prvek serveru ASP.NET vykresluje do HTML, použije se jeho ID
hodnota jako id
hodnota vykreslovaného elementu HTML. To nemusí být nutně případ, protože za určitých okolností se jeden ovládací prvek s jednou ID
hodnotou může v vykreslené značkě objevit vícekrát. Představte si ovládací prvek GridView, který obsahuje TemplateField s ovládacím ID
prvku Label Web s hodnotou ProductName
. Pokud je Objekt GridView 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.
Pro zpracování takových scénářů 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 ovládací prvky serveru, které se zobrazí v kontejneru pojmenování, mají svou vykreslenou id
hodnotu s předponou ID
ovládacího prvku kontejneru pojmenování. Například třídy GridView
jsou GridViewRow
kontejnery pojmenování. V důsledku toho je ovládací prvek Label definovaný v GridView TemplateField s ID
ProductName
přiřazenou vykreslenou id
hodnotou GridViewID_GridViewRowID_ProductName
. Vzhledem k tomu , že 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 konkrétní ASP.NET serverový ovládací prvek by měl fungovat jako kontejner pojmenování. Rozhraní INamingContainer
nevypisuje žádné metody, které musí ovládací prvek serveru implementovat, spíše se používá jako značka. Při generování vykreslených značek, pokud ovládací prvek implementuje toto rozhraní, modul ASP.NET automaticky předponu jeho ID
hodnoty sestupně vykreslovaných id
atributů. 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 může být ovládací prvek programově odkazován z třídy kódu na stránce ASP.NET. Metoda FindControl("controlID")
se běžně používá k programovému odkazu na webový ovládací prvek. FindControl
Nepronikne však prostřednictvím pojmenování kontejnerů. V důsledku toho nelze přímo použít metodu Page.FindControl
k odkazování ovládacích prvků v rámci GridView nebo jiného kontejneru pojmenování.
Jak jste se mohli domnívat, stránky předlohy i 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 programového odkazu 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 ASP.NET stránku. Vytvořte novou stránku obsahu pojmenovanou IDIssues.aspx
v kořenové složce a vytvořte vazbu na stránku předlohy Site.master
.
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 Content není k dispozici výchozí obsah ContentPlaceHolder stránky předlohy se místo toho vygeneruje. Vzhledem k tomu, že QuickLoginUI
a LeftColumnContent
ContentPlaceHolders obsahují vhodné výchozí značky pro tuto stránku, pokračujte a 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="VB" MasterPageFile="~/Site.master" AutoEventWireup="false" CodeFile="IDIssues.aspx.vb" Inherits="IDIssues" Title="Untitled Page" %>
<asp:Content ID="Content1" ContentPlaceHolderID="head" Runat="Server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" Runat="Server">
</asp:Content>
V kurzu Zadání názvu, meta značek a dalších hlaviček HTML v kurzu stránka předlohy jsme vytvořili vlastní třídu základní stránky (BasePage
), která automaticky nakonfiguruje název stránky, pokud není explicitně nastaven. IDIssues.aspx
Aby stránka tuto funkci využívala, musí kódová třída stránky odvodit z BasePage
třídy (místo System.Web.UI.Page
). Upravte definici třídy za kódem tak, aby vypadala takto:
Partial Class IDIssues
Inherits BasePage
End Class
Nakonec aktualizujte Web.sitemap
soubor tak, aby zahrnoval položku pro tuto novou lekci. <siteMapNode>
Přidejte prvek a nastavte jeho title
a url
atributy na "Control ID Pojmenování Problémů" a ~/IDIssues.aspx
v uvedeném pořadí. Po přidání kódu Web.sitemap
souboru by měl 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 Web.sitemap
mapy webu se okamžitě projeví v části 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: Zkoumání vykreslovanýchID
změn
Abychom lépe pochopili úpravy, které modul ASP.NET provádí na vykreslené id
hodnoty 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 "Zadejte váš věk:" následovaný ovládacím prvku TextBox Web. Na stránce dále dolů přidejte ovládací prvek Button Web a ovládací prvek Label Web. Nastavte TextBox ID
a Columns
vlastnosti na Age
a 3. Nastavte vlastnosti a vlastnosti tlačítka Text
na Odeslat a SubmitButton
.ID
Vymažte vlastnost Popisek Text
a nastavte jeho ID
hodnotu 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 prohlížení pomocí 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 zobrazte zdroj HTML. Jak ukazuje následující kód, id
hodnoty elementů HTML pro ovládací prvky TextBox, Button a Label Web jsou kombinací ID
hodnot webových ovládacích prvků a ID
hodnot kontejnerů pojmenování 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 jsme si poznamenali 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é ID
hodnoty jejich 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
. Toto je předpona hodnoty ovládacího prvku ID
ContentPlaceHolder, MainContent
. Tato hodnota je navíc předponou hodnoty stránky předlohyID
. ctl00
Net effect je id
hodnota atributu skládající se z ID
hodnot stránky předlohy, ContentPlaceHolder ovládacího prvku a samotného Textového pole.
Obrázek 4 znázorňuje toto chování. Chcete-li určit vykreslení id
Age
textového pole, začněte hodnotou ID
ovládacího prvku TextBox, Age
. V dalším kroku si projdete hierarchii ovládacích prvků. V každém kontejneru pojmenování (tyto uzly s barvou peach) předpona aktuální vykreslené id
kontejnerem id
pojmenování .
Obrázek 04: Vykreslené id
atributy jsou založené na ID
hodnotách kontejnerů pojmenování
Poznámka:
Jak jsme si 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 stránce ASP.NET se přidává explicitně prostřednictvím deklarativního kódu stránky. Ovládací MainContent
prvek ContentPlaceHolder byl explicitně zadán v kódu Site.master
; Age
TextBox byl definován IDIssues.aspx
's markup. 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, jako je 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
hodnoty za běhu pro ovládací prvky, jejichž ID nebyla explicitně nastavena. Používá vzor ctlXX
pojmenování , kde XX je sekvenční rostoucí celočíselná hodnota.
Vzhledem k tomu, že samotná stránka předlohy slouží jako kontejner pojmenování, webové ovládací prvky definované na stránce předlohy také změnily vykreslené id
hodnoty atributů. Například popisekDisplayDate
, který jsme přidali na stránku předlohy v kurzu Vytvoření rozložení pro celý web se stránkami předlohy, má následující vykreslené značky:
<span id="ctl00_DateDisplay">current date</span>
Všimněte si, že id
atribut zahrnuje hodnotu stránky ID
předlohy (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 programu prostřednictvímFindControl
Každý ASP.NET serverový ovládací prvek obsahuje metodu FindControl("controlID")
, která hledá sestupně ovládacího prvku s názvem controlID. Je-li takový ovládací prvek nalezen, je vrácen; pokud nebyl nalezen žádný odpovídající ovládací prvek, FindControl
vrátí hodnotu Nothing
.
FindControl
je užitečná ve scénářích, kdy potřebujete získat přístup k ovládacímu prvku, ale nemáte k němu přímý odkaz. Při práci s datovými webovými ovládacími prvky, jako je GridView, například ovládací prvky v polích GridView jsou definovány jednou v deklarativní syntaxi, ale za běhu se vytvoří instance ovládacího prvku pro každý řádek GridView. V důsledku toho existují ovládací prvky generované za běhu, ale nemáme přímý odkaz dostupný z třídy kódu za kódem. 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 naleznete v tématu Vlastní formátování založené na datech.) K tomuto scénáři dochází při dynamickém přidávání webových ovládacích prvků do webového formuláře, tématu popsaném v části Vytváření uživatelských rozhraní pro dynamické zadávání dat.
Chcete-li ilustrovat FindControl
použití metody vyhledávání ovládacích prvků na stránce obsahu, vytvořte obslužnou rutinu SubmitButton
Click
události pro událost události. 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 na Results
základě vstupu uživatele.
Poznámka:
Samozřejmě, že v tomto příkladu nemusíme používat FindControl
odkazy na ovládací prvky Popisek a TextBox. Mohli bychom na ně odkazovat přímo prostřednictvím ID
jejich hodnot vlastností. Tady se používám FindControl
k ilustraci toho, co se stane při použití FindControl
ze stránky obsahu.
Protected Sub SubmitButton_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles SubmitButton.Click
Dim ResultsLabel As Label = CType(FindControl("Results"), Label)
Dim AgeTextBox As TextBox = CType(Page.FindControl("Age"), TextBox)
ResultsLabel.Text = String.Format("You are {0} years old!", AgeTextBox.Text)
End Sub
Zatímco syntaxe použitá k volání FindControl
metody se mírně liší v prvních dvou řádcích SubmitButton_Click
, jsou sémanticky ekvivalentní. Vzpomeňte si, že všechny ovládací prvky serveru ASP.NET zahrnují metodu FindControl
. To zahrnuje Page
třídu, ze které musí být odvozeny všechny ASP.NET třídy za kódem. Volání je tedy ekvivalentní volání Page.FindControl("controlID")
, za předpokladu, FindControl("controlID")
že jste nepřepsali metodu FindControl
ve třídě kódu za nebo ve vlastní základní třídě.
Po zadání tohoto kódu přejděte na 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 Odeslat je NullReferenceException
vyvolána (viz obrázek 5).
Obrázek 05: Vyvolání A NullReferenceException
(kliknutím zobrazíte obrázek s plnou velikostí)
Pokud nastavíte zarážku v SubmitButton_Click
obslužné rutině události, uvidíte, že obě volání, která se mají FindControl
vrátit Nothing
. Vyvolá se NullReferenceException
při pokusu Age
o přístup k vlastnosti TextBox Text
.
Problémem je, že Control.FindControl
prohledává pouze sestupné položky ovládacího prvku, které jsou ve stejném kontejneru pojmenování. Vzhledem k tomu, že stránka předlohy představuje nový kontejner pojmenování, volání Page.FindControl("controlID")
nikdy permeuje objekt stránky předlohy ctl00
. (Zpět na obrázek 4 zobrazte hierarchii ovládacích prvků, která zobrazuje Page
objekt jako nadřazený objekt ctl00
stránky předlohy .) Results
Proto popisek a Age
TextBox nejsou nalezeny a ResultsLabel
AgeTextBox
jsou přiřazeny hodnoty Nothing
.
Existují dvě alternativní řešení této výzvy: můžeme přejít k podrobnostem, jeden kontejner pojmenování najednou, na příslušný ovládací prvek; 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 podrobnostem o příslušném kontejneru pojmenování
FindControl
Abychom mohli odkazovat na Results
Popisek nebo Age
TextBox, musíme volat FindControl
z nadřazeného ovládacího prvku ve stejném kontejneru pojmenování. Jak ukazuje obrázek 4, MainContent
je ovládací prvek ContentPlaceHolder jediným nadřazeným objektem Results
nebo Age
je v rámci stejného kontejneru pojmenování. Jinými slovy, volání FindControl
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 ovládací Results
prvky nebo Age
ovládací prvky.
Dim ResultsLabel As Label = CType(MainContent.FindControl("Results"), Label)
Dim AgeTextBox As TextBox = CType(MainContent.FindControl("Age"), TextBox)
Nemůžeme ale pracovat s MainContent
ContentPlaceHolderem z třídy kódu 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 Sub SubmitButton_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles SubmitButton.Click
Dim MainContent As ContentPlaceHolder = CType(FindControl("MainContent"), ContentPlaceHolder)
Dim ResultsLabel As Label = CType(MainContent.FindControl("Results"), Label)
Dim AgeTextBox As TextBox = CType(MainContent.FindControl("Age"), TextBox)
ResultsLabel.Text = String.Format("You are {0} years old!", AgeTextBox.Text)
End Sub
Pokud stránku navštívíte v prohlížeči, zadejte svůj věk a klikněte na tlačítko Odeslat, je NullReferenceException
vyvolána. Pokud nastavíte zarážku v SubmitButton_Click
obslužné rutině události, uvidíte, že k této výjimce dojde při pokusu MainContent
o volání metody objektu FindControl
. Objekt MainContent
je roven Nothing
, protože FindControl
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
spustí hledání od horní části hierarchie ovládacích prvků a nepronikne do kontejnerů pojmenování, ale MainContent
ContentPlaceHolder je v rámci stránky předlohy, což je kontejner pojmenování.
Než budeme moct použít FindControl
k získání odkazu MainContent
na , 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 odsud odkazy na Results
Popisek a Age
TextBox (znovu pomocí FindControl
). Jak ale získáme odkaz na stránku předlohy? Kontrolou id
atributů v vykreslené značkě 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 ilustruje tuto logiku:
'Get a reference to the master page
Dim ctl00 As MasterPage = CType(FindControl("ctl00"), MasterPage)
'Get a reference to the ContentPlaceHolder
Dim MainContent As ContentPlaceHolder = CType(ctl00.FindControl("MainContent"), ContentPlaceHolder)
'Reference the Label and TextBox controls
Dim ResultsLabel As Label = CType(MainContent.FindControl("Results"), Label)
Dim AgeTextBox As TextBox = CType(MainContent.FindControl("Age"), TextBox)
I když tento kód bude jistě fungovat, předpokládá, že automaticky vygenerovaná ID
stránka předlohy bude ctl00
vždy . Nikdy není vhodné vytvořit 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 použití FindControl("ctl00")
k získání odkazu na stránku předlohy pro přístup k MainContent
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 Sub SubmitButton_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles SubmitButton.Click
'Get a reference to the ContentPlaceHolder
Dim MainContent As ContentPlaceHolder = CType(Page.Master.FindControl("MainContent"), ContentPlaceHolder)
'Reference the Label and TextBox controls
Dim ResultsLabel As Label = CType(MainContent.FindControl("Results"), Label)
Dim AgeTextBox As TextBox = CType(MainContent.FindControl("Age"), TextBox)
ResultsLabel.Text = String.Format("You are {0} years old!", AgeTextBox.Text)
End Sub
Tentokrát přejděte na stránku v prohlížeči, zadejte svůj věk a kliknutím na tlačítko Odeslat zobrazíte zprávu v popisku Results
podle očekávání.
Obrázek 06: Věk uživatele se zobrazí v popisku (kliknutím zobrazíte obrázek v plné velikosti).
Rekurzivní vyhledávání prostřednictvím kontejnerů pojmenování
Důvod, proč předchozí příklad kódu odkazoval na MainContent
ContentPlaceHolder ovládací prvek ze stránky předlohy, a poté Results
Popisek a Age
TextBox ovládací prvky z MainContent
, je to proto, že Control.FindControl
metoda hledá pouze v rámci názvového kontejneru Control. Ve FindControl
většině scénářů dává smysl zůstat v kontejneru pojmenování, protože dva ovládací prvky ve dvou různých kontejnerech pojmenování můžou mít stejné ID
hodnoty. Představte si případ GridView, který definuje ovládací prvek Label Web pojmenovaný ProductName
v rámci jednoho z jeho TemplateFields. Pokud jsou data svázaná s Objektem GridView za běhu, ProductName
vytvoří se popisek pro každý řádek GridView. Pokud FindControl
se prohledávají všechny kontejnery pojmenování a my jsme volali Page.FindControl("ProductName")
, jakou instanci popisku má FindControl
vrátit? Popisek ProductName
v prvním řádku GridView? Ten v posledním řádku?
Takže ve Control.FindControl
většině případů má hledání smysl jen pro kontejner pojmenování Control. Existují ale i jiné případy, jako je například ten, který nás čelí, kde máme jedinečný ID
název ve všech kontejnerech pojmenování a chceme se vyhnout tomu, aby bylo nutné pro přístup k ovládacímu prvku přesně odkazovat na každý kontejner pojmenování v hierarchii řízení. Mít variantu FindControl
, která rekurzivně prohledává všechny kontejnery pojmenování, dává smysl také. 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 nemůžeme přidružovat metodu Control
FindControlRecursive
ke třídě, aby doprovázela její stávající FindControl
metodu.
Poznámka:
Rozšiřující metody jsou novinkou v jazyce C# 3.0 a Visual Basic 9, což jsou jazyky, které jsou součástí rozhraní .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í funkce základního typu pomocí rozšiřujících metod.
Chcete-li vytvořit rozšiřující metodu, přidejte nový soubor do App_Code
složky s názvem PageExtensionMethods.vb
. Přidejte rozšiřující metodu s názvem FindControlRecursive
, která přebírá jako vstup parametr s String
názvem controlID
. Aby metody rozšíření fungovaly správně, je důležité, aby třída byla označena jako Module
a že metody rozšíření mají předponu atributu <Extension()>
. Kromě toho všechny rozšiřující metody musí přijmout jako první parametr objekt typu, na který se metoda rozšíření vztahuje.
Do souboru přidejte následující kód PageExtensionMethods.vb
, který tento kód definuje a Module
metodu FindControlRecursive
rozšíření:
Imports System.Runtime.CompilerServices
Public Module PageExtensionMethods
<Extension()> _
Public Function FindControlRecursive(ByVal ctrl As Control, ByVal controlID As String) As Control
If String.Compare(ctrl.ID, controlID, True) = 0 Then
' We found the control!
Return ctrl
Else
' Recurse through ctrl's Controls collections
For Each child As Control In ctrl.Controls
Dim lookFor As Control = FindControlRecursive(child, controlID)
If lookFor IsNot Nothing Then
Return lookFor ' We found the control
End If
Next
' If we reach here, control was not found
Return Nothing
End If
End Function
End Module
S tímto kódem se vraťte do IDIssues.aspx
třídy kódu stránky a zakomentujte aktuální FindControl
volání metody. Nahraďte je voláním Page.FindControlRecursive("controlID")
. O rozšiřujících metodách je přehledné, že se zobrazují přímo v rozevíracích seznamech IntelliSense. Jak ukazuje obrázek 7, při psaní Page
a následném stisknutí tečky FindControlRecursive
je metoda zahrnuta do rozevíracího seznamu IntelliSense spolu s ostatními Control
metodami třídy.
Obrázek 07: V rozevíracích sadě IntelliSense jsou zahrnuty metody rozšíření (kliknutím zobrazíte obrázek v plné velikosti).
Do obslužné rutiny události zadejte následující kód SubmitButton_Click
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 zpět na obrázku 6, výsledný výstup bude zpráva "You are age years old!".
Protected Sub SubmitButton_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles SubmitButton.Click
Dim ResultsLabel As Label = CType(Page.FindControlRecursive("Results"), Label)
Dim AgeTextBox As TextBox = CType(Page.FindControlRecursive("Age"), TextBox)
ResultsLabel.Text = String.Format("You are {0} years old!", AgeTextBox.Text)
End Sub
Poznámka:
Vzhledem k tomu, že metody rozšíření jsou pro jazyk C# 3.0 a Visual Basic 9 novinkou, nemůžete použít rozšiřující metody, pokud používáte Visual Studio 2005. Místo toho budete muset implementovat metodu FindControlRecursive
v pomocné třídě. Rick Strahl má takový příklad 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 na straně klienta
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 odkazování na konkrétní element HTML. Například následující JavaScript odkazuje na element HTML podle jeho id
a pak zobrazí jeho hodnotu v modálním poli 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 pojmenování, atribut vykresleného elementu id
HTML je identický s hodnotou vlastnosti webového ID
ovládacího prvku. Z tohoto důvodu je lákavé pevně kódovat v id
hodnotách atributů do javascriptového kódu. To znamená, že pokud víte, že chcete získat přístup k webovému ovládacímu Age
prvku TextBox prostřednictvím skriptu na straně klienta, proveďte 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ů kontejneru pojmenování) vykreslený kód HTML id
není synonymem vlastnosti webového ID
ovládacího prvku. Vaším prvním sklonem může být navštívit stránku v prohlížeči a zobrazit zdroj k určení skutečného id
atributu. Jakmile znáte vykreslovanou id
hodnotu, můžete ji vložit do volání getElementById
pro přístup k elementu HTML, se kterým potřebujete pracovat prostřednictvím skriptu na straně klienta. Tento přístup je menší 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ž dojde k narušení kódu JavaScriptu.
Dobrou zprávou je, že hodnota atributuid
, která se vykresluje, 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žité ve skriptu na straně klienta. Chcete-li například přidat funkci JavaScriptu na stránku, která při zavolání zobrazí hodnotu Age
TextBox v modálním poli zprávy, přidejte do Page_Load
obslužné rutiny události následující kód:
ClientScript.RegisterClientScriptBlock(Me.GetType(), "ShowAgeTextBoxScript", _
"function ShowAge() " & vbCrLf & _
"{" & vbCrLf & _
" var elem = document.getElementById('" & AgeTextBox.ClientID & "');" & vbCrLf & _
" if (elem != null)" & vbCrLf & _
" alert('You entered ' + elem.value + ' into the Age text box.');" & vbCrLf & _
"}", True)
Výše uvedený kód vloží hodnotu Age
TextBox ClientID
vlastnost do javascriptového volání 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 v rámci volání getElementById
zobrazí správná id
hodnota atributu . Vzhledem k tomu, že tato hodnota se 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, musíte vytvořit další JavaScript, který funkci zavolá, když se dokument načte nebo když dojde k nějaké konkrétní akci uživatele. Další informace o těchto a souvisejících tématech najdete v tématu Práce se skriptem na straně klienta.
Shrnutí
Některé ASP.NET serverové ovládací prvky fungují jako kontejnery pojmenování, které ovlivňují vykreslené id
hodnoty atributů jejich sestupných ovládacích prvků a také rozsah ovládacích prvků plátna generovaných metodou FindControl
. 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 trochu více práce na programově odkazovat ovládací prvky na stránce 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 kontejnery pojmenování.
Kromě problémů na straně serveru představují kontejnery pojmenování, pokud jde o odkazování na webové ovládací prvky, existují také problémy na straně klienta. Bez pojmenování kontejnerů je hodnota vlastnosti webového ovládacího prvku ID
a vykreslená id
hodnota atributu stejná. Kromě přidání kontejneru pojmenování zahrnuje vykreslený id
atribut jak ID
hodnoty webového ovládacího prvku, tak kontejnery pojmenování v hierarchii ovládacích prvků. Tyto obavy týkající se pojmenování jsou 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.
Šťastné 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ánky předlohy a
FindControl
- Vytváření uživatelských rozhraní dynamického zadávání dat
- Postupy: Odkaz na obsah stránky předlohy ASP.NET
- Stránky mater: Tipy, triky a pasti
- Práce se skriptem na straně klienta
O autorovi
Scott Mitchell, autor více knih ASP/ASP.NET a zakladatel 4GuysFromRolla.com, pracoval s webovými technologiemi Microsoftu od roku 1998. Scott pracuje jako nezávislý konzultant, trenér a spisovatel. Jeho nejnovější kniha je Sams Výuka sebe ASP.NET 3,5 za 24 hodin. Scott může být dosažitelný na mitchell@4GuysFromRolla.com nebo přes svůj blog na http://ScottOnWriting.NET.
Zvláštní díky
Tato série kurzů byla zkontrolována mnoha užitečnými recenzenty. Vedoucí recenzenti tohoto kurzu byli Zack Jones a Suchi Barnerjee. Chcete si projít nadcházející články MSDN? Pokud ano, zahoďte mi řádek na mitchell@4GuysFromRolla.com.