Walkthrough: Accessibility Guidelines for Using the GridView Control

This walkthrough shows how to use the GridView 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 guideline:

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

Prerequisites

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

The Configuration System Browser Application

This walkthrough is the second in a series that demonstrates techniques that can help an ASP.NET Web site conform to accessibility guidelines. In this series of walkthroughs, you create a Web application that you can use to view ASP.NET configuration settings. If you want to run all 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 sections from one section group in the machine.config configuration file. You can specify the section group 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.

Creating a Data Source

The data to display in the GridView control 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 group from that object, and returns a list of sections that are contained in the section group.

Note

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 SectionGroupDataSource.vb or SectionGroupDataSource.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
    
    ''' <summary> 
    ''' Retrieves a list of sections in a section group.  
    ''' </summary> 
    Public Class SectionGroupDataSource
        Public Sub New()
        End Sub 
    
        Public Function GetSections(ByVal sectionGroupName As String,
                                    ByVal virtualPath As String,
                                    ByVal site As String,
                                    ByVal locationSubPath As String,
                                    ByVal server As String) _
                                As List(Of SectionInfo)
    
            Dim sectionList As New List(Of SectionInfo)()
    
            Dim config As Configuration =
                WebConfigurationManager.OpenWebConfiguration(
                    virtualPath, site, locationSubPath, server)
    
            Dim csg As ConfigurationSectionGroup =
                config.GetSectionGroup(sectionGroupName)
    
            For Each section As ConfigurationSection In csg.Sections
                Dim si As New SectionInfo()
                si.Name = section.SectionInformation.Name
                si.NameUrl = "Section.aspx?Section=" _
                    & section.SectionInformation.SectionName
    
                Dim i As Integer =
                    section.SectionInformation.Type.IndexOf(",")
                si.TypeName =
                    section.SectionInformation.Type.Substring(0, i)
                sectionList.Add(si)
            Next 
    
            For Each group As ConfigurationSectionGroup In csg.SectionGroups
                Dim si As New SectionInfo()
                si.Name = group.Name
                si.NameUrl = "SectionGroup.aspx?SectionGroup=" _
                    & group.SectionGroupName
                si.TypeName =
                    "System.Configuration.ConfigurationSectionGroup"
                sectionList.Add(si)
            Next 
            Return sectionList
        End Function 
    End Class 
    
    Public Class SectionInfo
        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 _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 "https://msdn.microsoft.com/en-us/library/" _
                    & TypeName & ".aspx" 
            End Get 
        End Property 
    End Class
    
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Configuration;
    using System.Configuration;
    
    /// <summary> 
    /// Retrieves a list of sections in a section group.  
    /// </summary> 
    public class SectionGroupDataSource
    {
        public SectionGroupDataSource()
        {
        }
    
        public List<SectionInfo> GetSections(
            string sectionGroupName, 
            string virtualPath, 
            string site, 
            string locationSubPath, 
            string server)
        {
            List<SectionInfo> sectionList = new List<SectionInfo>();
    
            Configuration config = WebConfigurationManager.OpenWebConfiguration(
                virtualPath, site, locationSubPath, server);
    
            ConfigurationSectionGroup csg = 
                config.GetSectionGroup(sectionGroupName);
    
            foreach (ConfigurationSection section in csg.Sections)
            {
                SectionInfo si = new SectionInfo();
                si.Name = section.SectionInformation.Name;
                si.NameUrl = "Section.aspx?Section=" + 
                    section.SectionInformation.SectionName;
    
                int i = section.SectionInformation.Type.IndexOf(",");
                si.TypeName = section.SectionInformation.Type.Substring(0, i);
                sectionList.Add(si);
            }
    
            foreach (ConfigurationSectionGroup group in csg.SectionGroups)
            {
                SectionInfo si = new SectionInfo();
                si.Name = group.Name;
                si.NameUrl = 
                    "SectionGroup.aspx?SectionGroup=" + group.SectionGroupName;
                si.TypeName = 
                    "System.Configuration.ConfigurationSectionGroup";
                sectionList.Add(si);
            }
            return sectionList;
        }
    }
    
    public class SectionInfo
    {
        public string Name { get; set; }
        public string NameUrl { get; set; }
        public string TypeName { get; set; }
        public string TypeNameUrl
        {
            get
            {
                return "https://msdn.microsoft.com/en-us/library/" + 
                    TypeName + ".aspx";
            }
        }
    }
    

    The SectionGroupDataSource class contains a GetSections method that accepts parameters that specify which Configuration object to retrieve and which section group to select. The method returns a collection of SectionInfo objects. The SectionInfo class is defined immediately following the SectionGroupDataSource class.

    Note

    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.

Creating a Web Page that Uses a GridView Control to Display Tabular Data

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

Note

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 GridView control are the same.

The GridView control creates an HTML table that has one row for each configuration section to display. Each row has the name of the section 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 GridView 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 have scope="col" attributes that identify column header cells.

In the following procedure you will create a Web page and add markup that displays the list of sections in a GridView 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 SectionGroup.aspx.

    The SectionGroup.aspx file opens in Source view.

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

  5. If you are adding this page to the Configuration System Browser application, make sure that the Select master page check box is selected. (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 - Sections in a Section Group, as shown in the following example:

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

    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="Sections in Section Group [name]">
        </asp:Label>
    </h2> 
    
    <h2>
        <asp:Label ID="HeadingLabel" runat="server" 
            Text="Sections in Section Group [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 Page_Load method in the page code will replace the string "[name]" in the heading with the actual name of the section group 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="GetSections" TypeName="SectionGroupDataSource">
        <SelectParameters>
            <asp:QueryStringParameter Name="sectionGroupName" 
                QueryStringField="SectionGroup" Type="String" 
                DefaultValue="system.web" />
            <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:ObjectDataSource ID="ObjectDataSource1" runat="server" 
        SelectMethod="GetSections" TypeName="SectionGroupDataSource">
        <SelectParameters>
            <asp:QueryStringParameter Name="sectionGroupName" 
                QueryStringField="SectionGroup" Type="String" 
                DefaultValue="system.web" />
            <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 GetSections method of the SectionGroupDataSource object. Parameters that are passed to the GetSections method specify the name of the section group and the specific Configuration object from which to retrieve the section group.

    The parameter value for the section group name is retrieved from a query string field that is named "SectionGroup". If there is no query string, the default section group is "system.web". 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, if you are creating this page without running all the walkthroughs in this series, only the default values will be used.

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

    <div class="dataTable">
        <asp:GridView ID="SectionGroupGridView" runat="server" 
            AutoGenerateColumns="False" 
            DataSourceID="ObjectDataSource1"
            Caption="Sections in Section Group [name]"
            summary="This table shows sections that are 
                contained in the specified section group."
             Width="100%">
            <Columns>
                <asp:TemplateField HeaderText="Name" 
                    SortExpression="Name" >
                    <ItemTemplate>
                        <asp:HyperLink ID="HyperLink1" runat="server" 
                            Text='<%# Bind("Name") %>' 
                            NavigateUrl='<%# Bind("NameUrl") %>'>
                        </asp:HyperLink>
                    </ItemTemplate>
                </asp:TemplateField>
                <asp:TemplateField HeaderText="TypeName" 
                    SortExpression="TypeName">
                    <ItemTemplate>
                        <asp:HyperLink ID="HyperLink2" runat="server" 
                            Text='<%# Bind("TypeName") %>' 
                            NavigateUrl='<%# Bind("TypeNameUrl") %>'>
                        </asp:HyperLink>
                    </ItemTemplate>
                </asp:TemplateField>
            </Columns>
        </asp:GridView>
    </div>
    
    <div class="dataTable">
        <asp:GridView ID="SectionGroupGridView" runat="server" 
            AutoGenerateColumns="False" 
            DataSourceID="ObjectDataSource1"
            Caption="Sections in Section Group [name]"
            summary="This table shows sections that are 
                contained in the specified section group."
             Width="100%">
            <Columns>
                <asp:TemplateField HeaderText="Name" 
                    SortExpression="Name" >
                    <ItemTemplate>
                        <asp:HyperLink ID="HyperLink1" runat="server" 
                            Text='<%# Bind("Name") %>' 
                            NavigateUrl='<%# Bind("NameUrl") %>'>
                        </asp:HyperLink>
                    </ItemTemplate>
                </asp:TemplateField>
                <asp:TemplateField HeaderText="TypeName" 
                    SortExpression="TypeName">
                    <ItemTemplate>
                        <asp:HyperLink ID="HyperLink2" runat="server" 
                            Text='<%# Bind("TypeName") %>' 
                            NavigateUrl='<%# Bind("TypeNameUrl") %>'>
                        </asp:HyperLink>
                    </ItemTemplate>
                </asp:TemplateField>
            </Columns>
        </asp:GridView>
    </div>
    

    This markup creates a GridView control. The following features of this markup relate to accessibility:

    • The Caption property is set so that a caption element will be generated.

    • A summary expando attribute is set so that a summary attribute on the table element will be generated. (When you specify attributes in markup that do not map to control properties, the attributes are passed through when the control is rendered; these are referred to as expando attributes.)

    Because each row presents the data for a section, and the first column contains the section name, cells in this row logically function as row headings. You could make this function explicit by adding scope="row" attributes to the td elements, and optionally you could use th instead of td elements. If you are using template fields you can cause the GridView control to generate th elements that have scope="row" attributes by setting the RowHeaderColumn property to the name of the field that has the identifier for a row. However, the RowHeaderColumn property is ignored when you use bound fields. This walkthrough uses bound fields in the GridView control. Therefore, the GridViewcontrol does not generate th elements for row headings. If you want to identify row headers in this manner, you can use bound fields or a different data control such as the ListView control.

In the following procedure you will add code that sets a GridView control property that causes thead, tbody, and th elements to be generated, and that sets the page heading.

To configure the GridView control and update the page heading

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

  2. In the Page_Load method, add the following code:

    SectionGroupGridView.HeaderRow.TableSection =
        TableRowSection.TableHeader
    
    SectionGroupGridView.HeaderRow.TableSection =
        TableRowSection.TableHeader;
    

    This code causes the GridView control to generate thead, tbody, and th elements.

  3. Below the code that you inserted in the preceding step, insert the following code:

    Dim s As String =
        ObjectDataSource1.SelectParameters("sectionGroupName").DefaultValue.ToString()
    If Request.QueryString("SectionGroup") IsNot Nothing Then
        s = Request.QueryString("SectionGroup")
    End If
    HeadingLabel.Text = HeadingLabel.Text.Replace("[name]", s)
    SectionGroupGridView.Caption =
        SectionGroupGridView.Caption.Replace("[name]", s)
    
    string s = ObjectDataSource1.SelectParameters["sectionGroupName"].DefaultValue.ToString();
    if (Request.QueryString["SectionGroup"] != null)
    {
        s = Request.QueryString["SectionGroup"];
    }
    HeadingLabel.Text = HeadingLabel.Text.Replace("[name]", s);
    SectionGroupGridView.Caption =
        SectionGroupGridView.Caption.Replace("[name]", s);
    

    This code determines which section group the page will display and puts the name of the selected section group in the page heading and in the table caption.

The following procedure is optional and will work only if you are creating this page as part of the Configuration System Browser application. Because the table is the only content on the page, the table caption is the same as the page heading. Therefore, in this procedure you add CSS markup that suppresses the display of the table caption. The caption will still be included in the HTML and can be announced by screen readers.

To prevent the table caption from being displayed

  1. Open the Site.css file that is in the Styles folder.

  2. Below the definition for the body element, add the following definition for caption elements:

    caption
    {
        display: none;
    }
    

Testing the Web Page

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 SectionGroup.aspx and then click View in Browser.

    You see a table that lists the sections in the system.web section group. Section 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 group type names are displayed as hyperlinks that point to the MSDN documentation for the indicated type, as shown in the following illustration:

    Configuration System Browser Section Group page

    Note

    You might have to click your browser's reload or refresh button to see the result of the new CSS settings that you added in the preceding procedure.

    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 will be the same, but there will be no title bar or menu bar, and the table caption will appear above the table

  2. In the browser, view the page source.

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

    <table cellspacing="0" rules="all" 
      summary="This table shows sections that are
      contained in the specified section group." border="1"
      id="ctl00_MainContent_SectionGroupGridView"
      style="width:100%;border-collapse:collapse;">
      <caption>
        Sections in Section Group system.web
      </caption>
      <thead>
        <tr>
          <th scope="col">Name</th>
          <th scope="col">TypeName</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>
            <a id="..." href="...">
              webParts
            </a>
          </td>
          <td>
            <a id="..." href="...">
              System.Web.Configuration.WebPartsSection
            </a>
          </td>
        </tr>
        [remaining rows of table]
      <tbody>
    </table>
    

Next Steps

In this walkthrough you used a GridView control to generate an HTML table that has 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 the ListView Control. The other walkthroughs in the series are the following:

See Also

Concepts

Accessibility in Visual Studio and ASP.NET