Пошаговое руководство. Руководства по специальным возможностям использования вложенных элементов управления ListView

В данном пошаговом руководстве описаны способы использования вложенных элементов управления ListView для создания сложных таблиц с данными, таким образом, чтобы сделать веб-страницу доступной для пользователей программ чтения с экрана. Эти способы позволяют выполнять следующие требования руководства по специальным возможностям для веб-содержимого (WCAG) версии 2.0:

  • Отделение структуры от представления (рекомендация WCAG 1.3).

Дополнительные сведения о специальных возможностях и WCAG 2.0 см. в разделе Специальные возможности Visual Studio и ASP.NET.

Для работы с этим пошаговым руководством необходимы следующие компоненты:

Это пошаговое руководство является четвертым в серии, демонстрирующей приемы, которые могут помочь обеспечить соответствие веб-сайта ASP.NET требованиям WCAG 2.0, предъявляемым к предоставлению специальных возможностей. В данной серии пошаговых руководств создается веб-приложение, которое можно использовать для просмотра параметров конфигурации ASP.NET. Если нужно выполнить все пошаговые руководства, перейдите к разделу Пошаговое руководство. Руководства по специальным возможностям использования элементов управления Image, Menu и AutoPostBack. Чтобы не проходить другие пошаговые руководства из этой серии, выполните альтернативные инструкции, приведенные для некоторых шагов. Одни и те же функции специальных возможностей будут показаны как при прохождении пошагового руководства в рамках серии, так и при его независимом прохождении.

Веб-страница, создаваемая в рамках этого пошагового руководства, отображает коллекцию элементов конфигурации из файла конфигурации machine.config. Таблица состоит из групп строк. У каждой группы строк есть заголовок, как показано на следующем рисунке.

Таблица HTML коллекции элементов

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

Примечание о безопасностиПримечание по безопасности

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

Проект веб-сайта Visual Studio с исходным кодом, прилагаемый к этому разделу, доступен на странице загрузка.

Данные для отображения в элементах управления ListView поступают из системы конфигурации ASP.NET. При выполнении следующей процедуры будет создан класс, получающий указанный объект Configuration, выбирающий коллекцию элементов из этого объекта и возвращающий коллекцию.

ПримечаниеПримечание

Этот раздел пошагового руководства не касается собственно функций специальных возможностей. Он просто содержит сведения для работы с элементом управления ListView.

