연습: ListView 컨트롤 사용을 위한 내게 필요한 옵션 지침

이 연습에서는 화면 판독기 소프트웨어를 사용하는 사용자가 웹 페이지를 편리하게 이용할 수 있도록 ASP.NET ListView 컨트롤을 사용하는 방법을 보여 줍니다. 이러한 기술은 다음 WCAG(Web Content Accessibility Guidelines) 2.0 지침을 준수하는 데 도움이 될 수 있습니다.

  • 프레젠테이션에서 구조 분리(WCAG 지침 1.3)

내게 필요한 옵션 및 WCAG 2.0에 대한 자세한 내용은 Visual Studio 및 ASP.NET의 내게 필요한 옵션을 참조하십시오.

이 연습을 실행하려면 다음 사항이 준비되어 있어야 합니다.

이 연습은 ASP.NET 웹 사이트가 WCAG 2.0 내게 필요한 옵션 지침을 준수하는 데 도움이 될 수 있는 기술을 보여 주는 시리즈 중 세 번째 연습입니다. 이 연습 시리즈에서는 ASP.NET 구성 설정을 보는 데 사용할 수 있는 웹 응용 프로그램을 만듭니다. 모든 연습을 실행하려면 연습: 이미지 컨트롤, 메뉴 컨트롤 및 AutoPostBack 사용을 위한 내게 필요한 옵션 지침에서 시작합니다. 시리즈의 다른 연습을 완료하지 않으려는 경우 일부 단계에 대해 제공되는 대체 지침을 따르십시오. 연습을 시리즈의 일부로 완료하든 개별적으로 완료하든 상관없이 동일한 내게 필요한 옵션 기능이 설명되어 있습니다.

이 연습에서 만드는 웹 페이지에는 machine.config 구성 파일의 한 섹션에 있는 요소가 표시됩니다. 쿼리 매개 변수에서 해당 섹션을 지정할 수 있습니다. 구성 파일과 이러한 파일에 포함되는 섹션 그룹, 섹션 및 요소에 대한 자세한 내용은 ASP.NET 구성 파일을 참조하십시오. 하지만 ASP.NET 구성 파일 시스템에 익숙하지 않더라도 내게 필요한 옵션 지침을 준수하는 웹 페이지를 만드는 방법을 보여 주는 이 연습을 사용할 수 있습니다.

보안 정보보안 정보

이러한 연습에서 만드는 응용 프로그램이 표시하는 구성 정보는 개발자에게 유용하지만 보안상의 이유로 프로덕션 웹 사이트에 표시해서는 안 됩니다. 구성 설정에는 권한이 있는 사용자에게만 표시되어야 하는 중요한 정보가 포함될 수 있습니다.

이 항목에 수반되는 Visual Studio 웹 사이트 프로젝트 및 소스 코드를 다운로드하십시오.

이 연습에서 사용하는 ListView 컨트롤에 표시할 데이터는 ASP.NET 구성 파일에서 나옵니다. 다음 절차에서는 지정된 Configuration 개체를 검색하고 해당 개체에서 섹션을 선택한 다음 섹션에 포함된 요소 목록을 반환하는 클래스를 만듭니다.

참고참고

이 연습 단원에서는 내게 필요한 옵션 기능을 구체적으로 설명하지 않습니다. 여기서는 GridView 컨트롤에서 사용할 데이터만 제공합니다.

구성 섹션 목록을 반환하는 클래스를 만들려면

  1. 웹 사이트에 App_Code 폴더가 없는 경우 솔루션 탐색기에서 프로젝트 이름을 마우스 오른쪽 단추로 클릭하고 ASP.NET 폴더 추가를 클릭한 다음 App_Code를 클릭합니다.

  2. App_Code를 마우스 오른쪽 단추로 클릭한 다음 새 항목 추가를 클릭합니다.

  3. 설치된 템플릿에서 Visual Basic 또는 Visual C#을 클릭한 다음 클래스를 클릭합니다.

  4. 이름 텍스트 상자에 SectionDataSource.vb 또는 SectionDataSource.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.Collections;
    using System.Reflection;
    
    /// <summary>
    /// Retrieves a list of elements in a section. 
    /// </summary>
    public class SectionDataSource
    {
        public SectionDataSource()
        {
        }
        public List<ElementInfo> GetProperties(
            string sectionName,
            string virtualPath,
            string site,
            string locationSubPath,
            string server)
        {
            List<ElementInfo> sectionList = new List<ElementInfo>();
    
            Configuration config =
                WebConfigurationManager.OpenWebConfiguration(
                    virtualPath, site, locationSubPath, server);
    
            ConfigurationSection cs = config.GetSection(sectionName);
            Type sectionType = cs.GetType();
            PropertyInfo[] sectionProperties = sectionType.GetProperties();
    
            foreach (PropertyInfo rpi in sectionProperties)
            {
                if (rpi.Name != "SectionInformation" &&
                    rpi.Name != "LockAttributes" &&
                    rpi.Name != "LockAllAttributesExcept" &&
                    rpi.Name != "LockElements" &&
                    rpi.Name != "LockAllElementsExcept" &&
                    rpi.Name != "LockItem" &&
                    rpi.Name != "ElementInformation" &&
                    rpi.Name != "CurrentConfiguration")
                {
                    ElementInfo ei = new ElementInfo();
                    ei.Name = rpi.Name;
                    ei.TypeName = rpi.PropertyType.ToString();
    
                    if (rpi.PropertyType.BaseType == 
                        typeof(ConfigurationElement))
                    {
                        ei.NameUrl = "Element.aspx?Section=" + 
                            sectionName + "&Element=" + rpi.Name;
                        ei.Value = "Element";
                    }
                    else if (rpi.PropertyType.BaseType == 
                        typeof(ConfigurationElementCollection))
                    {
                        ei.NameUrl = "Element.aspx?Section=" + 
                            sectionName + "&Element=" + rpi.Name;
                        ei.Value = "Element Collection";
                    }
                    else
                    {
                        ParameterInfo[] indexParms = rpi.GetIndexParameters();
                        if (rpi.PropertyType == typeof(IList) || 
                            rpi.PropertyType == typeof(ICollection) || 
                            indexParms.Length > 0)
                        {
                            ei.Value = "Collection";
                        }
                        else
                        {
                            object propertyValue = rpi.GetValue(cs, null);
                            ei.Value = propertyValue == null ? "" : 
                                propertyValue.ToString();
                        }
                    }
                    sectionList.Add(ei);
                }
            }
            return sectionList;
        }
    }
    
    public class ElementInfo
    {
        public string Name { get; set; }
        public string ItemName { get; set; }
        public string SectionName { get; set; }
        public string NameUrl { 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 int Index { get; set; }
    }
    
    
    

    SectionDataSource 클래스에는 검색할 Configuration 개체와 선택할 섹션을 지정하는 매개 변수를 받는 GetProperties 메서드가 포함됩니다. 이 메서드는 ElementInfo 개체 컬렉션을 반환합니다. ElementInfo 클래스는 SectionDataSource 클래스 바로 다음에 정의됩니다.

    참고참고

    이 연습에 사용된 Configuration Browser 응용 프로그램에는 공용 클래스 및 메서드로 리팩터링되었을 수 있는 중복 데이터 소스 코드가 포함되어 있습니다. 그러나 각 연습을 개별적으로 수행할 수 있도록 코드가 복제되었습니다. 이 접근 방식을 사용하면 내게 필요한 옵션과 직접 관련되지 않은 연습 부분의 단계 수도 최소화됩니다.

이 단원에서는 ObjectDataSource 컨트롤을 사용하여 데이터를 ListView 컨트롤에 제공하는 웹 페이지를 만듭니다. ObjectDataSource 컨트롤은 이전 절차에서 만든 SectionDataSource 개체의 GetProperties 메서드를 호출합니다.

참고참고

ObjectDataSource 를 사용하여 데이터를 검색하든 다른 메서드를 사용하여 데이터를 검색하든 상관 없이(예를 들어 SqlDataSource 컨트롤 또는 LinqDataSource 컨트롤을 사용하는 데이터베이스 쿼리), ListView 컨트롤을 구성하기 위한 메서드는 동일합니다.

ListView 컨트롤은 각 요소에 하나의 행이 있는 HTML table 요소를 만듭니다. 각 행에는 한 열에 있는 요소의 이름과 두 번째 열에서 요소에 대한 설정을 저장하는 데 사용되는 클래스의 이름이 있습니다.

화면 판독기 소프트웨어를 사용하는 사용자가 표를 편리하게 이용할 수 있도록 하려면 생성되는 HTML 표에 다음 기능을 포함하도록 ListView 컨트롤을 구성합니다.

  • 짧은 제목에 표의 용도를 설명하는 caption 요소

  • 표의 용도에 대한 긴 설명을 제공하는 summary 요소

  • 표의 제목과 본문 섹션을 구별하는 theadtbody 요소

  • 열 머리글 셀을 식별하는 scope="col" 특성이 있는 th 요소

  • 행 머리글 셀을 식별하는 scope="row" 특성이 있는 td 요소

다음 절차에서는 웹 페이지를 만들고 ListView 컨트롤에 요소 목록을 표시하는 태그를 추가합니다.

구성 섹션 목록을 표시하는 웹 페이지를 만들려면

  1. 솔루션 탐색기에서 프로젝트 이름을 마우스 오른쪽 단추로 클릭한 다음 새 항목 추가를 클릭합니다.

    새 항목 추가 대화 상자가 나타납니다.

  2. 설치된 템플릿에서 Visual Basic 또는 Visual C#을 클릭한 다음 Web Form을 클릭합니다.

  3. 이름 텍스트 상자에 Section.aspx를 입력합니다.

  4. 다른 파일에 코드 입력 확인란이 선택되어 있는지 확인합니다.

  5. Configuration System Browser 응용 프로그램에 이 페이지를 추가할 경우 마스터 페이지 선택 확인란이 선택되어 있는지 확인합니다. 연습: 이미지 컨트롤, 메뉴 컨트롤 및 AutoPostBack 사용을 위한 내게 필요한 옵션 지침 에서 만드는 웹 사이트에 이 페이지를 추가하지 않으면 마스터 페이지가 없을 수 있습니다.

  6. 새 항목 추가 대화 상자에서 확인을 클릭합니다.

  7. 마스터 페이지 선택 대화 상자가 나타나면 확인을 클릭합니다. 마스터 페이지가 하나만 있으며 이미 선택되어 있습니다.

  8. 다음 예제와 같이 @ Page 지시문에서 Title 속성을 Configuration System Browser - Elements in a Section으로 설정합니다.

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

    이 제목은 사이트와 사이트 페이지를 식별합니다. 내게 필요한 옵션 지침에 따라 페이지 제목을 설정해야 합니다.

  9. MainContent ContentPlaceHolder 컨트롤에 대한 Content 요소 내부에 다음 태그를 삽입합니다.

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

    Configuration System Browser 응용 프로그램의 일부가 아닌 웹 페이지를 만들 경우 <div> 태그와 </div> 태그 사이에 태그를 삽입합니다.

    이 태그는 제목을 프로그래밍 방식으로 변경할 수 있도록 Label 컨트롤에 제목을 추가합니다. 외부 ListView 컨트롤에 대한 PreRender 이벤트 처리기는 머리글의 "[name]" 문자열을 페이지에 표시되는 섹션의 실제 이름으로 바꿉니다.

  10. 이전 단계에서 삽입한 태그 아래에 다음 태그를 삽입합니다.

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

    이 태그는 SectionDataSource 개체의 GetProperties 메서드를 호출하는 ObjectDataSource 컨트롤을 만듭니다. GetProperties 메서드에 전달된 매개 변수는 섹션의 이름과 섹션을 검색하는 특정 Configuration 개체를 지정합니다.

    섹션 이름은 "Section"이라는 이름의 쿼리 문자열 필드에서 검색됩니다. 쿼리 문자열이 없으면 기본 섹션은 "system.web/httpHandlers"입니다. 다른 네 매개 변수의 값은 세션 상태에서 검색됩니다. 값은 Configuration System Browser 응용 프로그램의 다른 페이지에 의해 세션 상태에 배치됩니다. 따라서 이 연습을 독립적인 웹 페이지로 만들 경우 기본값만 사용됩니다.

  11. ObjectDataSource 컨트롤 아래에 다음 태그를 삽입합니다.

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

    이 태그는 div 요소에 ListView 컨트롤을 만듭니다. 나중에 이 요소에 대한 닫는 태그를 추가합니다. 이 태그는 선택한 구성 섹션의 이름을 사용하여 EmptyDataTemplate 개체와 HTML 표의 caption 요소를 사용자 지정할 수 있도록 컨트롤의 PreRender 이벤트에 대한 처리기를 등록합니다.

  12. 앞 단계에서 삽입한 태그 아래에 다음 태그를 삽입합니다.

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

    이 태그는 ListView 컨트롤에 대한 LayoutTemplate 개체를 만듭니다. LayoutTemplate 개체는 컨트롤이 내게 필요한 옵션과 관련된 다음과 같은 기능을 가진 HTML 표를 생성하도록 지정합니다.

    • 표의 내용에 대한 짧은 설명인 caption 요소

    • 표의 내용에 대한 긴 설명인 summary 특성

    • 표의 제목과 본문 섹션을 구별하는 theadtbody 요소

    • 열 머리글 셀을 식별하는 scope="col" 특성이 있는 th 요소

  13. 앞 단계에서 삽입한 태그 아래에 다음 태그를 삽입합니다.

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

    이 태그는 ListView 컨트롤에 대한 ItemTemplate 개체를 만듭니다. ItemTemplate 개체는 각 데이터 행이 tr 요소를 생성하도록 지정합니다. 첫 번째 열에는 요소 이름과 기능이 행 머리글로 포함되기 때문에 내게 필요한 옵션에 도움이 되도록 첫 번째 열의 셀은 scope="row" 특성을 사용하여 생성됩니다.

  14. 앞 단계에서 삽입한 태그 아래에 다음 태그를 삽입합니다.

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

    이 태그는 ListView 컨트롤에 대한 EmptyDataTemplate 개체를 만들며 ListView 컨트롤에 대한 닫는 태그와 이 컨트롤이 포함되는 div 요소를 만듭니다. EmptyDataTemplate 개체는 선택한 구성 섹션에 요소가 포함되지 않는 경우 사용자 지정 메시지를 제공합니다.

표 캡션 및 EmptyDataTemplate 개체 업데이트

다음 절차에서는 선택한 구성 섹션의 이름을 HTML 표의

caption 요소에 배치하는 코드를 추가합니다. 또한 데이터가 반환되지 않는 경우 발생하는 결과를 정의합니다.

캡션 및 EmptyDataTemplate 개체를 업데이트하려면

  1. SectionGroup.aspx.vb 또는 SectionGroup.aspx.cs 파일을 엽니다.

  2. using 문(Visual Basic의 경우 Imports) 끝에 다음 코드를 추가합니다.

    
    using System.Web.UI.HtmlControls;
    
    
    

    using 또는 Imports 문은 다음 단계에서 참조할 클래스에 필요합니다.

  3. Page_Load 메서드 아래에 다음 코드를 추가합니다.

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

    이 코드는 현재 선택한 구성 섹션 이름을 다음 위치에 배치합니다.

    • 페이지 제목

    • 생성된 경우 HTML 표의 caption 요소(선택한 구성 섹션에 요소가 있는 경우에만 표가 생성됨)

    • EmptyDataTemplate 개체에서 생성되는 태그: 이 템플릿은 선택한 구성 섹션에 요소가 없는 경우에만 HTML을 생성합니다.

이제 테스트를 실행하여 표가 제대로 표시되며 액세스 가능한 HTML이 생성되는지 확인할 수 있습니다.

페이지를 테스트하려면

  1. 솔루션 탐색기에서 Section.aspx를 마우스 오른쪽 단추로 클릭한 다음 브라우저에서 보기를 클릭합니다.

    system.web/httpHandlers 섹션의 요소를 보여 주는 표가 나타납니다. 요소 이름은 하이퍼링크로 표시되며 이 시리즈(연습: ListView 컨트롤 사용을 위한 내게 필요한 옵션 지침)의 다른 연습에서 실행할 경우 만들게 될 페이지를 가리킵니다.

    섹션 형식 이름은 다음 그림과 같이 표시된 형식에 대한 MSDN 설명서를 가리키는 하이퍼링크로 표시됩니다.

    구성 브라우저 - 섹션의 요소

    웹 페이지를 Configuration System Browser 응용 프로그램의 일부가 아닌 독립적 페이지로 만든 경우 제목과 표 내용은 동일하지만 제목 표시줄이나 메뉴 모음이 없고 표 캡션이 표 위에 나타납니다.

  2. 브라우저에서 페이지 소스를 봅니다.

    다음 예제에서는 화면 판독기 사용자에 대한 내게 필요한 표 옵션을 향상시키기 위해 추가된 표 요소를 보여 줍니다.

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

이 연습에서는 ListView 컨트롤을 사용하여 화면 판독기 소프트웨어를 사용하는 사용자가 표 데이터를 편리하게 이용할 수 있도록 하는 HTML 요소와 특성을 만들어 보았습니다. 이 시리즈의 다른 연습에서는 내게 필요한 옵션 지침을 준수하는 웹 페이지를 만드는 데 도움이 되는 다른 기술을 보여 줍니다. 이 시리즈의 다음 연습은 연습: 중첩 ListView 컨트롤 사용을 위한 내게 필요한 옵션 지침입니다. 이외에 다음과 같은 연습도 시리즈에 포함되어 있습니다.

표시: