Share via


Эффективное использование ASP.NET WebForms 4.0: генерация идентификаторов

Одним из нововведений в четвертой версии ASP.NET стала возможность контролировать формирование идентификаторов элементов разметки на клиенте. Ранее фреймворк задавал уникальный идентификатор для каждого элемента. Это приводило к тому, что определяемые вами идентификаторы преображались во что-то похожее на это: ctl00_MasterPageBody_ctl01_Textbox1.

Проблема

Модификация идентификаторов на клиентской стороне отлично работает, когда требуется обеспечить уникальность идентификаторов для каждого элемента, но работа с такими идентификаторами могла расстроить любого, кому приходилось работать с клиентскими скриптами. И если вы работали с ASP.NET, то скорее всего сталкивались с этими трудностями. Проблема состоит в том, что во время исполнения скрипта вы не можете точно знать каким может быть идентификатор, что затрудняет написание клиентских скриптов. Кроме того, любые модификации на странице, добавление или удаление элементов управления, могут привести к генерации других идентификаторов.

Решение в старом стиле

Если вы работали с ASP.NET достаточное время, то знаете, как решать описанную проблему. Каждый элемент управления содержит свойство только для чтения ClientID, которое определяет клиентский идентификатор для этого элемента. Вы можете использовать это свойство в своем серверном коде при динамическом добавлении скриптов или, в более распространенном случае, использовать его в коде разметки (стиль старого ASP) для реализации скриптов на стороне клиента.

<script type="text/javascript"> function DoSomething(){ alert('<%= Control.ClientID %>'); }< /script>

Решение в ASP.NET 4.0

Реализация поддержки уникальности идентификаторов на стороне клиента с ростом скриптов приводила к тому, что код содержал все больше ухищрений. С такой системой не существовало нормального пути для реализации работы множества элементов управления с большим количеством внешних файлов скриптов. Кроме того, должен был бы существовать какой-нибудь механизм для разработчика контролировать эту систему назначения уникальных идентификаторов. Разработчики любят все контролировать, нужно им это или нет, такова наша природа :). Решение, которое предлагается, содержит четыре режима, которые разработчик может использовать для полного контроля над системой идентификаторов. Свойство ID элементов управления модифицируется исходя из установленного режима ClientIDMode, и, соответственно, формирует идентификатор на стороне клиента.

Режимы и что они делают

Для каждого элемента управления (включая Page и MasterPage ) добавлено новое свойство, названное ClientIDMode, которое используется для выбора механизма формирования клиентского ID.

<asp:Label ID="Label1" runat="server" ClientIDMode="[Mode Type]" />

Режимы

  • AutoID: режим по умолчанию, когда ClientIDMode не установлен нигде в дереве элементов управления. Этот режим идентичен тому, как формировался идентификатор в версии 2.0 фреймворка (как и в 3.0 и 3.5). Этот режим будет генерировать ID похожие на ctl00_MasterPageBody_ctl01_Textbox1.
  • Inherit (наследуемый): этот режим по умолчанию для любого элемента управления. В этом случае для получения режима используется значение ClientIDMode у родительского элемента. Вам не нужно устанавливать это свойство для каждого элемента управления, поскольку оно установлено по умолчанию, использовать его можно в случае, если необходимо изменить механизм для элемента с какого-то режима на режим присущий родительскому.
  • Static (статический): этот режим делает именно то, о чем вы подумали, он задает статический ID. Это означает, что то что вы укажите для ID элемента управления, то и будет использовано для идентификатора на стороне клиента. Внимание, это означает, что в случае если статический ClientIDMode используется в элементе управления с повторяющимися элементами, то разработчик несет ответственность за самостоятельное обеспечение уникальности идентификаторов на стороне клиента.
  • Predictable (предсказуемый): этот режим используется, когда требуется обеспечить уникальность, но сделать это предсказуемо. Наиболее распространенным примером для использования этого режима могут стать элементы управления с привязкой к источникам данных. В этом случае, Фреймворк пройдет всю иерархию элементов управления, присвоив каждому элементу (кроме статических элементов) префикс в виде ID родительского элемента. В случае, когда элемент управления расположен внутри элемента управления с привязкой к данным, к ID добавится суффикс в виде некоторых значений. Для управления этими значениями используется свойство ClientIDRowSuffix (смотрите примеры). Этот режим будет генерировать значения идентификаторов похожих на Gridview1_Label1_0.

Примеры

Режим AutoID генерирует ID на клиентской стороне так же, как это делал фреймворк с версии 2.0.

<asp :TextBox ID ="txtEcho" runat ="server" Width ="65%" ClientIDMode="AutoID" />

Результат

<input id="ctl00_MasterPageBody_ctl00_txtEcho" style="width: 65%" name="ctl00$MasterPageBody$ctl00$txtEcho" />

Режим Static наиболее простой из всех режимов ClientIDMode, который позволяет вам получить ID на клиентской стороне таким же какой ID был задан для серверного элемента управления. Снова требуется предупредить, что в случае если статический ClientIDMode используется в элементе управления с повторяющимися элементами, то ответственность на формирование уникальности идентификаторов на стороне клиента ложится на разработчика.

<asp:TextBox ID="txtEcho2" runat="server" Width="65%" ClientIDMode="Static" />

Результат