Создание класса, который возвращает список разделов конфигурации

  1. Если веб-сайт не содержит папку App_Code, то в Обозревателе решений щелкните правой кнопкой мыши имя проекта и последовательно выберите пункты Добавить папку ASP.NET и App_Code.

  2. Щелкните правой кнопкой мыши пункт App_Code и выберите команду Добавить новый элемент.

  3. В разделе Установленные шаблоны выберите Visual Basic или Visual C#, а затем выберите Класс.

  4. В текстовом поле Имя введите ElementDataSource.vb или ElementDataSource.cs, а затем нажмите кнопку ОК.

  5. Удалите весь код в созданном файле класса.

  6. Вместо удаленного вставьте следующий код:

    
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Configuration;
    using System.Configuration;
    using System.ComponentModel;
    using System.Reflection;
    using System.Collections;
    
    /// <summary>
    /// Retrieves a list of properties for an element or for each
    /// item in an element collection. 
    /// </summary>
    public class ElementDataSource
    {
        public ElementDataSource()
        {
        }
    
        public List<ElementItemHeaderInfo> GetElements(
            string sectionName, 
            string elementName,
            string virtualPath,
            string site,
            string locationSubPath,
            string server)
        {
            List<ElementItemHeaderInfo> elementList = 
                new List<ElementItemHeaderInfo>();
    
            Configuration config = 
                WebConfigurationManager.OpenWebConfiguration(
                    virtualPath, site, locationSubPath, server);
    
            ConfigurationSection cs = config.GetSection(sectionName);
    
            Type sectionType = cs.GetType();
            System.Reflection.PropertyInfo reflectionElement = 
                sectionType.GetProperty(elementName);
            Object elementObject = reflectionElement.GetValue(cs, null);
    
            Type elementType = elementObject.GetType();
            System.Reflection.PropertyInfo reflectionProperty = 
                elementType.GetProperty("Count");
    
            if (reflectionProperty != null)
            {
                int elementCount = 
                    Convert.ToInt32(reflectionProperty.GetValue(
                        elementObject, null));
                for (int i = 0; i < elementCount; i++)
                {
                    ElementItemHeaderInfo ei = new ElementItemHeaderInfo();
                    ei.ItemName = String.Format(
                        "Item {0} of {1}", i + 1, elementCount);
                    ei.Index = i;
                    ei.Name = elementName;
                    ei.SectionName = sectionName;
                    elementList.Add(ei);
                }
            }
            else
            {
                ElementItemHeaderInfo ei = new ElementItemHeaderInfo();
                ei.Name = elementName;
                ei.ItemName = "Item 1 of 1";
                ei.SectionName = sectionName;
                elementList.Add(ei);
            }
            return elementList;
        }
    
        public List<ElementItemInfo> GetProperties(
            string sectionName, 
            string elementName, 
            int index,
            string virtualPath,
            string site,
            string locationSubPath,
            string server)
        {
            List<ElementItemInfo> elementItemList = 
                new List<ElementItemInfo>();
    
            Configuration config =
                WebConfigurationManager.OpenWebConfiguration(
                    virtualPath, site, locationSubPath, server);
    
            ConfigurationSection cs = config.GetSection(sectionName);
    
            Type sectionType = cs.GetType();
            System.Reflection.PropertyInfo reflectionElement = 
                sectionType.GetProperty(elementName);
            Object elementObject = reflectionElement.GetValue(cs, null);
    
            Type elementType = elementObject.GetType();
            System.Reflection.PropertyInfo reflectionProperty = 
                elementType.GetProperty("Count");
    
            int elementCount = reflectionProperty == null ? 0 : 
                Convert.ToInt32(
                    reflectionProperty.GetValue(elementObject, null));
    
            if (elementCount > 0)
            {
                int i = 0;
                ConfigurationElementCollection elementItems = 
                    elementObject as ConfigurationElementCollection;
                foreach (ConfigurationElement elementItem in elementItems)
                {
                    if (i == index)
                    {
                        elementObject = elementItem;
                    }
                    i++;
                }
            }
    
            Type reflectionItemType = elementObject.GetType();
            PropertyInfo[] elementProperties = 
                reflectionItemType.GetProperties();
    
            foreach (System.Reflection.PropertyInfo rpi in elementProperties)
            {
                if (rpi.Name != "SectionInformation" && 
                    rpi.Name != "LockAttributes" && 
                    rpi.Name != "LockAllAttributesExcept" && 
                    rpi.Name != "LockElements" && 
                    rpi.Name != "LockAllElementsExcept" && 
                    rpi.Name != "LockItem" &&
                    rpi.Name != "Item" &&
                    rpi.Name != "ElementInformation" && 
                    rpi.Name != "CurrentConfiguration")
                {
                    ElementItemInfo eii = new ElementItemInfo();
                    eii.Name = rpi.Name;
                    eii.TypeName = rpi.PropertyType.ToString();
                    string uniqueID = 
                        rpi.Name + index.ToString();
                    eii.UniqueID = uniqueID.Replace("/","");
                    ParameterInfo[] indexParms = rpi.GetIndexParameters();
                    if (rpi.PropertyType == typeof(IList) || 
                        rpi.PropertyType == typeof(ICollection) || 
                        indexParms.Length > 0)
                    {
                        eii.Value = "List";
                    }
                    else
                    {
                        object propertyValue = 
                            rpi.GetValue(elementObject, null);
                        eii.Value = propertyValue == null ? "" : 
                            propertyValue.ToString();
                    }
                    elementItemList.Add(eii);
                }
            }
            return elementItemList;
        }
    }
    
    public class ElementItemHeaderInfo
    {
        public string Name { get; set; }
        public string ItemName { get; set; }
        public string SectionName { get; set; }
        public string Value { get; set; }
        public int Index { get; set; }
    }
    
    public class ElementItemInfo
    {
        public string Name { get; set; }
        public string TypeName { get; set; }
        public string TypeNameUrl
        {
            get
            {
                return "http://msdn.microsoft.com/en-us/library/" + 
                    TypeName + ".aspx";
            }
        }
        public string Value { get; set; }
        public string UniqueID { get; set; }
    }
    
    
    

    Класс ElementDataSource содержит метод GetElements и метод GetProperties.

    Метод GetElements принимает параметры, которые определяют, какую коллекцию элементов следует получить. Он возвращает коллекцию объектов ElementItemHeaderInfo, один объект для каждого элемента к коллекции. Если в заданный элемент является единственным элементом, возвращается коллекция, которая содержит один элемент. Класс ElementItemHeaderInfo определяется сразу после класса SectionDataSource.

    Метод GetProperties принимает параметры, которые определяют, какой элемент в коллекции элементов следует получить. Он возвращает коллекцию объектов ElementItemInfo, один объект для каждого свойства заданного элемента в коллекции элементов. Класс ElementItemInfo определяется сразу после класса ElementItemHeaderInfo.

    Оба метода также принимают параметры, которые указывают, какой объект Configuration следует получить.

    ПримечаниеПримечание

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

