Поделиться через


Именование идентификатора элемента управления на страницах содержимого (VB)

Скотт Митчелл

Скачать в формате PDF

Иллюстрирует, как элементы управления ContentPlaceHolder служат контейнером именования и поэтому программно работают с элементом управления (с помощью FindControl). Рассмотрим эту проблему и обходные пути. Также описывается, как программно получить доступ к полученному значению ClientID.

Введение

Все элементы управления ASP.NET сервера включают ID свойство, уникально определяющее элемент управления и являющееся средством программного доступа к элементу управления в классе code-behind. Аналогичным образом элементы в HTML-документе могут включать id атрибут, который однозначно идентифицирует элемент. Эти id значения часто используются в клиентском скрипте для программной ссылки на определенный элемент HTML. Учитывая это, можно предположить, что при отображении ASP.NET серверного элемента управления в HTML его ID значение используется в качестве id значения отрисованного HTML-элемента. Это не обязательно так, так как в определенных обстоятельствах один элемент управления с одним ID значением может отображаться несколько раз в отрисованной разметке. Рассмотрим элемент управления GridView, включающий шаблонField с веб-элементом управления Label с значением ID ProductName. Если GridView привязан к источнику данных во время выполнения, эта метка повторяется один раз для каждой строки GridView. Для каждой отрисоченной метки требуется уникальное id значение.

Для обработки таких сценариев ASP.NET позволяет обозначать определенные элементы управления как контейнеры именования. Контейнер именования служит новым ID пространством имен. Все серверные элементы управления, отображаемые в контейнере именования, имеют префикс отрисованного id значения с ID помощью элемента управления именованием контейнера. Например, GridView и GridViewRow классы являются контейнерами именования. Следовательно, элемент управления Label, определенный в GridView TemplateField, ID ProductName получает отрисованное id значение GridViewID_GridViewRowID_ProductName. Так как GridViewRowID является уникальным для каждой строки GridView, полученные id значения являются уникальными.

Примечание.

Интерфейс INamingContainer используется для указания того, что определенный серверный элемент управления ASP.NET должен функционировать в качестве контейнера именования. Интерфейс не содержит никаких методов, которые должен реализовывать серверный элемент управления. Вместо INamingContainer этого он используется в качестве маркера. При создании отрисованной разметки, если элемент управления реализует этот интерфейс, модуль ASP.NET автоматически префиксирует его ID значение для отрисованных id значений атрибутов потомков. Этот процесс подробно рассматривается на шаге 2.

Контейнеры именования не только изменяют отрисованное id значение атрибута, но и влияют на то, как элемент управления может быть программно ссылаться на класс кода ASP.NET страницы. Этот FindControl("controlID") метод обычно используется для программной ссылки на веб-элемент управления. FindControl Однако не проникает через контейнеры именования. Следовательно, нельзя напрямую использовать Page.FindControl метод для ссылки на элементы управления в GridView или другом контейнере именования.

Как вы могли предположить, главные страницы и ContentPlaceHolders реализуются как контейнеры именования. В этом руководстве мы рассмотрим, как эталонные страницы влияют на значения элементов id HTML и способы программно ссылаться на веб-элементы управления на странице содержимого с помощью FindControl.

Шаг 1. Добавление новой страницы ASP.NET

Чтобы продемонстрировать основные понятия, описанные в этом руководстве, давайте добавим новую страницу ASP.NET на наш веб-сайт. Создайте новую страницу содержимого с именем IDIssues.aspx в корневой папке, привязав ее к главной Site.master странице.

Добавление страницы содержимого IDIssues.aspx в корневую папку

Рис. 01. Добавление страницы IDIssues.aspx содержимого в корневую папку

Visual Studio автоматически создает элемент управления контентом для каждой из четырех главных страниц ContentPlaceHolders. Как отмечалось в руководстве по нескольким contentPlaceHolders и содержимому по умолчанию, если элемент управления контентом отсутствует содержимое главной страницы по умолчанию ContentPlaceHolder, создается вместо этого. Так как contentPlaceHolders QuickLoginUI LeftColumnContent содержат подходящую разметку по умолчанию для этой страницы, перейдите и удалите соответствующие элементы управления содержимым.IDIssues.aspx На этом этапе декларативная разметка страницы содержимого должна выглядеть следующим образом:

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

