다음을 통해 공유


라디오 단추의 GridView 열 추가(C#)

작성한 스콧 미첼

PDF 다운로드

이 자습서에서는 GridView 컨트롤에 라디오 단추 열을 추가하여 사용자에게 GridView의 단일 행을 선택하는 보다 직관적인 방법을 제공하는 방법을 살펴봅니다.

소개

GridView 컨트롤은 다양한 기본 제공 기능을 제공합니다. 여기에는 텍스트, 이미지, 하이퍼링크 및 단추를 표시하기 위한 다양한 필드가 포함됩니다. 추가 사용자 지정을 위한 템플릿을 지원합니다. 마우스를 몇 번 클릭하면 단추를 통해 각 행을 선택할 수 있는 GridView를 만들거나 기능을 편집하거나 삭제할 수 있습니다. 제공된 기능의 과다에도 불구하고 지원되지 않는 추가 기능을 추가해야 하는 경우가 종종 있습니다. 이 자습서와 다음 두 자습서에서는 추가 기능을 포함하도록 GridView의 기능을 향상시키는 방법을 살펴봅니다.

이 자습서와 다음 자습서에서는 행 선택 프로세스를 향상시키는 데 중점을 두고 있습니다. 선택 가능한 마스터 GridView 및 세부 정보 DetailView를 사용하는 마스터/세부 정보에서 분석했듯이, Select 단추가 포함된 CommandField를 GridView에 추가할 수 있습니다. 클릭하면 포스트백이 계속되고 GridView의 SelectedIndex 속성이 선택 단추를 클릭한 행의 인덱스로 업데이트됩니다. Master/Detail에서 선택 가능한 Master GridView를 사용한 DetailView 자습서에서 이 기능을 사용하여 선택한 GridView 행의 세부 정보를 표시하는 방법을 살펴보았습니다.

선택 단추는 많은 상황에서 작동하지만 다른 사용자도 작동하지 않을 수 있습니다. 단추를 사용하는 대신 라디오 단추와 확인란이라는 두 가지 다른 사용자 인터페이스 요소가 일반적으로 선택 영역에 사용됩니다. 선택 단추 대신 각 행에 라디오 단추 또는 확인란이 포함되도록 GridView를 보강할 수 있습니다. 사용자가 GridView 레코드 중 하나만 선택할 수 있는 시나리오에서는 선택 단추보다 라디오 단추를 선호할 수 있습니다. 사용자가 웹 기반 전자 메일 애플리케이션과 같은 여러 레코드를 선택할 수 있는 경우 사용자가 여러 메시지를 선택하여 확인란을 삭제하려는 경우 선택 단추 또는 라디오 단추 사용자 인터페이스에서 사용할 수 없는 기능을 제공합니다.

이 자습서에서는 GridView에 라디오 단추 열을 추가하는 방법을 살펴봅니다. 진행 자습서에서는 확인란을 사용하여 탐색합니다.

1단계: GridView 웹 페이지 향상 만들기

라디오 단추 열을 포함하도록 GridView를 향상시키기 전에 먼저 이 자습서와 다음 두 가지에 필요한 웹 사이트 프로젝트에서 ASP.NET 페이지를 만들어 보겠습니다. 먼저 .라는 EnhancedGridView새 폴더를 추가합니다. 다음으로, 다음 ASP.NET 페이지를 해당 폴더에 추가하여 각 페이지를 마스터 페이지와 Site.master 연결해야 합니다.

  • Default.aspx
  • RadioButtonField.aspx
  • CheckBoxField.aspx
  • InsertThroughFooter.aspx

SqlDataSource-Related 자습서에 대한 ASP.NET 페이지 추가

그림 1: SqlDataSource-Related 자습서의 ASP.NET 페이지 추가

다른 폴더들처럼 Default.aspx 폴더에서는 해당 섹션의 자습서를 나열합니다. 사용자 컨트롤이 SectionLevelTutorialListing.ascx 이 기능을 제공한다는 점을 기억하세요. 따라서 솔루션 탐색기에서 페이지 디자인 보기로 끌어서 이 사용자 컨트롤 Default.aspx 을 추가합니다.

SectionLevelTutorialListing.ascx 사용자 컨트롤을 Default.aspx에 추가하십시오

그림 2: 사용자 정의 컨트롤 추가 SectionLevelTutorialListing.ascxDefault.aspx (전체 크기 이미지를 보려면 클릭)

마지막으로 이 네 페이지를 파일에 항목으로 추가합니다 Web.sitemap . 특히 SqlDataSource 컨트롤 <siteMapNode>사용 후 다음 태그를 추가합니다.

<siteMapNode 
    title="Enhancing the GridView" 
    url="~/EnhancedGridView/Default.aspx" 
    description="Augment the user experience of the GridView control.">
    <siteMapNode 
        url="~/EnhancedGridView/RadioButtonField.aspx" 
        title="Selection via a Radio Button Column" 
        description="Explore how to add a column of radio buttons in the GridView." />
    <siteMapNode 
        url="~/EnhancedGridView/CheckBoxField.aspx" 
        title="Selection via a Checkbox Column" 
        description="Select multiple records in the GridView by using a column of 
            checkboxes." />
    <siteMapNode 
        url="~/EnhancedGridView/InsertThroughFooter.aspx" 
        title="Add New Records through the Footer" 
        description="Learn how to allow users to add new records through the 
            GridView's footer." />
</siteMapNode>

업데이트 Web.sitemap한 후 잠시 브라우저를 통해 자습서 웹 사이트를 봅니다. 이제 왼쪽 메뉴에는 자습서 편집, 삽입 및 삭제를 위한 항목이 포함되어 있습니다.

이제 사이트 맵에 GridView 자습서 향상을 위한 항목이 포함됩니다.

그림 3: 이제 사이트 맵에 GridView 자습서 향상을 위한 항목이 포함됩니다.

2단계: GridView에 공급업체 표시

이 자습서에서는 각 GridView 행에 라디오 단추를 제공하는 미국의 공급업체를 나열하는 GridView를 빌드해 보겠습니다. 라디오 단추를 통해 공급업체를 선택한 후 사용자는 단추를 클릭하여 공급업체 제품을 볼 수 있습니다. 이 작업은 사소한 것처럼 들릴 수 있지만, 특히 까다로울 수 있는 미묘한 차이가 많이 있습니다. 이러한 미묘한 차이를 살펴보기 전에 먼저 공급업체를 나열하는 GridView를 살펴보겠습니다.

먼저 폴더에서 RadioButtonField.aspx 페이지를 열고, 도구 상자에서 GridView를 디자이너로 끌어다 놓습니다EnhancedGridView. GridView의 IDSuppliers로 설정하고 스마트 태그에서 새 데이터 원본을 만들도록 선택합니다. 특히 SuppliersDataSource 객체에서 데이터를 가져오는 SuppliersBLL라는 이름의 ObjectDataSource를 생성합니다.

SuppliersDataSource라는 새 ObjectDataSource 만들기

그림 4: 새 ObjectDataSource 이름 SuppliersDataSource 만들기(전체 크기 이미지를 보려면 클릭)

비즈니스 개체 SuppliersBLL이 선택되고 다음 단추가 강조 표시된 데이터 원본 구성 - SuppliersDataSource 창의 스크린샷

그림 5: 클래스를 사용하도록 SuppliersBLL ObjectDataSource 구성(전체 크기 이미지를 보려면 클릭)

미국에서 해당 공급업체만 나열하려고 하므로 SELECT 탭의 GetSuppliersByCountry(country) 드롭다운 목록에서 메서드를 선택합니다.

SELECT 탭이 열려 있는 데이터 원본 구성 - SuppliersDataSource 창의 스크린샷 메서드 옵션 GetSupplierByCountry가 선택되고 다음 단추가 강조 표시됩니다.

그림 6: 클래스를 사용하도록 SuppliersBLL ObjectDataSource 구성(전체 크기 이미지를 보려면 클릭)

업데이트 탭에서 (없음) 옵션을 선택하고 다음을 클릭합니다.

UPDATE 탭이 열려 있는 데이터 원본 구성 - SuppliersDataSource 창의 스크린샷 메서드 옵션(없음)이 선택되고 다음 단추가 강조 표시됩니다.

그림 7: 클래스를 사용하도록 SuppliersBLL ObjectDataSource 구성(전체 크기 이미지를 보려면 클릭)

메서드는 GetSuppliersByCountry(country) 매개 변수를 허용하므로 데이터 원본 구성 마법사에서 해당 매개 변수의 원본을 묻는 메시지를 표시합니다. 하드 코딩된 값(미국, 이 예제에서는)을 지정하려면 매개 변수 원본 드롭다운 목록을 None으로 설정하고 텍스트 상자에 기본값을 입력합니다. 마침을 클릭하여 마법사를 완료합니다.

국가 매개 변수의 기본값으로 USA 사용

그림 8: 매개 변수의 기본값 country 으로 USA 사용(전체 크기 이미지를 보려면 클릭)

마법사를 완료한 후 GridView에는 각 공급업체 데이터 필드에 대한 BoundField가 포함됩니다. CompanyName, City, 그리고 Country BoundFields를 제외한 모든 것을 제거하고 CompanyName BoundFields의 HeaderText 속성을 Supplier로 바꿉니다. 이렇게 하면 GridView 및 ObjectDataSource 선언적 구문이 다음과 유사하게 표시됩니다.

<asp:GridView ID="Suppliers" runat="server" AutoGenerateColumns="False"
    DataKeyNames="SupplierID" DataSourceID="SuppliersDataSource" 
    EnableViewState="False">
    <Columns>
        <asp:BoundField DataField="CompanyName" HeaderText="Supplier" 
            SortExpression="CompanyName" />
        <asp:BoundField DataField="City" HeaderText="City" 
            SortExpression="City" />
        <asp:BoundField DataField="Country" HeaderText="Country" 
            SortExpression="Country" />
    </Columns>
</asp:GridView>
<asp:ObjectDataSource ID="SuppliersDataSource" runat="server" 
    OldValuesParameterFormatString="original_{0}"
    SelectMethod="GetSuppliersByCountry" TypeName="SuppliersBLL">
    <SelectParameters>
        <asp:Parameter DefaultValue="USA" Name="country" Type="String" />
    </SelectParameters>
</asp:ObjectDataSource>

이 자습서에서는 사용자가 공급자 목록과 동일한 페이지 또는 다른 페이지에서 선택한 공급업체 제품을 볼 수 있도록 허용해 보겠습니다. 이를 수용하려면 페이지에 두 개의 단추 웹 컨트롤을 추가합니다. 이 두 버튼의 ID을 설정했습니다. ListProducts을 클릭하면 포스트백이 발생하고 선택한 공급업체의 제품이 같은 페이지에 나열됩니다. 그러나 SendToProducts을 클릭하면 사용자는 제품을 나열하는 다른 페이지로 이동하게 됩니다.

그림 9는 브라우저를 Suppliers 통해 볼 때 GridView와 두 개의 단추 웹 컨트롤을 보여 줍니다.

미국의 해당 공급업체에는 이름, 도시 및 국가 정보가 나열되어 있습니다.

그림 9: 미국의 공급업체의 이름, 도시 및 국가 정보가 나열되어 있습니다(전체 크기 이미지를 보려면 클릭).

3단계: 라디오 버튼 열 추가

이 시점에서 Suppliers GridView에는 미국에 있는 각 공급업체의 회사 이름, 도시 및 국가를 표시하는 세 개의 BoundFields가 있습니다. 그러나 여전히 라디오 단추 열이 부족합니다. 아쉽게도 GridView에는 기본 제공 RadioButtonField가 포함되지 않습니다. 그렇지 않다면 그리드에 추가하여 바로 완료할 수 있을 텐데요. 대신 TemplateField를 추가하고 라디오 단추를 렌더링하도록 구성 ItemTemplate 하여 각 GridView 행에 라디오 단추를 만들 수 있습니다.

처음에는 TemplateField에 RadioButton 웹 컨트롤을 추가하여 원하는 사용자 인터페이스를 구현할 수 있다고 가정할 ItemTemplate 수 있습니다. 실제로 GridView의 각 행에 단일 라디오 단추를 추가하지만 라디오 단추를 그룹화할 수 없으므로 상호 배타적이지 않습니다. 즉, 최종 사용자는 GridView에서 동시에 여러 라디오 단추를 선택할 수 있습니다.

RadioButton 웹 컨트롤의 TemplateField는 우리가 필요한 기능을 제공하지 않지만, 결과적으로 라디오 버튼이 그룹화되지 않는 이유를 알아보는 것이 중요합니다. 먼저 Suppliers GridView에 TemplateField를 추가하여 맨 왼쪽 필드로 만듭니다. 그런 다음 GridView의 스마트 태그에서 템플릿 편집 링크를 클릭하고 도구 상자에서 TemplateField ItemTemplate 로 RadioButton 웹 컨트롤을 끕니다(그림 10 참조). RadioButton의 ID 속성을 RowSelector로 설정하고 GroupName 속성을 SuppliersGroup로 설정합니다.

ItemTemplate에 RadioButton 웹 컨트롤 추가

그림 10: RadioButton 웹 컨트롤을 ItemTemplate 추가합니다(전체 크기 이미지를 보려면 클릭).

디자이너를 통해 이러한 추가 작업을 수행한 후 GridView의 태그는 다음과 유사하게 표시됩니다.

<asp:GridView ID="Suppliers" runat="server" AutoGenerateColumns="False"
    DataKeyNames="SupplierID" DataSourceID="SuppliersDataSource" 
    EnableViewState="False">
    <Columns>
        <asp:TemplateField>
            <ItemTemplate>
                <asp:RadioButton ID="RowSelector" runat="server" 
                    GroupName="SuppliersGroup" />
            </ItemTemplate>
        </asp:TemplateField>
        <asp:BoundField DataField="CompanyName" HeaderText="Supplier" 
            SortExpression="CompanyName" />
        <asp:BoundField DataField="City" HeaderText="City" 
            SortExpression="City" />
        <asp:BoundField DataField="Country" HeaderText="Country" 
            SortExpression="Country" />
    </Columns>
</asp:GridView>

RadioButton의 GroupName 속성 은 일련의 라디오 단추를 그룹화하는 데 사용됩니다. 동일한 GroupName 값을 가진 모든 RadioButton 컨트롤은 그룹화된 것으로 간주되며 한 번에 하나의 라디오 단추만 그룹에서 선택할 수 있습니다. 이 속성은 GroupName 렌더링된 라디오 버튼의 name 속성에 대한 값을 지정합니다. 브라우저는 라디오 단추 name 특성을 검사하여 라디오 단추 그룹화가 결정됩니다.

RadioButton 웹 컨트롤을 ItemTemplate에 추가한 후, 브라우저를 통해 이 페이지를 방문하여 격자 행의 라디오 버튼을 클릭합니다. 그림 11과 같이 라디오 단추가 그룹화되지 않아 모든 행을 선택할 수 있습니다.

GridView의 라디오 단추가 그룹화되지 않음

그림 11: GridView의 라디오 단추가 그룹화되지 않음(전체 크기 이미지를 보려면 클릭)

라디오 단추가 그룹화되지 않는 이유는 동일한 name 속성 설정에도 불구하고 렌더링된 GroupName 특성이 다르기 때문입니다. 이러한 차이점을 확인하려면 브라우저에서 보기/원본을 수행하고 라디오 단추 태그를 검사합니다.

<input id="ctl00_MainContent_Suppliers_ctl02_RowSelector" 
    name="ctl00$MainContent$Suppliers$ctl02$SuppliersGroup" 
    type="radio" value="RowSelector" />
<input id="ctl00_MainContent_Suppliers_ctl03_RowSelector" 
    name="ctl00$MainContent$Suppliers$ctl03$SuppliersGroup" 
    type="radio" value="RowSelector" />
<input id="ctl00_MainContent_Suppliers_ctl04_RowSelector" 
    name="ctl00$MainContent$Suppliers$ctl04$SuppliersGroup" 
    type="radio" value="RowSelector" />
<input id="ctl00_MainContent_Suppliers_ctl05_RowSelector" 
    name="ctl00$MainContent$Suppliers$ctl05$SuppliersGroup" 
    type="radio" value="RowSelector" />

속성 창에 지정된 값과 정확히 일치하지 않고 여러 다른 name 값들 앞에 추가된 idID 특성을 확인하세요. 렌더링된 IDid 속성 앞에 추가된 name 값은 라디오 버튼의 부모 컨트롤인 IDs, GridView의 GridViewRow, 컨텐츠 컨트롤의 ID, 웹 폼의 IDs 입니다. GridView에서 렌더링된 각 웹 컨트롤에 고유 ID 하고 id 값이 있도록 이러한 name 항목이 추가됩니다.

렌더링된 각 컨트롤은 서로 다른 nameid 것이 필요하며, 이는 브라우저가 클라이언트 쪽의 각 컨트롤을 고유하게 식별하는 방식과 포스트백 시 발생한 작업 또는 변경 내용을 웹 서버에 식별하는 방식이기 때문입니다. 예를 들어 RadioButton의 확인 상태가 변경될 때마다 일부 서버 쪽 코드를 실행하려고 하는 경우를 생각해 보겠습니다. RadioButton의 AutoPostBack 속성을 true로 설정하고 CheckChanged 이벤트에 대한 이벤트 처리기를 만들어서 이 작업을 수행할 수 있습니다. 그러나 모든 라디오 버튼에 대해 렌더링된 nameid 값이 동일한 경우, 포스트백에서 어떤 특정한 라디오 버튼이 클릭되었는지 확인할 수 없습니다.

간단히 말해서 RadioButton 웹 컨트롤을 사용하여 GridView에서 라디오 단추 열을 만들 수 없다는 것입니다. 대신, 적절한 태그가 각 GridView 행에 삽입되도록 하기 위해 다소 오래된 기술을 사용해야 합니다.

비고

RadioButton 웹 컨트롤과 마찬가지로 템플릿에 추가할 때 라디오 단추 HTML 컨트롤에는 고유 name 특성이 포함되므로 그리드의 라디오 단추가 그룹화되지 않습니다. HTML 컨트롤에 익숙하지 않은 경우 특히 ASP.NET 2.0에서 HTML 컨트롤이 거의 사용되지 않으므로 이 메모를 무시해도 됩니다. 그러나 자세히 알아보려면 K. Scott Allen 의 블로그 항목 웹 컨트롤 및 HTML 컨트롤을 참조하세요.

리터럴 컨트롤을 이용해 라디오 버튼 마크업을 삽입하기

GridView 내의 모든 라디오 단추를 올바르게 그룹화하려면 라디오 단추 태그 ItemTemplate를 수동으로 삽입해야 합니다. 각 라디오 단추에는 동일한 name 특성이 필요하지만 고유한 id 특성이 있어야 합니다(클라이언트 쪽 스크립트를 통해 라디오 단추에 액세스하려는 경우). 사용자가 라디오 단추를 선택하고 페이지를 다시 게시하면 브라우저에서 선택한 라디오 단추 특성의 value 값을 다시 보냅니다. 따라서 각 라디오 단추에는 고유한 value 특성이 필요합니다. 마지막으로, 포스트백 시 선택한 하나의 라디오 단추에 특성을 추가 checked 해야 합니다. 그렇지 않으면 사용자가 선택하고 다시 게시한 후에는 라디오 단추가 기본 상태로 돌아갑니다(모두 선택되지 않음).

템플릿에 하위 수준 태그를 삽입하기 위해 수행할 수 있는 두 가지 방법이 있습니다. 하나는 코드 숨김 클래스에 정의된 형식 지정 메서드에 대한 태그와 호출을 혼합하여 수행하는 것입니다. 이 기술은 GridView 컨트롤 자습서의 TemplateFields 사용 자습서에서 처음 설명했습니다. 이 경우 다음과 같이 표시될 수 있습니다.

<input type="radio" id='<%# GetUniqueRadioButtonID(...) %>' 
    name='SuppliersGroup' value='<%# GetRadioButtonValue(...) %>' ... />

여기서는 GetUniqueRadioButtonGetRadioButtonValue 각 라디오 단추에 대한 적절한 idvalue 특성 값을 반환하는 코드 숨김 클래스에 정의된 메서드입니다. 이 방법은 idvalue 특성을 할당하는 데 잘 작동하지만, 데이터 바인딩 구문은 데이터가 처음으로 GridView에 바인딩될 때만 실행되기 때문에 checked 특성 값을 지정할 때 문제를 초래합니다. 따라서 GridView에서 뷰 상태를 사용하도록 설정한 경우 페이지가 처음 로드되거나 GridView가 데이터 원본에 명시적으로 반등할 때만 서식 지정 메서드가 실행되므로 특성을 설정하는 checked 함수는 포스트백 시 호출되지 않습니다. 그것은 다소 미묘한 문제이고 이 기사에서는 깊게 다루지 않으므로 여기서 마무리하도록 하겠습니다. 그러나 저는 위의 접근 방식을 시도하여 막힐 때까지 작업해보시길 권장합니다. 이러한 연습은 작업 버전에 더 가까워지지는 않지만 GridView 및 데이터 바인딩 수명 주기에 대한 심층적인 이해를 촉진하는 데 도움이 됩니다.

템플릿에 사용자 지정 하위 수준 태그를 삽입하는 다른 방법 및 이 자습서에 사용할 방법은 템플릿에 리터럴 컨트롤 을 추가하는 것입니다. 그런 다음 GridView RowCreated 또는 RowDataBound 이벤트 처리기에서 리터럴 컨트롤에 프로그래밍 방식으로 액세스하고 해당 Text 속성을 태그로 설정하여 내보낼 수 있습니다.

먼저 TemplateField ItemTemplate에서 RadioButton을 제거하고 리터럴 컨트롤로 바꿔서 시작합니다. 리터럴 컨트롤 IDRadioButtonMarkup로 설정합니다.

ItemTemplate에 리터럴 컨트롤 추가

그림 12: 리터럴 컨트롤을 ItemTemplate 추가합니다(전체 크기 이미지를 보려면 클릭).

다음으로 GridView RowCreated 이벤트에 대한 이벤트 처리기를 만듭니다. 데이터가 RowCreated GridView에 반등하는지 여부에 관계없이 추가된 모든 행에 대해 이벤트가 한 번 발생합니다. 즉, 데이터가 뷰 상태에서 다시 로드될 때에도 포스트백 시에 RowCreated 이벤트가 계속 발생한다는 뜻이며, 이는 RowDataBound 이벤트가 데이터 웹 컨트롤에 명시적으로 바인딩될 때에만 발생하기 때문에 RowCreated을 사용하는 이유입니다.

이 이벤트 처리기에서는 데이터 행을 처리하는 경우에만 진행하려고 합니다. 각 데이터 행에 대해 프로그램적으로 리터럴 컨트롤을 참조하고 해당 RadioButtonMarkup 속성을 내보낼 태그로 설정하려고 합니다. 다음 코드에 나타난 바와 같이, 내보낸 마크업은 name 속성이 SuppliersGroup로 설정된 라디오 버튼을 생성합니다. 또한, id 속성이 RowSelectorX로 설정되며, X는 GridView 행의 인덱스이고, value 속성 또한 GridView 행의 인덱스로 설정됩니다.

protected void Suppliers_RowCreated(object sender, GridViewRowEventArgs e)
{
    if (e.Row.RowType == DataControlRowType.DataRow)
    {
        // Grab a reference to the Literal control
        Literal output = (Literal)e.Row.FindControl("RadioButtonMarkup");
        // Output the markup except for the "checked" attribute
        output.Text = string.Format(
            @"<input type="radio" name="SuppliersGroup" " +
            @"id="RowSelector{0}" value="{0}" />", e.Row.RowIndex);
    }
}

GridView 행이 선택되고 포스트백이 발생하면, 우리는 선택한 공급업체의 SupplierID를 확인합니다. 따라서 각 라디오 단추의 값은 GridView 행의 인덱스가 아닌 실제 SupplierID 값이어야 한다고 생각할 수 있습니다. 이는 특정 상황에서 작동할 수 있지만 맹목적으로 받아들이고 처리하는 것은 보안 위험입니다 SupplierID. 예를 들어 GridView는 미국의 공급업체만 나열합니다. 그러나 SupplierID가 라디오 버튼에서 직접 전달되는 경우, 장난스러운 사용자가 SupplierID 값을 포스트백으로 보낼 때 조작하지 못하게 하려면 어떻게 해야 할까요? 행 인덱스를 value로 사용하고, SupplierID 컬렉션에서 DataKeys을 포스트백 시 가져오면 사용자가 GridView 행 중 하나와 연결된 SupplierID 값 중 하나만 사용하고 있는지 확인할 수 있습니다.

이 이벤트 처리기 코드를 추가한 후 브라우저에서 페이지를 테스트하는 데 1분이 소요됩니다. 먼저 그리드의 라디오 단추 하나만 한 번에 선택할 수 있습니다. 그러나 라디오 단추를 선택하고 단추 중 하나를 클릭하면 포스트백이 발생하고 라디오 단추가 모두 초기 상태로 되돌아갑니다(즉, 포스트백 시 선택한 라디오 단추가 더 이상 선택되지 않음). 이 문제를 해결하려면 RowCreated 이벤트 처리기를 포스트백으로 전송된 선택한 라디오 버튼 인덱스를 검사하여, 해당 행 인덱스가 일치하는 경우 내보내는 태그에 checked="checked" 특성을 추가하도록 해야 합니다.

포스트백이 발생하면 브라우저는 선택한 라디오 단추의 namevalue를 다시 보냅니다. Request.Form["name"]을 사용하여 값을 프로그래밍 방식으로 검색할 수 있습니다. 이 속성은Request.Form 양식 변수를 나타내는 형식을 제공합니다NameValueCollection. 양식 변수는 웹 페이지에 있는 양식 필드의 이름과 값이며, 포스트백이 계속될 때마다 웹 브라우저에서 다시 전송됩니다. GridView에서 라디오 단추의 렌더링된 name 특성이 있기 SuppliersGroup때문에 웹 페이지가 다시 게시되면 브라우저가 웹 서버(다른 양식 필드와 함께)로 다시 전송 SuppliersGroup=valueOfSelectedRadioButton 됩니다. 이 정보는 Request.Form 속성에서 Request.Form["SuppliersGroup"]를 사용하여 액세스할 수 있습니다.

이벤트 처리기뿐만 아니라 버튼 웹 컨트롤의 RowCreated 이벤트 처리기에서도 선택한 라디오 버튼의 인덱스를 결정해야 하므로, 코드 숨김 클래스에 Click 속성을 추가하여 라디오 버튼이 선택되지 않은 경우에는 SuppliersSelectedIndex를 반환하고, 하나의 라디오 버튼이 선택된 경우 그 선택된 인덱스를 반환하도록 해보겠습니다.

private int SuppliersSelectedIndex
{
    get
    {
        if (string.IsNullOrEmpty(Request.Form["SuppliersGroup"]))
            return -1;
        else
            return Convert.ToInt32(Request.Form["SuppliersGroup"]);
    }
}

이 속성이 추가되면, checked="checked"RowCreated와 같을 때 SuppliersSelectedIndex 이벤트 처리기에서 e.Row.RowIndex 태그를 추가해야 한다는 것을 알게 됩니다. 다음 논리를 포함하도록 이벤트 처리기를 업데이트합니다.

protected void Suppliers_RowCreated(object sender, GridViewRowEventArgs e)
{
    if (e.Row.RowType == DataControlRowType.DataRow)
    {
        // Grab a reference to the Literal control
        Literal output = (Literal)e.Row.FindControl("RadioButtonMarkup");
        // Output the markup except for the "checked" attribute
        output.Text = string.Format(
            @"<input type="radio" name="SuppliersGroup" " +
            @"id="RowSelector{0}" value="{0}"", e.Row.RowIndex);
        // See if we need to add the "checked" attribute
        if (SuppliersSelectedIndex == e.Row.RowIndex)
            output.Text += @" checked="checked"";
        // Add the closing tag
        output.Text += " />";
    }
}

이 변경으로 선택한 라디오 단추는 포스트백 후에 선택된 상태로 유지됩니다. 이제 선택한 라디오 단추를 지정할 수 있으므로 페이지가 처음 방문되었을 때 첫 번째 GridView 행의 라디오 단추가 선택되도록 동작을 변경할 수 있습니다(기본적으로 현재 동작인 라디오 단추가 선택되지 않음). 기본적으로 첫 번째 라디오 단추를 선택하려면 문을 다음if (SuppliersSelectedIndex == e.Row.RowIndex)으로 변경 if (SuppliersSelectedIndex == e.Row.RowIndex || (!Page.IsPostBack && e.Row.RowIndex == 0)) 하기만 하면됩니다.

이 시점에서 페이지 다시 로드 시 선택된 단일 GridView 행이 저장될 수 있도록 그룹화된 라디오 버튼 열을 GridView에 추가했습니다. 다음 단계는 선택한 공급업체에서 제공하는 제품을 표시하는 것입니다. 4단계에서는 사용자를 다른 페이지로 리디렉션하여 선택한 SupplierID페이지를 따라 보내는 방법을 살펴보겠습니다. 5단계에서는 선택한 공급업체 제품을 동일한 페이지의 GridView에 표시하는 방법을 알아봅니다.

비고

TemplateField(이 긴 3단계의 초점)를 사용하는 대신 적절한 사용자 인터페이스 및 기능을 렌더링하는 사용자 지정 DataControlField 클래스를 만들 수 있습니다. 클래스는 DataControlField BoundField, CheckBoxField, TemplateField 및 기타 기본 제공 GridView 및 DetailsView 필드가 파생되는 기본 클래스입니다. 사용자 지정 DataControlField 클래스를 만들면 선언적 구문을 사용하여 라디오 단추 열을 추가할 수 있으며 다른 웹 페이지 및 기타 웹 애플리케이션의 기능을 훨씬 쉽게 복제할 수 있습니다.

그러나 ASP.NET 컴파일된 사용자 지정 컨트롤을 만든 적이 있는 경우 이렇게 하려면 상당한 양의 레그워크가 필요하며 신중하게 처리해야 하는 미묘한 요소와 에지 케이스가 수반된다는 것을 알고 있습니다. 따라서 지금은 라디오 단추 열을 사용자 지정 DataControlField 클래스로 구현하는 것을 포기하고 TemplateField 옵션을 고수합니다. 향후 자습서에서는 사용자 지정 DataControlField 클래스를 만들고, 사용하고, 배포하는 방법을 살펴볼 수 있습니다.

4단계: 개별 페이지에 선택한 공급업체 제품 표시

사용자가 GridView 행을 선택한 후에는 선택한 공급업체 제품을 표시해야 합니다. 경우에 따라 이러한 제품을 별도의 페이지에 표시하고, 다른 경우에는 동일한 페이지에서 제품을 표시하는 것을 선호할 수 있습니다. 먼저 별도의 페이지에서 제품을 표시하는 방법을 살펴보겠습니다. 5단계에서는 GridView RadioButtonField.aspx 를 추가하여 선택한 공급업체 제품을 표시하는 방법을 살펴보겠습니다.

현재 페이지에 두 개의 버튼 웹 컨트롤 ListProductsSendToProducts가 있습니다. SendToProducts 단추를 클릭하면 사용자를 ~/Filtering/ProductsForSupplierDetails.aspx로 보내려고 합니다. 이 페이지는 두 페이지의 마스터/세부 정보 필터링 자습서에서 만들어졌으며 명명SupplierID된 쿼리 문자열 필드를 통해 전달되는 공급자 SupplierID 의 제품을 표시합니다.

이 기능을 제공하려면 Button SendToProducts 이벤트에 대한 Click 이벤트 처리기를 만듭니다. 3단계에서 라디오 단추가 선택된 행의 인덱스를 반환하는 속성 SuppliersSelectedIndex을(를) 추가했습니다. 해당 SupplierID는 GridView의 DataKeys 컬렉션에서 검색할 수 있으며, ~/Filtering/ProductsForSupplierDetails.aspx?SupplierID=SupplierID를 사용하여 사용자를 Response.Redirect("url")로 보낼 수 있습니다.

protected void SendToProducts_Click(object sender, EventArgs e)
{
    // Send the user to ~/Filtering/ProductsForSupplierDetails.aspx
    int supplierID = 
        Convert.ToInt32(Suppliers.DataKeys[SuppliersSelectedIndex].Value);
    Response.Redirect(
        "~/Filtering/ProductsForSupplierDetails.aspx?SupplierID=" 
        + supplierID);
    }
}

