Export (0) Print
Expand All

Walkthrough: Accessibility Guidelines for Using the ListView Control

.NET Framework 4

This walkthrough shows how to use the ASP.NET ListView control in ways that help make a Web page accessible for people who use screen reader software. These techniques can help you meet the following Web Content Accessibility Guidelines (WCAG) 2.0 guidelines:

  • Separating structure from presentation (WCAG guideline 1.3).

For more information about accessibility and WCAG 2.0, see Accessibility in Visual Studio and ASP.NET.

In order to run this walkthrough, you must have the following:

This walkthrough is the third in a series that demonstrates techniques that can help an ASP.NET Web site conform to WCAG 2.0 accessibility guidelines. This series of walkthroughs creates a Web application that you can use to view ASP.NET configuration settings. If you want to do all of the walkthroughs, start with Walkthrough: Accessibility Guidelines for Using Image Controls, Menu Controls, and AutoPostBack. If you do not want to complete other walkthroughs in the series, follow the alternate instructions that are provided for a few of the steps. The same accessibility features are illustrated whether you choose to complete the walkthrough as part of the series or independently.

The Web page that you create in this walkthrough displays elements from one section in the machine.config configuration file. You can specify the section in a query parameter. For more information about configuration files and the section groups, sections, and elements that they contain, see ASP.NET Configuration Files. However, it is not necessary to be familiar with the ASP.NET configuration file system to use these walkthroughs as illustrations of how to create Web pages that comply with accessibility guidelines.

Security noteSecurity Note

The configuration information that is displayed by the application that you create in these walkthroughs is useful for developers, but you should not display it in a production Web site for security reasons. Configuration settings might include sensitive information that should be shown only to authorized users.

A Visual Studio Web site project with source code is available to accompany this topic: Download.

The data to display in the ListView control that you use in this walkthrough comes from the ASP.NET configuration system. In the following procedure, you will create a class that retrieves a specified Configuration object, selects a section from that object, and returns a list of elements that are contained in the section.

NoteNote

This section of the walkthrough does not illustrate accessibility features specifically. It just provides data for you to work with in the GridView control.