В руководстве по указанию заголовка, мета тегов и других заголовков HTML в руководстве по главной странице мы создали настраиваемый базовый класс страницы (BasePage), который автоматически настраивает заголовок страницы, если он не задан явным образом. IDIssues.aspx Чтобы страница применяла эту функцию, класс кода страницы должен быть производным от BasePage класса (а неSystem.Web.UI.Page). Измените определение класса программной части, чтобы он выглядел следующим образом:

Partial Class IDIssues
 Inherits BasePage

End Class

Наконец, обновите Web.sitemap файл, чтобы включить запись для этого нового занятия. <siteMapNode> Добавьте элемент и задайте для его title атрибутов url значение Control ID Naming Issues (Проблемы именования идентификаторов элемента) и ~/IDIssues.aspxсоответственно. После добавления этого дополнения Web.sitemap разметка файла должна выглядеть следующим образом:

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

Как показано на рисунке 2, новая запись Web.sitemap карты сайта немедленно отражается в разделе "Уроки" в левом столбце.

В разделе уроков теперь содержится ссылка на

Рис. 02. Раздел уроков теперь содержит ссылку на "Проблемы именования идентификаторов элемента управления"

Шаг 2. Изучение отрисованныхIDизменений

Чтобы лучше понять изменения, внесенные подсистемой ASP.NET в отображаемые id значения серверных элементов управления, давайте добавим несколько веб-элементов управления на IDIssues.aspx страницу, а затем просмотрите отрисованную разметку, отправленную в браузер. В частности, введите текст "Введите свой возраст:", за которым следует элемент управления TextBox Web. Далее вниз на странице добавьте веб-элемент управления Button и веб-элемент управления Label. Задайте для текстового ID поля и Columns свойства Age значение 3 соответственно. Задайте для кнопки Text и ID свойства значение "Отправить" и SubmitButton. Удалите свойство Label Text и задайте для него значение ID Results.

На этом этапе декларативная разметка элемента управления контентом должна выглядеть следующим образом:

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

На рисунке 3 показана страница при просмотре с помощью конструктора Visual Studio.

Страница содержит три веб-элемента управления: текстовое поле, кнопка и метка

Рис. 03. Страница включает три веб-элемента управления: текстовое поле, кнопку и метку (щелкните, чтобы просмотреть изображение полного размера)

Перейдите на страницу через браузер, а затем просмотрите источник HTML. Как показано в приведенной ниже разметке, id значения элементов HTML для элементов TextBox, Button и Label Web controls являются сочетанием ID значений веб-элементов управления и ID значений контейнеров именования на странице.

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

Как отмечалось ранее в этом руководстве, эталонная страница и ее ContentPlaceHolders служат контейнерами именования. Следовательно, оба вносят отрисованные ID значения вложенных элементов управления. Возьмите атрибут TextBoxid, например: ctl00_MainContent_Age Помните, что значение элемента управления ID TextBox было Age. Это префиксируется со значением элемента управления ID ContentPlaceHolder. MainContent Кроме того, это значение префиксируется со значением ctl00главной страницыID. Чистый id эффект — это значение атрибута, состоящее из ID значений главной страницы, элемента управления ContentPlaceHolder и самого TextBox.

Рис. 4 иллюстрирует это поведение. Чтобы определить отрисовку id текстового Age поля, начните со ID значения элемента управления TextBox. Age Затем перейдите к иерархии элементов управления. На каждом контейнере именования (эти узлы с цветом персика), префикс текущей отрисовки id с помощью контейнера idименования.

Атрибуты идентификатора отрисовки основаны на значениях идентификаторов контейнеров именования

Рис. 04. Отрисованные id атрибуты основаны на ID значениях контейнеров именования

Примечание.