이 코드는 GridView에서 라디오 단추 중 하나를 선택하는 한 멋지게 작동합니다. 처음에 GridView에 라디오 버튼이 선택되어 있지 않은 상태에서 사용자가 SendToProducts 버튼을 클릭하면, SuppliersSelectedIndex이(가) -1이므로 예외가 발생하게 됩니다. 이는 -1DataKeys 컬렉션의 인덱스 범위에서 벗어나기 때문입니다. 그러나 GridView의 첫 번째 라디오 단추를 처음에 선택하도록 3단계에서 설명한 대로 이벤트 처리기를 업데이트 RowCreated 하기로 결정한 경우에는 문제가 되지 않습니다.

SuppliersSelectedIndex 값을 -1로 수용하기 위해, GridView 위의 페이지에 Label 웹 컨트롤을 추가하세요. ID 속성을 ChooseSupplierMsg로 설정하고, CssClass 속성을 Warning로 설정하며, EnableViewStateVisible 속성을 false로 설정하고, Text 속성을 표에서 공급자를 선택하세요. CSS 클래스 Warning 는 빨간색, 기울임꼴, 굵은 글꼴, 큰 글꼴로 텍스트를 표시하며 에 정의되어 있습니다 Styles.css. EnableViewStateVisible 속성을 false으로 설정하면, Control의 Visible 속성이 프로그래밍 방식으로 true으로 설정된 경우를 제외하고, Label은 렌더링되지 않습니다.