В рамках этого раздела создается веб-страница, использующая элементы управления ObjectDataSource для предоставления данных вложенным элементам управления ListView. Один из элементов управления ObjectDataSource вызывает метод GetElements объекта ElementDataSource, созданного в предыдущей процедуре. Другой элемент управления ObjectDataSource вызывает метод GetProperties.

ПримечаниеПримечание

При использовании элемента управления ObjectDataSource или некоторых других методов для извлечения данных (например, запроса к базе данных с помощью элемента управления SqlDataSource или LinqDataSource), применяются аналогичные методы настройки элемента управления ListView.

Элементы управления ListView создают сложный HTML-элемент table, который содержит группу строк для каждого элемента в коллекции элементов. Каждая группа строк содержит строку заголовков столбцов, которая объединяет все столбцы и указывает какому элементу коллекции принадлежат следующие строки.

Чтобы облегчить доступ к таблице пользователей программ чтения с экрана, будут настроены элементы управления ListView, добавляющий в создаваемую им таблицу HTML следующие возможности:

  • элемент caption, который описывает назначение таблицы в коротком заголовке;

  • элемент summary, который содержит более длинное описание назначения таблицы;

  • элементы th, которые имеют атрибуты id, определяющие ячейки заголовков группы и ячейки заголовков столбцов.

  • элементы td, которые имеют атрибуты id, определяющие ячейки заголовков строк.

  • атрибуты headers в ячейках данных явным образом указывают группу, столбец и строку заголовков, к которым относятся.

ПримечаниеПримечание

Разметка HTML-кода сложной таблицы, которая используется в качестве примера в данном пошаговом руководстве, является одним из двух возможных подходов. Вместо использования атрибутов headers можно группировать строки в элементы tbody и указывать группу заголовков с помощью атрибута scope="rowgroup". Дополнительные сведения см. в разделе "11.4. Отображение таблиц для невизуальных пользовательских агентов" в спецификации HTML версии 4.01 на веб-сайте консорциума W3C.

При выполнении следующей процедуры будет создана веб-страница и добавлена разметка, отображающая список элементов во вложенных элементах управления ListView.