<input id="txtEcho2" style="width: 65%" name="ctl00$MasterPageBody$ctl00$txtEcho2" />

Режим Predictable бьет прямо в сердце проблемы. Ранее фреймворк генерировал уникальные ID, чтобы избежать совпадения идентификаторов, например в самом распространенном случае — внутри элементов управления с привязкой к источникам данных. Хотя предсказуемый режим разработан именно для таких моментов, он может быть использован и в других случаях. Для использования предсказуемого режима есть три варианта, каждый из которых указывается через свойство ClientIDRowSuffix, которое указывает какой суффикс использовать для каждого элемента. ClientIDRowSuffix использует значения из коллекции ключевых полей элемента управления, так что если элемент управления не содержит такой коллекции, то это свойство не будет работать. В случае если это свойство не установлено или не доступно, то для суффикса будет использовано числовое значение индекса элемента.

1. ClientIDRowSuffix не определен, что может быть использовано когда у элемента управления нет коллекции ключевых полей, например для Repeater. Обратите внимание, что фреймворк присваивает элементам префикс в виде ID предка, а суффикс в виде простого порядкового значения.

<asp:GridView ID="EmployeesNoSuffix" runat="server" AutoGenerateColumns="false" ClientIDMode="Predictable" > <Columns> <asp:TemplateField HeaderText="ID"> <ItemTemplate> <asp:Label ID="EmployeeID" runat="server" Text='<%# Eval("ID") %>' /> </ItemTemplate> </asp:TemplateField> <asp:TemplateField HeaderText="Name"> <ItemTemplate> <asp:Label ID="EmployeeName" runat="server" Text='<%# Eval("Name") %>' /> </ItemTemplate> </asp:TemplateField> </Columns></asp:GridView>

Результат:

<table id="EmployeesNoSuffix" style="border-collapse: collapse" cellspacing="0" rules="all" border="1"> <tbody> <tr> <th scope="col">ID</th> <th scope="col">Name</th> </tr> <tr> <td><span id="EmployeesNoSuffix_EmployeeID_0">1</span></td> <td><span id="EmployeesNoSuffix_EmployeeName_0">EmployeeName1</span></td> </tr> ... <tr> <td><span id="EmployeesNoSuffix_EmployeeID_8">9</span></td> <td><span id="EmployeesNoSuffix_EmployeeName_8">EmployeeName9</span></td> </tr> </tbody></table>

2. ClientIDRowSuffix указан, в этом случае производится поиск значений ключевых полей для значений суффиксов.

<asp:GridView ID="EmployeesSuffix" runat="server" AutoGenerateColumns="false" ClientIDMode="Predictable" ClientIDRowSuffix="ID" > <Columns> <asp:TemplateField HeaderText="ID"> <ItemTemplate> <asp:Label ID="EmployeeID" runat="server" Text='<%# Eval("ID") %>' /> </ItemTemplate> </asp:TemplateField> <asp:TemplateField HeaderText="Name"> <ItemTemplate> <asp:Label ID="EmployeeName" runat="server" Text='<%# Eval("Name") %>' /> </ItemTemplate> </asp:TemplateField> </Columns></asp:GridView>

результат

<table id="EmployeesSuffix" style="border-collapse: collapse" cellspacing="0" rules="all" border="1"> <tbody> <tr> <th scope="col">ID</th> <th scope="col">Name</th> </tr> <tr> <td><span id="EmployeesSuffix_EmployeeID_1">1</span></td> <td><span id="EmployeesSuffix_EmployeeName_1">EmployeeName1</span></td> </tr> ... <tr> <td><span id="EmployeesSuffix_EmployeeID_9">9</span></td> <td><span id="EmployeesSuffix_EmployeeName_9">EmployeeName9</span></td> </tr> </tbody></table>

3. ClientIDRowSuffix указано, но вместо одного значения задано несколько. Приводит к тому, что суффикс будет состоять из нескольких значений.

<asp:GridView ID="EmployeesCompSuffix" runat="server" AutoGenerateColumns="false" ClientIDMode="Predictable" ClientIDRowSuffix="ID, Name" > <Columns> <asp:TemplateField HeaderText="ID"> <ItemTemplate> <asp:Label ID="EmployeeID" runat="server" Text='<%# Eval("ID") %>' /> </ItemTemplate> </asp:TemplateField> <asp:TemplateField HeaderText="Name"> <ItemTemplate> <asp:Label ID="EmployeeName" runat="server" Text='<%# Eval("Name") %>' /> </ItemTemplate> </asp:TemplateField> </Columns></asp:GridView>

Результат

<table id="EmployeesCompSuffix" style="border-collapse: collapse" cellspacing="0" rules="all" border="1"> <tbody> <tr> <th scope="col">ID</th> <th scope="col">Name</th> </tr> <tr> <td><span id="EmployeesCompSuffix_EmployeeID_1_EmployeeName1">1</span></td> <td><span id="EmployeesCompSuffix_EmployeeName_1_EmployeeName1">EmployeeName1</span></td> </tr> ... <tr> <td><span id="EmployeesCompSuffix_EmployeeID_9_EmployeeName9">9</span></td> <td><span id="EmployeesCompSuffix_EmployeeName_9_EmployeeName9">EmployeeName9</span></td> </tr> </tbody></table>