GridView 위에 레이블 웹 컨트롤 추가

그림 13: GridView 위에 레이블 웹 컨트롤 추가(전체 크기 이미지를 보려면 클릭)

다음으로, Click 이벤트 처리기를 확장하여 ChooseSupplierMsg가 0보다 작은 경우에는 SuppliersSelectedIndex 레이블을 표시하고, 그렇지 않으면 사용자를 ~/Filtering/ProductsForSupplierDetails.aspx?SupplierID=SupplierID로 리디렉션합니다.

protected void SendToProducts_Click(object sender, EventArgs e)
{
    // make sure one of the radio buttons has been selected
    if (SuppliersSelectedIndex < 0)
        ChooseSupplierMsg.Visible = true;
    else
    {
        // Send the user to ~/Filtering/ProductsForSupplierDetails.aspx
        int supplierID = 
            Convert.ToInt32(Suppliers.DataKeys[SuppliersSelectedIndex].Value);
        Response.Redirect(
            "~/Filtering/ProductsForSupplierDetails.aspx?SupplierID=" 
            + supplierID);
    }
}

GridView에서 공급업체를 선택하기 전에 브라우저에서 페이지를 방문하고 단추를 클릭합니다 SendToProducts . 그림 14와 같이 레이블이 ChooseSupplierMsg 표시됩니다. 다음으로 공급업체를 선택하고 단추를 클릭합니다 SendToProducts . 그러면 선택한 공급업체에서 제공하는 제품이 나열된 페이지로 이동됩니다. 그림 15는 빅풋 양조장 공급업체가 선택된 ProductsForSupplierDetails.aspx 페이지를 보여줍니다.