Создание веб-страницы, на которой отображается список разделов конфигурации

  1. В обозревателе решений щелкните правой кнопкой мыши имя проекта и выберите команду Добавить новый элемент.

    Откроется диалоговое окно Добавление нового элемента.

  2. В разделе Установленные шаблоны нажмите Visual Basic или Visual C#, а затем выберите пункт Веб-форма.

  3. В текстовом поле Имя введите Element.aspx.

  4. Установите флажок Поместить код в отдельный файл.

  5. Если данная страница добавляется в приложение браузера системы конфигурации, убедитесь, что флажок Выбрать главную страницу установлен. (если эта страница не добавляется в веб-сайт, созданный в разделе Пошаговое руководство. Руководства по специальным возможностям использования элементов управления Image, Menu и AutoPostBack, то главная страница может отсутствовать).

  6. Нажмите кнопку ОК.

  7. Если откроется диалоговое окно Выбор главной страницы, нажмите кнопку ОК. Определена только одна главная страница, и она уже будет выбрана.

  8. В директиве @ Page присвойте свойству Title значение "Configuration System Browser - Element Properties", как показано в следующем примере:

    
    <%@ Page Language="C#" AutoEventWireup="true" 
        Title="Configuration System Browser - Element Properties"
        CodeFile="Element.aspx.cs" MasterPageFile="~/Site.master" 
        Inherits="Element" %>
    
    
    

    Этот заголовок определяет сайт и страницу на сайте. Задание заголовка страницы является обязательным в соответствии с требованиями специальных возможностей.

  9. В элемент Content, который предназначен для элемента управления MainContentContentPlaceHolder, вставьте следующую разметку:

    
    <h2>
        <asp:Label ID="HeadingLabel" runat="server" 
            Text="Elements in Section [name]">
        </asp:Label>
    </h2> 
    
    
    

    (Если создается веб-страница, которая не является частью приложения браузера системы конфигурации, вставьте разметку между тегами <div> и </div>.)

    Данная разметка добавляет в элемент управления Label заголовок, чтобы этот заголовок можно было изменять программным образом. Обработчик событий PreRender для внешнего элемента управления ListView заменит строку "[name]" в заголовке фактическим именем элемента, отображаемого на странице.

  10. Под разметкой, вставленной на предыдущем этапе, добавьте следующую разметку:

    
    <asp:ObjectDataSource ID="OuterObjectDataSource" runat="server" 
        SelectMethod="GetElements" TypeName="ElementDataSource">
        <SelectParameters>
            <asp:QueryStringParameter Name="sectionName" 
                QueryStringField="Section" Type="String" 
                DefaultValue="system.web/webParts" />
            <asp:QueryStringParameter Name="elementName" 
                QueryStringField="Element" Type="String" 
                DefaultValue="Transformers" />
            <asp:SessionParameter Name="virtualPath" 
                SessionField="Path" Type="String" 
                DefaultValue="" />
            <asp:SessionParameter Name="site" 
                SessionField="Site" Type="String" 
                DefaultValue="" />
            <asp:SessionParameter Name="locationSubPath" 
                SessionField="SubPath" Type="String" 
                DefaultValue="" />
            <asp:SessionParameter Name="server" 
                SessionField="Server" Type="String" 
                DefaultValue="" />
        </SelectParameters>
    </asp:ObjectDataSource>
    
    
    

    Эта разметка создает элемент управления ObjectDataSource, который вызывает метод GetElements объекта ElementDataSource. Параметры, переданные методу GetElements, определяют коллекцию элементов и определенный объект Configuration, из которого извлекается раздел.

    Имя элемента и раздела в нем поступает из полей строки запроса с именами "Section" и "Element". Если строка запроса отсутствует, разделом по умолчанию является раздел "system.web/webParts", а коллекцией элементов по умолчанию — "Transformers". Значения других четырех параметров получаются из состояния сеанса. Значения помещаются в состояние сеанса другой страницей в приложении браузера системы конфигурации. Поэтому при реализации данного руководства в форме независимой веб-страницы будут использованы только значения, установленные по умолчанию.

  11. Под элементом управления ObjectDataSource вставьте следующую разметку:

    
    <div class="dataTable">
        <asp:ListView ID="ListView1" runat="server" 
            DataSourceID="OuterObjectDataSource"
            OnPreRender="ListView1_PreRender" 
            onitemdatabound="ListView1_ItemDataBound">
    
    
    

    Эта разметка создает элемент управления ListView в элементе div (закрывающие теги для этих элементов будут добавлены позднее). Это внешний элемент управления ListView. Он будет создавать структуру таблицы и строки заголовков групп. Внутренний элемент управления ListView будет создавать строки групп сведений.

    Разметка регистрирует обработчик для события PreRender элемента управления, чтобы объект EmptyDataTemplate, элемент caption HTML-таблицы и заголовок страницы можно было настраивать с помощью имени выбранной коллекции элементов конфигурации.

  12. Под разметкой, вставленной на предыдущем шаге, вставьте следующую разметку:

    
    <LayoutTemplate>
        <table class="listViewTable" width="100%"
            cellpadding="5" rules="all" border="1"
            summary="This table shows properties of items 
                contained in an element collection.">
            <caption runat="server" ID="ElementTableCaption">
                Properties of the [name] Element
            </caption>
            <tr style="">
                <th id="hdrName" axis="field">Name</th>
                <th id="hdrType" axis="field">Type</th>
                <th id="hdrValue" axis="field">Value</th>
            </tr>
            <tbody id="itemPlaceholder" runat="server"></tbody>
        </table>
    </LayoutTemplate>
    
    
    

    Эта разметка создает объект LayoutTemplate для элемента управления ListView. Объект LayoutTemplate указывает, что элемент управления будет создавать HTML-таблицу, имеющую следующие, относящиеся к специальным возможностям, функции:

    • элемент caption, который является коротким описанием содержимого таблицы;

    • атрибут summary, который является длинным описанием содержимого таблицы;

    • элементы th, которые имеют атрибуты id и атрибуты axis, определяющие ячейки заголовков столбцов.

  13. Под разметкой, вставленной на предыдущем шаге, вставьте следующую разметку:

    
    <ItemTemplate>
        <tr>
            <th colspan="3" 
                id="<%# GetElementHeaderID(Container) %>" axis="item">
                <asp:Label ID="Label1" runat="server" 
                    Text='<%# Eval("ItemName") %>' >
                </asp:Label>
            </th>
        </tr>
    
    
    

    Эта разметка создает первую часть объекта ItemTemplate для элемента управления ListView. Эта разметка указывает, что каждая строка данных будет создавать элемент tr, который содержит единственную ячейку, объединяющую все три столбца. Эта ячейка выступает в качестве заголовка для группы строк. В следующих шагах будет добавлена оставшаяся часть шаблона элемента, которая задает порядок создания других строк группы.

    Чтобы упростить создание специальных возможностей у элемента td есть атрибуты id и axis. Атрибут id однозначно определяет эту ячейку заголовка таблицы, поэтому строки сведений могут ссылаться на нее. Значение для атрибута id будет равным "hdrElementX", где "X" это номер группы. Например, hdrElement0 будет значением id в первой группе. Значение создается методом в коде страницы, который будет добавлен позже.

  14. Под разметкой, вставленной на предыдущем этапе, добавьте следующую разметку:

    
    <asp:ObjectDataSource ID="InnerObjectDataSource" runat="server" 
        SelectMethod="GetProperties" TypeName="ElementDataSource">
        <SelectParameters>
            <asp:Parameter Name="sectionName" Type="String" 
                DefaultValue="system.web/webParts" />
            <asp:Parameter Name="elementName" 
                Type="String" DefaultValue="Transformers" />
            <asp:Parameter Name="index" Type="Int32"
                DefaultValue="1" />
            <asp:SessionParameter Name="virtualPath" 
                SessionField="Path" Type="String" 
                DefaultValue="" />
            <asp:SessionParameter Name="site" 
                SessionField="Site" Type="String" 
                DefaultValue="" />
            <asp:SessionParameter Name="locationSubPath" 
                SessionField="SubPath" Type="String" 
                DefaultValue="" />
            <asp:SessionParameter Name="server" 
                SessionField="Server" Type="String" 
                DefaultValue="" />
        </SelectParameters>
    </asp:ObjectDataSource>
    
    
    

    Эта разметка создает элемент управления ObjectDataSource, который вызывает метод GetProperties объекта ElementDataSource. Параметры, переданные методу GetProperties, задают определенный элемент в коллекции элементов и определенный объект Configuration, из которого извлекается раздел.

    На более позднем этапе будет добавлен код, который задает параметры для метода GetProperties. Источником значений является строка заголовков, которая создается внешним элементом управления ListView.

  15. Под разметкой, вставленной на предыдущем шаге, вставьте следующую разметку:

    
        <asp:ListView ID="PropertiesListView" runat="server" 
            DataSourceID="InnerObjectDataSource">
            <LayoutTemplate>
                <tr id="itemPlaceHolder" runat="server"></tr>
            </LayoutTemplate>
            <ItemTemplate>
                <tr>
                    <td id="<%# GetPropertyHeaderID(Container) %>"
                        axis="property">
                        <%# Eval("Name") %>
                    </td>
                    <td headers="<%# GetColumnHeaderIDs(Container, "hdrType") %>">
                        <asp:HyperLink ID="HyperLink2" 
                            runat="server" 
                            Text='<%# Eval("TypeName") %>' 
                            NavigateUrl='<%# Eval("TypeNameUrl") %>'>
                        </asp:HyperLink>
                    </td>
                    <td headers="<%# GetColumnHeaderIDs(Container, "hdrValue") %>">
                        <%# Eval("Value") %>
                    </td>
                </tr>
            </ItemTemplate>
        </asp:ListView>
    </ItemTemplate>
    
    
    

    Эта разметка создает объект LayoutTemplate и объект ItemTemplate для внутреннего элемента управления ListView. Объект ItemTemplate указывает, что каждая строка данных будет создавать элемент tr, который содержит следующие функции, относящиеся к специальным возможностям:

    • Так как каждая строка представляет данные для элемента, а первая строка содержит имя элемента, элементы td, которые создаются в этом столбце, содержат атрибуты id и axis.

      Значение для атрибута id будет равным "hdrPropertyXY", где "X" это имя свойства, а "Y" это номер группы. Например, "hdrPropertyName0" будет значением id для свойства "Name" в первой группе. Значение создается методом в коде страницы, который будет добавлен позже.

    • Создаются элементы td второго и третьего столбцов, которые содержат атрибуты headers, указывающие три ячейки заголовка, которые относятся к каждой ячейке сведений.

      Например, атрибут headers для ячейки, которая содержит значение "RowToFieldTransformer" на рисунке ниже, содержит значение атрибута headers равное "hdrElement0 hdrPropertyName0 hdrValue". Эти значения указывают, что ячейка относится к заголовку группы Item 1 of 2 (Элемент 1 из 2), заголовку строки Name (Имя) и заголовку столбца Value (Значение). Значение атрибута headers создается методом в коде страницы, который будет добавлен позже.

    На следующем рисунке показан итоговый результат.

    Таблица HTML коллекции элементов
  16. Под разметкой, вставленной на предыдущем шаге, вставьте следующую разметку:

    
        <EmptyDataTemplate>
            <asp:Label ID="NoElementsLabel" runat="server" 
                Text="No information is available for the [element] element.">
            </asp:Label>
        </EmptyDataTemplate>
    </asp:ListView>
    </div>
    
    
    

    Эта разметка создает объект EmptyDataTemplate для внешнего элемента управления ListView и предоставляет закрывающие теги для внешнего элемента управления ListView и находящегося в нем объекта div. В случае, когда выбранная коллекция элементов конфигурации не содержит элементов, объект EmptyDataTemplate предоставляет настраиваемое сообщение.

    Страница Element.aspx будет иметь примерно следующий вид.

    
    <%@ Page Language="C#" AutoEventWireup="true" 
        Title="Configuration System Browser - Element Properties"
        CodeFile="Element.aspx.cs" MasterPageFile="~/Site.master" 
        Inherits="Element" %>
    
    <asp:Content ID="Content1" ContentPlaceHolderID="HeadContent" Runat="Server">
    </asp:Content>
    <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" Runat="Server">
        <h2>
            <asp:Label ID="HeadingLabel" runat="server" 
                Text="Elements in Section [name]">
            </asp:Label>
        </h2> 
        <asp:ObjectDataSource ID="OuterObjectDataSource" runat="server" 
            SelectMethod="GetElements" TypeName="ElementDataSource">
            <SelectParameters>
                <asp:QueryStringParameter Name="sectionName" 
                    QueryStringField="Section" Type="String" 
                    DefaultValue="system.web/webParts" />
                <asp:QueryStringParameter Name="elementName" 
                    QueryStringField="Element" Type="String" 
                    DefaultValue="Transformers" />
                <asp:SessionParameter Name="virtualPath" 
                    SessionField="Path" Type="String" 
                    DefaultValue="" />
                <asp:SessionParameter Name="site" 
                    SessionField="Site" Type="String" 
                    DefaultValue="" />
                <asp:SessionParameter Name="locationSubPath" 
                    SessionField="SubPath" Type="String" 
                    DefaultValue="" />
                <asp:SessionParameter Name="server" 
                    SessionField="Server" Type="String" 
                    DefaultValue="" />
            </SelectParameters>
        </asp:ObjectDataSource>
        <div class="dataTable">
            <asp:ListView ID="ListView1" runat="server" 
                DataSourceID="OuterObjectDataSource"
                OnPreRender="ListView1_PreRender" 
                onitemdatabound="ListView1_ItemDataBound">
                <LayoutTemplate>
                    <table class="listViewTable" width="100%"
                        cellpadding="5" rules="all" border="1"
                        summary="This table shows properties of items 
                            contained in an element collection.">
                        <caption runat="server" ID="ElementTableCaption">
                            Properties of the [name] Element
                        </caption>
                        <tr style="">
                            <th id="hdrName" axis="field">Name</th>
                            <th id="hdrType" axis="field">Type</th>
                            <th id="hdrValue" axis="field">Value</th>
                        </tr>
                        <tbody id="itemPlaceholder" runat="server"></tbody>
                    </table>
                </LayoutTemplate>
                <ItemTemplate>
                    <tr>
                        <th colspan="3" 
                            id="<%# GetElementHeaderID(Container) %>" axis="item">
                            <asp:Label ID="Label1" runat="server" 
                                Text='<%# Eval("ItemName") %>' >
                            </asp:Label>
                        </th>
                    </tr>
                    <asp:ObjectDataSource ID="InnerObjectDataSource" runat="server" 
                        SelectMethod="GetProperties" TypeName="ElementDataSource">
                        <SelectParameters>
                            <asp:Parameter Name="sectionName" Type="String" 
                                DefaultValue="system.web/webParts" />
                            <asp:Parameter Name="elementName" 
                                Type="String" DefaultValue="Transformers" />
                            <asp:Parameter Name="index" Type="Int32"
                                DefaultValue="1" />
                            <asp:SessionParameter Name="virtualPath" 
                                SessionField="Path" Type="String" 
                                DefaultValue="" />
                            <asp:SessionParameter Name="site" 
                                SessionField="Site" Type="String" 
                                DefaultValue="" />
                            <asp:SessionParameter Name="locationSubPath" 
                                SessionField="SubPath" Type="String" 
                                DefaultValue="" />
                            <asp:SessionParameter Name="server" 
                                SessionField="Server" Type="String" 
                                DefaultValue="" />
                        </SelectParameters>
                    </asp:ObjectDataSource>
                    <asp:ListView ID="PropertiesListView" runat="server" 
                        DataSourceID="InnerObjectDataSource">
                        <LayoutTemplate>
                            <tr id="itemPlaceHolder" runat="server"></tr>
                        </LayoutTemplate>
                        <ItemTemplate>
                            <tr>
                                <td id="<%# GetPropertyHeaderID(Container) %>"
                                    axis="property">
                                    <%# Eval("Name") %>
                                </td>
                                <td headers="<%# GetColumnHeaderIDs(Container, "hdrType") %>">
                                    <asp:HyperLink ID="HyperLink2" 
                                        runat="server" 
                                        Text='<%# Eval("TypeName") %>' 
                                        NavigateUrl='<%# Eval("TypeNameUrl") %>'>
                                    </asp:HyperLink>
                                </td>
                                <td headers="<%# GetColumnHeaderIDs(Container, "hdrValue") %>">
                                    <%# Eval("Value") %>
                                </td>
                            </tr>
                        </ItemTemplate>
                    </asp:ListView>
                </ItemTemplate>
                <EmptyDataTemplate>
                    <asp:Label ID="NoElementsLabel" runat="server" 
                        Text="No information is available for the [element] element.">
                    </asp:Label>
                </EmptyDataTemplate>
            </asp:ListView>
            </div>
    </asp:Content>
    
    
    