To create a class that returns a list of configuration sections

  1. If the Web site does not have an App_Code folder, in Solution Explorer right-click the project name, click Add ASP.NET Folder, and then click App_Code.

  2. Right-click App_Code and then click Add New Item.

  3. Under Installed Templates, click Visual Basic or Visual C#, and then click Class.

  4. In the Name text box, enter SectionDataSource.vb or SectionDataSource.cs, and then click OK.

  5. Delete all the code in the new class file.

  6. In its place, insert the following code:

    
    Imports Microsoft.VisualBasic
    Imports System.Web.Configuration
    Imports System.Configuration
    Imports System.Reflection
    
    ''' <summary>
    ''' Retrieves a list of elements in a section. 
    ''' </summary>
    Public Class SectionDataSource
        Public Sub New()
        End Sub
        Public Function GetProperties(ByVal sectionName As String,
                                      ByVal virtualPath As String,
                                      ByVal site As String,
                                      ByVal locationSubPath As String,
                                      ByVal server As String) _
                                  As List(Of ElementInfo)
    
            Dim sectionList As New List(Of ElementInfo)()
    
            Dim config As Configuration =
                WebConfigurationManager.OpenWebConfiguration(
                    virtualPath, site, locationSubPath, server)
    
            Dim cs As ConfigurationSection = config.GetSection(sectionName)
            Dim sectionType As Type = cs.[GetType]()
            Dim sectionProperties As PropertyInfo() =
                sectionType.GetProperties()
    
            For Each rpi As PropertyInfo In sectionProperties
                If rpi.Name <> "SectionInformation" _
                    AndAlso rpi.Name <> "LockAttributes" _
                    AndAlso rpi.Name <> "LockAllAttributesExcept" _
                    AndAlso rpi.Name <> "LockElements" _
                    AndAlso rpi.Name <> "LockAllElementsExcept" _
                    AndAlso rpi.Name <> "LockItem" _
                    AndAlso rpi.Name <> "ElementInformation" _
                    AndAlso rpi.Name <> "CurrentConfiguration" Then
    
                    Dim ei As New ElementInfo()
                    ei.Name = rpi.Name
                    ei.TypeName = rpi.PropertyType.ToString()
    
                    If rpi.PropertyType.BaseType _
                        Is GetType(ConfigurationElement) Then
    
                        ei.NameUrl = ("Element.aspx?Section=" _
                                      & sectionName & "&Element=") + rpi.Name
                        ei.Value = "Element"
                    ElseIf rpi.PropertyType.BaseType _
                        Is GetType(ConfigurationElementCollection) Then
    
                        ei.NameUrl = ("Element.aspx?Section=" _
                                      & sectionName & "&Element=") + rpi.Name
                        ei.Value = "Element Collection"
                    Else
                        Dim indexParms As ParameterInfo() =
                            rpi.GetIndexParameters()
                        If rpi.PropertyType Is GetType(IList) _
                            OrElse rpi.PropertyType Is GetType(ICollection) _
                            OrElse indexParms.Length > 0 Then
    
                            ei.Value = "Collection"
                        Else
                            Dim propertyValue As Object =
                                rpi.GetValue(cs, Nothing)
                            ei.Value = IIf(propertyValue Is Nothing,
                                           "", propertyValue.ToString())
                        End If
                    End If
                    sectionList.Add(ei)
                End If
            Next
            Return sectionList
        End Function
    End Class
    
    Public Class ElementInfo
        Private _Name As String
        Public Property Name() As String
            Get
                Return _Name
            End Get
            Set(ByVal value As String)
                _Name = value
            End Set
        End Property
        Private _ItemName As String
        Public Property ItemName() As String
            Get
                Return _ItemName
            End Get
            Set(ByVal value As String)
                _ItemName = value
            End Set
        End Property
        Private _SectionName As String
        Public Property SectionName() As String
            Get
                Return _SectionName
            End Get
            Set(ByVal value As String)
                _SectionName = value
            End Set
        End Property
        Private _NameUrl As String
        Public Property NameUrl() As String
            Get
                Return _NameUrl
            End Get
            Set(ByVal value As String)
                _NameUrl = value
            End Set
        End Property
        Private _TypeName As String
        Public Property TypeName() As String
            Get
                Return _TypeName
            End Get
            Set(ByVal value As String)
                _TypeName = value
            End Set
        End Property
        Public ReadOnly Property TypeNameUrl() As String
            Get
                Return "http://msdn.microsoft.com/en-us/library/" & TypeName & ".aspx"
            End Get
        End Property
        Private _Value As String
        Public Property Value() As String
            Get
                Return _Value
            End Get
            Set(ByVal value As String)
                _Value = value
            End Set
        End Property
        Private _Index As Integer
        Public Property Index() As Integer
            Get
                Return _Index
            End Get
            Set(ByVal value As Integer)
                _Index = value
            End Set
        End Property
    End Class
    
    
    

    The SectionDataSource class contains a GetProperties method that accepts parameters that specify which Configuration object to retrieve and which section to select. The method returns a collection of ElementInfo objects. The ElementInfo class is defined immediately following the SectionDataSource class.

    NoteNote

    The Configuration Browser application used in these walkthroughs includes redundant data source code that could have been refactored into common classes and methods. However, the code was duplicated to make sure that each walkthrough can be done separately. This approach also minimizes the number of steps in parts of the walkthrough that are not directly relevant to accessibility.

In this section you create a Web page that uses an ObjectDataSource control to provide data to a ListView control. The ObjectDataSource control calls the GetProperties method of the SectionDataSource object that you created in the previous procedure.

NoteNote

Whether you are using the ObjectDataSource or some other method to retrieve data (for example, a database query using the SqlDataSource control or the LinqDataSource control), the methods for configuring the ListView control are the same.

The ListView control creates an HTML table element that has one row for each element. Each row has the name of the element in one column and the name of the class that is used to store settings for it in the second column.

To make the table more accessible for people who use screen reader software, you will configure the ListView control to include the following features in the HTML table that it generates:

  • A caption element describes the purpose of the table in a short heading.

  • A summary element provides a longer description of the purpose of the table.

  • thead and tbody elements distinguish the heading and body sections of the table.

  • th elements that have scope="col" attributes identify column header cells.

  • td elements that have scope="row" attributes identify row header cells.

In the following procedure you will create a Web page and add markup that displays the list of elements in a ListView control.

To create a Web page that displays a list of configuration sections

  1. In Solution Explorer, right-click the project name and then click Add New Item.

    The Add New Item dialog box appears.

  2. Under Installed Templates, click Visual Basic or Visual C#, and then click Web Form.

  3. In the Name text box, enter Section.aspx.

  4. Make sure that the Place code in separate file check box is checked.

  5. If you are adding this page to the Configuration System Browser application, make sure that the Select master page check box is checked. (If you are not adding this page to the Web site that you create in Walkthrough: Accessibility Guidelines for Using Image Controls, Menu Controls, and AutoPostBack, there might not be a master page.)

  6. In the Add New Item dialog box, click OK.

  7. If the Select a Master Page dialog box appears, click OK. There is only one master page, and it will already be selected.

  8. In the @ Page directive, set the Title property to Configuration System Browser - Elements in a Section, as shown in the following example:

    
    <%@ Page  Language="VB" AutoEventWireup="true" 
        Title="Configuration System Browser - Elements in a Section"
        CodeFile="Section.aspx.vb"  MasterPageFile="~/Site.master" 
        Inherits="Section" %>
    
    
    

    This title identifies the site and the page in the site. Setting the page title is required by accessibility guidelines.

  9. Inside the Content element that is for the MainContent ContentPlaceHolder control, insert the following markup:

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

    (If you creating a Web page that is not part of the Configuration System Browser application, insert the markup between the <div> and </div> tags.)

    This markup adds a heading in a Label control so that the heading can be changed programmatically. The PreRender event handler for the outer ListView control will replace the string "[name]" in the heading with the actual name of the section that the page is displaying.

  10. Below the markup that you inserted in the previous step, insert the following markup:

    
    <asp:ObjectDataSource ID="ObjectDataSource1" runat="server" 
        SelectMethod="GetProperties" TypeName="SectionDataSource">
        <SelectParameters>
            <asp:QueryStringParameter Name="sectionName" 
                QueryStringField="Section" Type="String" 
                DefaultValue="system.web/httpHandlers" />
            <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>
    
    
    

    This markup creates an ObjectDataSource control that calls the GetProperties method of the SectionDataSource object. Parameters that are passed to the GetProperties method specify the name of the section and the specific Configuration object from which to retrieve the section.

    The section name is retrieved from a query string field that is named "Section". If there is no query string, the default section is "system.web/httpHandlers". Values for the other four parameters are retrieved from session state. Values are placed in session state by another page in the Configuration System Browser application. Therefore, only the default values will be used if you are creating this walkthrough as an independent Web page.

  11. Below the ObjectDataSource control, insert the following markup:

    
    <div class="dataTable">
        <asp:ListView ID="ListView1" runat="server" 
            DataSourceID="ObjectDataSource1" 
            onprerender="ListView1_PreRender" >
    
    
    

    This markup creates a ListView control in a div element (you will add the closing tags for these elements later). The markup registers a handler for the control's PreRender event so that the EmptyDataTemplate object and the caption element of the HTML table can be customized using the name of the selected configuration section.

  12. Below the markup that you inserted in the preceding step, insert the following markup:

    
    <LayoutTemplate>
        <table class="listViewTable" width="100%"
            cellpadding="5" rules="all" border="1" 
            summary="This table shows elements that are 
                contained in the specified section.">
            <caption runat="server" ID="ElementTableCaption">
                Elements in the system.web/httpHandlers Section
            </caption>
            <thead>
                <tr style="">
                    <th scope="col">Name</th>
                    <th scope="col">Type</th>
                    <th scope="col">Value</th>
                </tr>
            </thead>
            <tbody>
                <tr id="itemPlaceholder" runat="server"></tr>
            </tbody>
        </table>
    </LayoutTemplate>
    
    
    

    This markup creates a LayoutTemplate object for the ListView control. The LayoutTemplate object specifies that the control will generate an HTML table that has the following features that relate to accessibility:

    • The caption element is a short description of the table's contents.

    • The summary attribute is a longer description of the table's contents.

    • thead and tbody elements distinguish the heading and body sections of the table.

    • th elements have scope="col" attributes that identify column-header cells.

  13. Below the markup that you inserted in the preceding step, insert the following markup:

    
    <ItemTemplate>
        <tr>
            <td scope="row" class="rowHeading">
                <asp:HyperLink ID="HyperLink1" runat="server" 
                    Text='<%# Eval("Name") %>' 
                    NavigateUrl='<%# Eval("NameUrl") %>'>
                </asp:HyperLink>
            </td>
            <td>
                <asp:HyperLink ID="HyperLink2" runat="server" 
                    Text='<%# Eval("TypeName") %>' 
                    NavigateUrl='<%# Eval("TypeNameUrl") %>'>
                </asp:HyperLink>
            </td>
            <td>
                <asp:Label ID="Label1" runat="server" 
                    Text='<%# Eval("Value") %>' >
                </asp:Label>
            </td>
        </tr>
    </ItemTemplate>
    
    
    

    This markup creates an ItemTemplate object for the ListView control. The ItemTemplate object specifies that each data row will generate a tr element. To help with accessibility, cells in the first column are generated using scope="row" attributes because the first column contains the element name and functions as a row header.

  14. Below the markup that you inserted in the preceding step, insert the following markup:

    
            <EmptyDataTemplate>
                <asp:Label ID="NoElementsLabel" runat="server" 
                    Text="The [name] section 
                        does not contain any elements.">
                </asp:Label>
            </EmptyDataTemplate>
        </asp:ListView>
    </div>
    
    
    

    This markup creates an EmptyDataTemplate object for the ListView control and provides the closing tags for the ListView control and the div element that it is in. The EmptyDataTemplate object provides a custom message in case the selected configuration section does not contain any elements.

Updating the Table Caption and the EmptyDataTemplate Object

In the following procedure you will add code that puts the name of the selected

configuration section in the caption element of the HTML table. You also define what happens if no data is returned.

To update the caption and the EmptyDataTemplate object

  1. Open the SectionGroup.aspx.vb or SectionGroup.aspx.cs file.

  2. At the end of the using statements (Imports in Visual Basic) add the following code:

    
    Imports System.Web.UI.HtmlControls
    
    
    

    This using or Imports statement is needed for a class that you will reference in the following steps.

  3. Below the Page_Load method, add the following code:

    
    Protected Sub ListView1_PreRender(ByVal sender As Object,
                                      ByVal e As EventArgs)
    
        Dim s As String =
            ObjectDataSource1.SelectParameters(
                "sectionName").DefaultValue.ToString()
        If Request.QueryString("Section") IsNot Nothing Then
            s = Request.QueryString("Section")
        End If
        HeadingLabel.Text = HeadingLabel.Text.Replace("[name]", s)
    
        Dim tableCaption As HtmlGenericControl =
            TryCast(ListView1.FindControl("ElementTableCaption"), 
                System.Web.UI.HtmlControls.HtmlGenericControl)
        If tableCaption IsNot Nothing Then
            tableCaption.InnerText =
                tableCaption.InnerText.Replace("[name]", s)
        End If
    
        Dim noElementsLabel As Label =
            TryCast(ListView1.Controls(0).FindControl("NoElementsLabel"), 
                Label)
        If noElementsLabel IsNot Nothing Then
            noElementsLabel.Text =
                noElementsLabel.Text.Replace("[name]", s)
    
        End If
    End Sub
    
    
    

    This code puts the currently selected configuration section name in the following places:

    • The page heading.

    • The caption element of the HTML table if it is generated (the table is only generated if the selected configuration section has elements).

    • Markup that is generated from the EmptyDataTemplate object. This template generates HTML only if the selected configuration section does not have any elements.

You can now test to verify that the table displays correctly and that accessible HTML is generated for it.

To test the page

  1. In Solution Explorer, right-click Section.aspx and then click View in Browser.

    You see a table that lists the elements in the system.web/httpHandlers section. Element names are displayed as hyperlinks that point to a page that you will create if you run a different walkthrough in this series (Walkthrough: Accessibility Guidelines for Using the ListView Control).

    Section type names are displayed as hyperlinks that point to the MSDN documentation for the indicated type, as shown in the following illustration:

    Configuration Browser - ELements in a Section

    If you created the Web page as an independent page instead of as part of the Configuration System Browser application, the heading and the table contents are the same, but there will be no title bar or menu bar, and the table caption appears above the table.

  2. In the browser, view the page source.

    The following example shows the table elements that were added to enhance the table's accessibility for people who use screen readers.

    <table class="listViewTable" width="100%"
        cellpadding="5" rules="all" border="1" 
        summary="This table shows elements that are 
            contained in the specified section.">
        <caption id="ctl00_MainContent_ListView1_ElementTableCaption">
            Elements in the system.web/httpHandlers Section
        </caption>
        <thead>
            <tr style="">
                <th scope="col">Name</th>
                <th scope="col">Type</th>
                <th scope="col">Value</th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <th scope="row" class="rowHeading">
                    <a id=...>Handlers</a>
                </th>
                <td>
                    <a id=...>
                        System.Web...HttpHandlerActionCollection
                    </a>
                </td>
                <td>
                    <span id=...>Element Collection</span>
                </td>
            </tr>
        </tbody>
    </table>
    

In this walkthrough you used a ListView control to generate HTML elements and attributes that help make tabular data accessible for people who use screen reader software. Other walkthroughs in this series demonstrate other techniques that help your Web site conform to accessibility guidelines. The next walkthrough in the series is Walkthrough: Accessibility Guidelines for Using Nested ListView Controls. The other walkthroughs in the series are the following:

Community Additions

ADD
Show:
© 2014 Microsoft