Как мы обсуждали, часть отрисованного id атрибута представляет собой ID значение главной страницы, но вы можете задуматься о том, ctl00 как это ID значение произошло. Мы не указали его где-либо на главной странице или странице содержимого. Большинство элементов управления серверами на странице ASP.NET добавляются явным образом через декларативную разметку страницы. Элемент MainContent управления ContentPlaceHolder был явно указан в разметке Site.master; Age в разметке TextBox был определен IDIssues.aspxразметка. Можно указать ID значения для этих типов элементов управления с помощью окно свойств или декларативного синтаксиса. Другие элементы управления, такие как сама эталонная страница, не определены в декларативной разметке. Следовательно, их ID значения должны быть автоматически созданы для нас. Модуль ASP.NET задает ID значения во время выполнения для этих элементов управления, идентификаторы которых не были явно заданы. Он использует шаблон ctlXXименования, где XX является последовательным увеличением целочисленного значения.

Так как главная страница служит контейнером именования, веб-элементы управления, определенные на главной странице, также изменили отрисованные id значения атрибутов. Например, метка, DisplayDate добавленная на главную страницу в руководстве по созданию макета на уровне сайта с помощью эталонных страниц, содержит следующую отрисованную разметку:

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

Обратите внимание, что id атрибут включает значение главной страницы ID (ctl00) и ID значение веб-элемента управления Label (DateDisplay).

Шаг 3. Программное ссылка на веб-элементы управления с помощьюFindControl

Каждый элемент управления ASP.NET сервера включает FindControl("controlID") метод, который выполняет поиск потомков элемента управления для именованного элемента управления. Если такой элемент управления найден, возвращается; Если соответствующий элемент управления не найден, FindControl возвращается Nothing.

FindControl полезно в сценариях, где требуется доступ к элементу управления, но у вас нет прямой ссылки на него. При работе с веб-элементами управления данными, например GridView, элементы управления в полях GridView определяются один раз в декларативном синтаксисе, но во время выполнения для каждой строки GridView создается экземпляр элемента управления. Следовательно, элементы управления, созданные во время выполнения, существуют, но у нас нет прямой ссылки, доступной из класса code-behind. В результате необходимо программно FindControl работать с определенным элементом управления в полях GridView. (Дополнительные сведения об использовании FindControl для доступа к элементам управления в шаблонах веб-элемента управления данными см. в разделе "Настраиваемое форматирование на основе данных".) Этот же сценарий происходит при динамическом добавлении веб-элементов управления в веб-форму, тема, описанная в разделе "Создание пользовательских интерфейсов динамической записи данных".

Чтобы проиллюстрировать использование FindControl метода для поиска элементов управления на странице содержимого, создайте обработчик событий для SubmitButtonClick события. В обработчике событий добавьте следующий код, который программно ссылается на Age текстовое поле и Results метку с помощью FindControl метода, а затем отображает сообщение на Results основе входных данных пользователя.

Примечание.

Конечно, нам не нужно ссылаться FindControl на элементы управления Label и TextBox для этого примера. Мы могли бы ссылаться на них напрямую с помощью значений свойств ID . Я использую FindControl здесь, чтобы проиллюстрировать, что происходит при использовании FindControl с страницы содержимого.

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

Хотя синтаксис, используемый для вызова FindControl метода, немного отличается в первых двух строках SubmitButton_Click, они семантически эквивалентны. Помните, что все ASP.NET серверные FindControl элементы управления включают метод. К ним относится Page класс, от которого должны быть производны все ASP.NET классы кода. Поэтому вызов эквивалентен вызову FindControl("controlID") Page.FindControl("controlID"), если вы не переопределили FindControl метод в классе кода или в пользовательском базовом классе.

После ввода этого кода посетите IDIssues.aspx страницу через браузер, введите возраст и нажмите кнопку "Отправить". После нажатия кнопки NullReferenceException "Отправить" вызывается (см. рис. 5).

Вызывается значение NullReferenceException

Рис. 05. NullReferenceException Вызывается (щелкните, чтобы просмотреть изображение полного размера)

Если установить точку останова в обработчике SubmitButton_Click событий, вы увидите, что оба вызова возвращаются FindControl Nothing. Вызывается NullReferenceException при попытке получить доступ к свойству Age TextBox Text .

Проблема заключается в том, что Control.FindControl выполняется поиск только потомков Элемента управления, которые находятся в одном контейнере именования. Так как эталонная страница представляет собой новый контейнер именования, вызов Page.FindControl("controlID") никогда не пронизывает объект ctl00главной страницы. (Вернитесь на рис. 4, чтобы просмотреть иерархию элементов управления, которая отображает Page объект в качестве родительского объекта ctl00главной страницы .) Поэтому метка и текстовое Results поле не найдены и AgeTextBox ResultsLabel присваиваются значенияNothing.Age