В следующей процедуре будет добавлен код метод, который будет выполнять перечисленные ниже функции.

  • привязка внутреннего элемента управления ListView к данным, соответствуют каждой строке, которая создается внешним элементом управления ListView;

  • размещение имени выбранной коллекции элементов конфигурации в заголовке страницы, элемента caption HTML-таблицы и объекта EmptyDataTemplate если отсутствуют возвращаемые данные;

  • конструирование уникальных значений атрибута id для заголовка элемента (группы) и заголовка свойства (строки);

  • конструирование значений для атрибутов headers.

Добавление кода для заполнения HTML-таблицы

  1. Откройте файл Element.aspx.vb или Element.aspx.cs.

  2. После операторов using (Imports в Visual Basic) добавьте следующий код:

    
    using System.Web.UI.HtmlControls;
    
    
    

    Этот оператор using или оператор Imports, которые требуются для класса, на который будут делаться ссылки на следующих этапах.

  3. Под методом Page_Load добавьте следующий код:

    
    protected void ListView1_ItemDataBound(
        object sender, ListViewItemEventArgs e)
    {
        ElementItemHeaderInfo ei = e.Item.DataItem 
            as ElementItemHeaderInfo;
    
        ObjectDataSource ods = (ObjectDataSource)e.Item.FindControl("InnerObjectDataSource");
        ods.SelectParameters["sectionName"].DefaultValue = ei.SectionName;
        ods.SelectParameters["elementName"].DefaultValue = ei.Name;
        ods.SelectParameters["index"].DefaultValue = ei.Index.ToString();
        //propertiesListView.DataBind();
    }
    
    
    

    Этот обработчик события ItemDataBound для внешнего элемента управления ListView получает текущий объект ElementItemHeaderInfo из внешнего элемента управления ListView и помещает значения данных из этого объекта в параметры внутреннего элемента управления ObjectDataSource.

  4. Под кодом, вставленным на предыдущем шаге, поместите следующий код:

    
    protected void ListView1_PreRender(object sender, EventArgs e)
    {
        string elementName =
            OuterObjectDataSource.SelectParameters["sectionName"].DefaultValue.ToString() +
            "/" +
            OuterObjectDataSource.SelectParameters["elementName"].DefaultValue.ToString();
        if (Request.QueryString["Section"] != null)
        {
            elementName = Request.QueryString["Section"] + "/" +
                Request.QueryString["Element"];
        }
    
        HeadingLabel.Text = HeadingLabel.Text.Replace("[name]", elementName);
    
        HtmlGenericControl tableCaption =
            ListView1.FindControl("ElementTableCaption")
            as System.Web.UI.HtmlControls.HtmlGenericControl;
        if (tableCaption != null)
        {
            tableCaption.InnerText = tableCaption.InnerText.Replace(
                    "[name]", elementName);
        }
    
        Label noElementsLabel = 
            ListView1.Controls[0].FindControl("NoElementsLabel") as Label;
        if (noElementsLabel != null)
        {
            noElementsLabel.Text = noElementsLabel.Text.Replace(
                "[name]", elementName);
        }
    }
    
    
    

    Этот обработчик событий PreRender внешнего элемента управления ListView получает выделенные имена раздела и элемента из строки запроса. Затем выполняется обновление заголовка страницы, элемента caption и объекта EmptyDataTemplate. Если строка запроса отсутствует, используются значения параметра по умолчанию для внешнего элемента управления ObjectDataSource.

  5. Под кодом, вставленным на предыдущем шаге, поместите следующий код:

    
    protected string GetElementHeaderID(ListViewItem item)
    {
        return "hdrElement" + item.DataItemIndex.ToString();
    }
    protected string GetPropertyHeaderID(ListViewItem item)
    {
        return "hdrProperty" +
            ((ElementItemInfo)item.DataItem).UniqueID;
    }
    
    
    

    Эти методы создают значения атрибута id для заголовка элемента (группы) и ячеек заголовка свойства (строки). Эти методы вызываются разметкой в ASPX-странице, когда создаются ячейки заголовка. Они также вызываются методом, добавляемом в следующем шаге, который используется для создания значений атрибута headers для ячеек со сведениями. В следующем примере показаны значения, которые предоставляются этими методами.

        <th colspan="3" id="hdrElement0" axis="item">
              <span id=...>Item 1 of 2</span>
        </th>
      </tr>
      <tr>
        <th id="hdrPropertyName0" axis="property" 
            class="rowHeading">
            Name
        </th>
        <td headers="hdrElement0 hdrPropertyName0 hdrType">
          <a id=... class="smallText" href=...>
              System.String
          </a>
        </td>
        <td headers="hdrElement0 hdrPropertyName0 hdrValue">
            RowToFieldTransformer
        </td>
      </tr>
    

    Следующая иллюстрация показывает строку заголовка и первую строку сведений под строкой заголовка, которая создана с помощью HTML-кода из предыдущего примера.

    Таблица HTML коллекции элементов
  6. Под кодом, вставленным на предыдущем шаге, поместите следующий код:

    
    protected string GetColumnHeaderIDs
        (ListViewDataItem item, string columnHeader)
    {
        string elementHeaderID =
            GetElementHeaderID
                ((ListViewItem)item.NamingContainer.NamingContainer);
    
        string propertyHeaderID = GetPropertyHeaderID(item);
    
        return string.Format("{0} {1} {2}",
            elementHeaderID, propertyHeaderID, columnHeader);
    }
    
    
    

    Этот метод создает значения атрибута headers для ячеек сведений. Атрибут headers создан из значений атрибута id из трех ячеек заголовка, отделенных пробелами. Для создания элемента id заголовка (группы) и элемента id заголовка свойства (строки) этот метод вызывает методы, которые были созданы в предыдущем шаге. Атрибуты id ячеек заголовка поля (столбца) никогда не меняются. Поэтому они передаются методу в параметре. В следующем примере показаны значения, которые предоставляются этими методами.

      <tr>
        <th id="hdrPropertyName0" axis="property" 
            class="rowHeading">
            Name
        </th>
        <td headers="hdrElement0 hdrPropertyName0 hdrType">
          <a id=... class="smallText" href=...>
              System.String
          </a>
        </td>
        <td headers="hdrElement0 hdrPropertyName0 hdrValue">
            RowToFieldTransformer
        </td>
      </tr>
    

    На следующем рисунке представлена первая строка сведений под строкой заголовка.

    Таблица HTML коллекции элементов

Теперь можно проверить, что таблица отображается правильно, и что для нее создается доступный HTML-код.

Тестирование страницы

  1. В обозревателе решений щелкните правой кнопкой мыши файл Element.aspx и выберите пункт Просмотр в браузере.

    Будет отображена таблица, перечисляющая элементы в коллекции элементов system.web/webParts/Transformers. Имена типов отображаются в виде гиперссылок, указывающих на документацию MSDN для определенного типа, как показано на следующем рисунке.

    Страница списка элементов браузера настройки

    Если веб-страница была создана в виде самостоятельной страницы, а не части приложения браузера системы конфигурации, заголовок и содержимое таблицы будут одинаковыми, однако заголовок окна или строка меню будут отсутствовать, а заголовок таблицы будет отображаться над самой таблицей.

  2. Просмотрите исходный код страницы в браузере.

    В следующем примере показаны элементы таблицы, которые были добавлены, чтобы улучшить доступность таблицы для пользователей программ чтения с экрана.

    <table class="listViewTable" width="100%"
        cellpadding="5" rules="all" border="1"
        summary="This table shows properties of items 
        contained in an element collection.">
      <caption id=...>
          Properties of the system.web/webParts/Transformers Element
      </caption>
      <tr style="">
          <th id="hdrName" axis="field">Name</th>
          <th id="hdrType" axis="field">Type</th>
          <th id="hdrValue" axis="field">Value</th>
      </tr>
      <tr>
        <th colspan="3" id="hdrElement0" axis="item">
              <span id=...>Item 1 of 2</span>
        </th>
      </tr>
      <tr>
        <th id="hdrPropertyName0" axis="property" 
            class="rowHeading">
            Name
        </th>
        <td headers="hdrElement0 hdrPropertyName0 hdrType">
          <a id=... class="smallText" href=...>
              System.String
          </a>
        </td>
        <td headers="hdrElement0 hdrPropertyName0 hdrValue">
            RowToFieldTransformer
        </td>
      </tr>
    ...
    </table>
    

В данном пошаговом руководстве использовались вложенные элементы управления ListView для создания HTML-таблицы, содержащей элементы и атрибуты, которые облегчают доступ к сложным табличным данным пользователям программ чтения с экрана. В остальных пошаговых руководствах этой серии демонстрируются другие подходы по обеспечению соответствия веб-сайта требованиям специальных возможностей. Следующим пошаговым руководством данной серии является Пошаговое руководство. Руководства по специальным возможностям использования элементов управления Label, Panel и проверяющих элементов управления. Также доступны приведенные ниже пошаговые руководства.

Показ: