Sdílet prostřednictvím


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

Scott Mitchell

Stáhnout PDF

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 .

Přidání stránky obsahu IDIssues.aspx 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 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.aspxv 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.

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: Zkoumání vykreslovanýchIDzmě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.

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 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 idpojmenování .

Atributy vykresleného ID jsou založené na hodnotách ID kontejnerů 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 ctlXXpojmenová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 SubmitButtonClick 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).

A NullReferenceException is Raised

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 ctl00strá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 MainContentna , 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 MainContentatd. 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 ctl00vž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í.

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

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.

Metody rozšíření jsou zahrnuty v rozevíracích sadě IntelliSense.

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éidhodnoty 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_Agejak se v rámci volání getElementByIdzobrazí 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í:

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.