Существует два обходных решения этой проблемы: мы можем детализировать один контейнер именования за раз до соответствующего элемента управления; или мы можем создать собственный FindControl метод, который пронизывает контейнеры именования. Рассмотрим каждый из этих вариантов.

Детализация в соответствующем контейнере именования

Чтобы ссылаться FindControl на Results метку или Age текстовое поле, необходимо вызвать FindControl из элемента управления предка в том же контейнере именования. Как показано на рисунке 4, MainContent элемент управления ContentPlaceHolder является единственным предком Results или Age находится в одном контейнере именования. Другими словами, вызов FindControl метода из MainContent элемента управления, как показано в приведенном ниже фрагменте кода, правильно возвращает ссылку на Results элементы управления или Age элементы управления.

Dim ResultsLabel As Label = CType(MainContent.FindControl("Results"), Label)
Dim AgeTextBox As TextBox = CType(MainContent.FindControl("Age"), TextBox)

Однако мы не можем работать с MainContent ContentPlaceHolder из класса кода страницы содержимого, используя приведенный выше синтаксис, так как ContentPlaceHolder определен на главной странице. Вместо этого мы должны использовать FindControl для получения ссылки на MainContent. Замените код в обработчике SubmitButton_Click событий следующими изменениями:

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

Если вы посещаете страницу через браузер, введите свой возраст и нажмите кнопку "Отправить", NullReferenceException вызывается. Если задать точку останова в обработчике SubmitButton_Click событий, это исключение возникает при попытке вызвать MainContent метод объекта FindControl . Объект MainContent равен Nothing , так как FindControl метод не может найти объект с именем MainContent. Основная причина совпадает с Results элементами управления Label и Age TextBox: FindControl запускает поиск в верхней части иерархии элементов управления и не проникает в контейнеры именования, но MainContent ContentPlaceHolder находится на главной странице, которая является контейнером именования.

Прежде чем получить FindControl ссылку MainContentна нее, сначала нам потребуется ссылка на элемент управления главной страницы. Получив ссылку на главную страницу, мы можем получить ссылку на MainContent ContentPlaceHolder с помощью FindControl Results ссылки на метку и Age текстовое поле (опять же с помощью).FindControl Но как получить ссылку на главную страницу? Проверяя id атрибуты в отрисованной разметке, очевидно, что значение главной страницы ID .ctl00 Таким образом, мы можем использовать Page.FindControl("ctl00") для получения ссылки на главную страницу, а затем использовать этот объект для получения ссылки MainContentна и т. д. Следующий фрагмент кода иллюстрирует эту логику:

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

Хотя этот код, безусловно, будет работать, предполагается, что автогенерированные эталонной ID страницы всегда будут.ctl00 Никогда не рекомендуется делать предположения об автогенерированных значениях.

К счастью, ссылка на главную страницу доступна через Page свойство класса Master . Поэтому вместо того FindControl("ctl00") , чтобы получить ссылку на главную страницу для доступа к MainContent ContentPlaceHolder, мы можем использовать Page.Master.FindControl("MainContent")вместо этого ссылку. SubmitButton_Click Обновите обработчик событий следующим кодом:

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

На этот раз посетите страницу через браузер, введя возраст, и нажмите кнопку "Отправить", чтобы отобразить сообщение в Results метке, как ожидалось.

Возраст пользователя отображается в метке

Рис. 06. Возраст пользователя отображается в метке (щелкните, чтобы просмотреть изображение полного размера)

Рекурсивно поиск по контейнерам именования

Причина, по которой предыдущий пример кода ссылается MainContent на элемент управления ContentPlaceHolder с главной страницы, а затем Results элементы управления MainContentLabel и Age TextBox из , обусловлены тем, что Control.FindControl метод выполняет поиск только в контейнере именования Элемента управления. Наличие FindControl в контейнере именования имеет смысл в большинстве сценариев, так как два элемента управления в двух разных контейнерах именования могут иметь одинаковые ID значения. Рассмотрим случай GridView, который определяет веб-элемент управления Label, названный ProductName в одном из его TemplateFields. Если данные привязаны к GridView во время выполнения, ProductName метка создается для каждой строки GridView. Если FindControl выполняется поиск по всем контейнерам именования и вызывается Page.FindControl("ProductName"), какой экземпляр Label должен FindControl возвращать? Метка в первой строке ProductName GridView? Один в последней строке?