공급자를 선택하지 않으면 SelectSupplierMsg 레이블이 표시됩니다.

그림 14: ChooseSupplierMsg 공급자가 선택되지 않은 경우 레이블이 표시됩니다(전체 크기 이미지를 보려면 클릭).

선택한 공급업체 제품이 ProductsForSupplierDetails.aspx 표시됨

그림 15: 선택한 공급업체 제품이 표시됩니다 ProductsForSupplierDetails.aspx (전체 크기 이미지를 보려면 클릭).

5단계: 동일한 페이지에 선택한 공급업체 제품 표시

4단계에서는 사용자를 다른 웹 페이지로 보내 선택한 공급업체 제품을 표시하는 방법을 알아보았습니다. 또는 선택한 공급업체 제품을 동일한 페이지에 표시할 수 있습니다. 이를 설명하기 위해 다른 GridView를 RadioButtonField.aspx 추가하여 선택한 공급업체 제품을 표시합니다.

공급업체가 선택된 후에만 제품의 이 GridView를 표시하도록 하려면 GridView 아래에 Suppliers 패널 웹 컨트롤을 추가하고 해당 IDProductsBySupplierPanelVisible 속성을 false로 설정합니다. 패널 내에서 선택한 공급업체에 대한 "제품" 텍스트를 추가하고, 이름이 ProductsBySupplier인 GridView를 추가합니다. GridView의 스마트 태그에서 새 ObjectDataSource에 ProductsBySupplierDataSource바인딩하도록 선택합니다.

ProductsBySupplier GridView를 새 ObjectDataSource에 바인딩

그림 16: GridView를 ProductsBySupplier 새 ObjectDataSource에 바인딩(전체 크기 이미지를 보려면 클릭)

다음으로, 클래스를 사용하도록 ObjectDataSource를 구성합니다 ProductsBLL . 선택한 공급업체에서 제공하는 제품만 검색하려고 하므로 ObjectDataSource에서 메서드를 호출 GetProductsBySupplierID(supplierID) 하여 해당 데이터를 검색하도록 지정합니다. UPDATE, INSERT 및 DELETE 탭의 드롭다운 목록에서 (없음)을 선택합니다.

GetProductsBySupplierID(supplierID) 메서드를 사용하도록 ObjectDataSource 구성

그림 17: 메서드를 사용하도록 GetProductsBySupplierID(supplierID) ObjectDataSource 구성(전체 크기 이미지를 보려면 클릭)

UPDATE, INSERT 및 DELETE 탭에서 Drop-Down 목록을 (없음)으로 설정

그림 18: UPDATE, INSERT 및 DELETE 탭에서 Drop-Down 목록을 (없음)으로 설정합니다(전체 크기 이미지를 보려면 클릭).

SELECT, UPDATE, INSERT 및 DELETE 탭을 구성한 후 다음을 클릭합니다. 메서드에 GetProductsBySupplierID(supplierID) 입력 매개 변수가 예상되므로 데이터 원본 만들기 마법사는 매개 변수 값의 원본을 지정하라는 메시지를 표시합니다.

매개 변수 값의 원본을 지정하는 몇 가지 옵션이 있습니다. 기본 Parameter 개체를 사용하고 ObjectDataSource SuppliersSelectedIndex 이벤트 DefaultValue 처리기의 Parameter Selecting 속성에 속성 값을 프로그래밍 방식으로 할당할 수 있습니다. ObjectDataSource의 매개 변수 값 설정을 프로그래밍 방식으로 수행하는 방법을 상기하기 위해 해당 자습서를 참조하세요.

또는 ControlParameter를 사용하여 Suppliers GridView의 SelectedValue 속성을 참조할 수 있습니다(그림 19 참조). GridView의 SelectedValue 속성은 속성에 DataKey 해당하는 값을 반환합니다SelectedIndex. 이 옵션이 작동하려면 단추를 클릭할 때 SelectedIndex GridView 속성을 ListProducts 선택한 행으로 프로그래밍 방식으로 설정해야 합니다. 추가 혜택으로, SelectedIndex을(를) 설정하면 선택한 레코드가 SelectedRowStyle 테마(노란색 배경색)에 정의된 DataWebControls을(를) 사용하게 됩니다.

ControlParameter를 사용하여 GridView의 SelectedValue를 매개 변수 원본으로 지정

그림 19: ControlParameter를 사용하여 GridView의 SelectedValue를 매개 변수 원본으로 지정합니다(전체 크기 이미지를 보려면 클릭).

마법사를 완료하면 Visual Studio에서 제품 데이터 필드에 대한 필드를 자동으로 추가합니다. ProductName, CategoryName, UnitPrice BoundFields를 제외한 모든 항목을 제거하고 HeaderText 속성을 Product, Category 및 Price로 변경하십시오. 해당 값이 UnitPrice 통화 형식으로 지정되도록 BoundField를 구성합니다. 이러한 변경을 수행한 후 Panel, GridView 및 ObjectDataSource의 선언적 태그는 다음과 같이 표시됩니다.

<asp:Panel runat="server" ID="ProductsBySupplierPanel" Visible="False">
    <h3>
        Products for the Selected Supplier</h3>
    <p>
        <asp:GridView ID="ProductsBySupplier" runat="server" 
            AutoGenerateColumns="False" DataKeyNames="ProductID"
            DataSourceID="ProductsBySupplierDataSource" EnableViewState="False">
            <Columns>
                <asp:BoundField DataField="ProductName" HeaderText="Product" 
                    SortExpression="ProductName" />
                <asp:BoundField DataField="CategoryName" HeaderText="Category" 
                    ReadOnly="True" SortExpression="CategoryName" />
                <asp:BoundField DataField="UnitPrice" DataFormatString="{0:c}" 
                    HeaderText="Price" HtmlEncode="False" 
                    SortExpression="UnitPrice" />
            </Columns>
        </asp:GridView>
        <asp:ObjectDataSource ID="ProductsBySupplierDataSource" runat="server" 
            OldValuesParameterFormatString="original_{0}"
            SelectMethod="GetProductsBySupplierID" TypeName="ProductsBLL">
            <SelectParameters>
                <asp:ControlParameter ControlID="Suppliers" Name="supplierID" 
                    PropertyName="SelectedValue" Type="Int32" />
            </SelectParameters>
        </asp:ObjectDataSource>
    </p>
</asp:Panel>

이 연습을 완료하기 위해서는, SelectedIndex 버튼이 클릭될 때 GridView의 SelectedSuppliersIndex 속성을 ProductsBySupplierPanel로 설정하고, Panel의 Visible 속성을 true로 설정해야 합니다. 이렇게 하려면 Button Web 컨트롤의 ListProducts 이벤트에 대한 Click 이벤트 처리기를 만들고 다음 코드를 추가합니다.

protected void ListProducts_Click(object sender, EventArgs e)
{
    // make sure one of the radio buttons has been selected
    if (SuppliersSelectedIndex < 0)
    {
        ChooseSupplierMsg.Visible = true;
        ProductsBySupplierPanel.Visible = false;
    }
    else
    {
        // Set the GridView's SelectedIndex
        Suppliers.SelectedIndex = SuppliersSelectedIndex;
        // Show the ProductsBySupplierPanel panel
        ProductsBySupplierPanel.Visible = true;
    }
}

GridView ChooseSupplierMsg 에서 공급업체를 선택하지 않은 경우 레이블이 표시되고 패널이 ProductsBySupplierPanel 숨겨집니다. 그렇지 않으면 공급자가 선택된 ProductsBySupplierPanel 경우 해당 공급자가 표시되고 GridView의 SelectedIndex 속성이 업데이트됩니다.

그림 20은 Bigfoot 양조장 공급업체가 선택되고 페이지에 제품 표시 단추를 클릭한 후의 결과를 보여 줍니다.

빅풋 양조장에서 제공하는 제품은 동일한 페이지에 나열됩니다.

그림 20: Bigfoot 양조장에서 제공하는 제품이 같은 페이지에 나열됩니다(전체 크기 이미지를 보려면 클릭).

요약

Master/Detail Using a Selectable Master GridView with a Details DetailView 자습서에서 설명한 대로 ShowSelectButton 속성이 true로 설정된 CommandField를 사용하여 GridView에서 레코드를 선택할 수 있습니다. 그러나 CommandField는 해당 단추를 일반 누름 단추, 링크 또는 이미지로 표시합니다. 다른 행 선택 사용자 인터페이스는 각 GridView 행에 라디오 단추 또는 확인란을 제공하는 것입니다. 이 자습서에서는 라디오 단추 열을 추가하는 방법을 검토했습니다.

아쉽게도 라디오 버튼 열을 추가하는 것은 예상만큼 간단하거나 쉬운 일이 아닙니다. 단추를 클릭할 때 추가할 수 있는 기본 제공 RadioButtonField가 없으며 TemplateField 내에서 RadioButton 웹 컨트롤을 사용하면 고유한 문제 집합이 도입됩니다. 결국 이러한 인터페이스를 제공하려면 사용자 지정 DataControlField 클래스를 만들거나 이벤트 중에 RowCreated 적절한 HTML을 TemplateField에 삽입해야 합니다.

라디오 단추 열을 추가하는 방법을 살펴보면서 확인란 열을 추가하는 데 주의를 기울이겠습니다. 확인란의 열을 사용하여 사용자는 하나 이상의 GridView 행을 선택한 다음 선택한 모든 행(예: 웹 기반 전자 메일 클라이언트에서 전자 메일 집합을 선택한 다음 선택한 모든 전자 메일을 삭제하도록 선택)에 대해 작업을 수행할 수 있습니다. 다음 자습서에서는 이러한 열을 추가하는 방법을 살펴보겠습니다.

행복한 프로그래밍!

작성자 정보

7개의 ASP/ASP.NET 책의 저자이자 4GuysFromRolla.com 창립자인 Scott Mitchell은 1998년부터 Microsoft 웹 기술을 연구해 왔습니다. Scott은 독립 컨설턴트, 트레이너 및 작가로 일합니다. 그의 최신 책은 Sams에서 배우는 ASP.NET 2.0 24시간 완성입니다. 그는 mitchell@4GuysFromRolla.com로 연락할 수 있습니다.

특별히 감사드립니다.

이 자습서 시리즈는 많은 유용한 검토자가 검토했습니다. 이 자습서의 수석 검토자는 David Suru였습니다. 예정된 MSDN 문서를 검토하는 데 관심이 있으신가요? 그렇다면 mitchell@4GuysFromRolla.com으로 메시지를 보내 주세요.