Поэтому при Control.FindControl поиске в контейнере именования элемента управления имеет смысл в большинстве случаев. Но существуют и другие случаи, например те, которые сталкиваются с нами, где у нас есть уникальный ID для всех контейнеров именования и хотите избежать необходимости тщательно ссылаться на каждый контейнер именования в иерархии элементов управления для доступа к элементу управления. FindControl Наличие варианта, который рекурсивно выполняет поиск всех контейнеров именования, также имеет смысл. К сожалению, платформа .NET Framework не включает такой метод.

Хорошая новость заключается в том, что мы можем создать собственный FindControl метод, который рекурсивно выполняет поиск всех контейнеров именования. На самом деле, используя методы расширения, мы не можем использовать FindControlRecursive метод к Control классу для сопровождения существующего FindControl метода.

Примечание.

Методы расширения — это функция, новая для C# 3.0 и Visual Basic 9, которые являются языками, которые отправляются с платформа .NET Framework версии 3.5 и Visual Studio 2008. Короче говоря, методы расширения позволяют разработчику создать новый метод для существующего типа класса с помощью специального синтаксиса. Дополнительные сведения об этой полезной функции см. в статье " Расширение функциональных возможностей базового типа с помощью методов расширения".

Чтобы создать метод расширения, добавьте новый файл в папку App_Code с именем PageExtensionMethods.vb. Добавьте метод расширения с именем FindControlRecursive , который принимает в качестве входных данных String параметр с именем controlID. Для правильной работы методов расширения важно, чтобы класс был помечен как a Module и что методы расширения должны быть префиксированы атрибутом <Extension()> . Кроме того, все методы расширения должны принимать в качестве первого параметра объект типа, к которому применяется метод расширения.

Добавьте следующий код в PageExtensionMethods.vb файл для определения этого Module и FindControlRecursive метода расширения:

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

В этом коде вернитесь к IDIssues.aspx классу кода страницы и закомментируйте текущие FindControl вызовы метода. Замените их вызовами Page.FindControlRecursive("controlID"). Что понятно о методах расширения, заключается в том, что они отображаются непосредственно в раскрывающихся списках IntelliSense. Как показано на рисунке 7, при вводе Page и нажатии периода FindControlRecursive метод включается в раскрывающийся список IntelliSense вместе с другими Control методами класса.

Методы расширения включены в раскрывающийся список IntelliSense

Рис. 07. Методы расширения включены в раскрывающийся список IntelliSense (щелкните, чтобы просмотреть изображение полного размера)

Введите следующий код в SubmitButton_Click обработчик событий, а затем протестируйте его, перейдя на страницу, введя возраст и нажав кнопку "Отправить". Как показано на рисунке 6, результирующий результат будет сообщением :"Вы возрастом!"

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

Примечание.

Так как методы расширения являются новыми для C# 3.0 и Visual Basic 9, если вы используете Visual Studio 2005, нельзя использовать методы расширения. Вместо этого необходимо реализовать FindControlRecursive метод в вспомогательном классе. Рик Штрахл имеет такой пример в своем блоге, ASP.NET Maser Pages и FindControl.

Шаг 4. Использование правильногоidзначения атрибута в клиентском скрипте

Как отмечалось в этом руководстве, атрибут отрисовки id веб-элемента управления часто используется в клиентском скрипте для программной ссылки на определенный элемент HTML. Например, следующий Код JavaScript ссылается на элемент HTML, id а затем отображает его значение в модальном окне сообщения:

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

Помните, что на страницах ASP.NET, не включающих контейнер именования, атрибут отрисованного HTML-элемента id идентичен значению свойства веб-элемента управления ID . Из-за этого заманчиво жесткого кода в значениях атрибутов в id код JavaScript. То есть, если вы знаете, что вы хотите получить доступ к Age веб-элементу управления TextBox через клиентский скрипт, сделайте это с помощью вызова document.getElementById("Age").

Проблема с этим подходом заключается в том, что при использовании главных страниц (или других элементов управления контейнера именования) отрисованный HTML id не является синонимом свойства веб-элемента управления ID . Ваше первое изменение может быть для посещения страницы через браузер и просмотра источника для определения фактического id атрибута. Когда вы знаете отрисованное id значение, его можно вставить в вызов для getElementById доступа к HTML-элементу, с которым необходимо работать с клиентским скриптом. Этот подход меньше идеала, так как некоторые изменения в иерархии элементов управления страницы или изменения ID свойств элементов управления именованием изменяют результирующий id атрибут, тем самым нарушая код JavaScript.

Хорошая новость заключается в том, что id отображаемое значение атрибута доступно в серверном коде с помощью свойства веб-элемента управленияClientID. Это свойство следует использовать для определения значения атрибута id , используемого в клиентском скрипте. Например, чтобы добавить функцию JavaScript на страницу, которая при вызове отображает значение Age TextBox в модальном окне сообщения, добавьте следующий код в Page_Load обработчик событий:

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)

Приведенный выше код вводит значение Age свойства TextBox ClientID в вызов getElementByIdJavaScript. Если вы посещаете эту страницу через браузер и просматриваете html-источник, вы найдете следующий код JavaScript:

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

Обратите внимание, как правильное id значение атрибута отображается ctl00_MainContent_Ageв вызове getElementById. Так как это значение вычисляется во время выполнения, оно работает независимо от последующих изменений в иерархии элементов управления страницами.

Примечание.

В этом примере JavaScript просто показано, как добавить функцию JavaScript, которая правильно ссылается на HTML-элемент, отображаемый серверным элементом управления. Чтобы использовать эту функцию, необходимо создать дополнительный JavaScript для вызова функции при загрузке документа или при выполнении определенных действий пользователя. Дополнительные сведения об этих и связанных разделах см. в статье "Работа с клиентским скриптом".

Итоги

Некоторые ASP.NET серверные элементы управления действуют как контейнеры именования, которые влияют на отрисованные id значения атрибутов элементов управления потомками, а также область элементов управления, холсты, созданные методом FindControl . Что касается главных страниц, то как главная страница, так и элементы управления ContentPlaceHolder называют контейнеры. Следовательно, нам нужно немного больше работать над программными ссылками на элементы управления на странице содержимого с помощью FindControl. В этом руководстве мы рассмотрели два метода: детализацию элемента управления ContentPlaceHolder и вызов его FindControl метода, а также развертывание собственной FindControl реализации, которая рекурсивно выполняет поиск по всем контейнерам именования.

В дополнение к контейнерам именования на стороне сервера вводятся вопросы, касающиеся ссылок на веб-элементы управления, также возникают проблемы на стороне клиента. Если контейнеры именования отсутствуют, значение свойства веб-элемента управления ID и отображаемое id значение атрибута совпадают. Но при добавлении контейнера именования отрисованный id атрибут включает как значения веб-элемента управления, так ID и контейнеры именования в родословную иерархию элементов управления. Эти проблемы, связанные с именованием, являются неисключающими, если вы используете свойство веб-элемента управления ClientID для определения значения отрисованного id атрибута в клиентском скрипте.

Счастливое программирование!

Дополнительные материалы

Дополнительные сведения о разделах, описанных в этом руководстве, см. в следующих ресурсах:

Об авторе

Скотт Митчелл, автор нескольких книг ASP/ASP.NET и основатель 4GuysFromRolla.com, работает с технологиями Microsoft Web с 1998 года. Скотт работает независимым консультантом, тренером и писателем. Его последняя книга Сэмс Учит себя ASP.NET 3,5 в 24 часах. Скотт можно получить по mitchell@4GuysFromRolla.com адресу или через свой блог.http://ScottOnWriting.NET

Особое спасибо

Эта серия учебников была проверена многими полезными рецензентами. Ведущие рецензенты для этого руководства были Zack Jones и Suchi Barnerjee. Хотите просмотреть мои предстоящие статьи MSDN? Если да, упадите меня линию в mitchell@4GuysFromRolla.com.