login register Sysop! about ME  
qrcode
    최초 작성일 :    2003년 07월 25일
  최종 수정일 :    2003년 07월 25일
  작성자 :    taeyo
  편집자 :    Taeyo (김 태영)
  읽음수 :    36,059

강좌 목록으로 돌아가기

필자의 잡담~

날씨가 무덥네요...  버지니아에는 벌써 코스모스가 피었음에도.. 날씨는 무덥습니다.
동부 지역이라.... 기후가 한국과 거의 같거든요....
겨우 3달 나와있었는데도... 한국에 있는 가족과 친구들이 그립네요..  ㅠ_ㅠ
다음 달에는 돌아가니깐...  돌아가면 사람들을 실컷 만나볼랍니다. 하하

대상 : ASP.NET의 기본적인 컨트롤 사용법을 뗀 이들.
선수지식 : ADO.NET 기본 지식.

저번 강좌는 재미있으셨습니까? 아무래도... 제 ASP.NET 책의 일부를 편집해서 올리는 것이라 문체가 조금은 딱딱한 감이 없지는 않습니다만..그래도 재미있으셨으리라 믿어 의심치 않아보려 할까요? -_-+

재미있으셨던, 재미가 없으셨던 강좌는 계속됩니다....
그것도 쭈~욱 말입니다. (갑자기 제가 좀 뻔뻔하다는 생각이... ㅠ_ㅠ)

Command 관련 이벤트들

이제 꽤나 재미있는 사실을 하나 알려드리도록 하겠습니다. 핫핫핫... 그것이무엇이냐? 바로 그것이 제가 [변경] 버튼 컨트롤의 CommandName 값으로 "edit"를 준 진정한 이유입니다. 사실, DataList 컨트롤은 이미 제공하고 있는 5가지 정도의 이벤트가 있어요. 그 중에 하나가 이미 우리가 사용해 본 ItemCommand 이벤트 인데요, 이는 컨트롤 내부에 위치한 어떠한 버튼 컨트롤이 클릭되던지 수행되는 이벤트입니다. 하지만, 이것이 지원되는 기능 및 이벤트의 전부는 아닌 것입니다. (두둥~) DataList는 아이템의 수정과 삭제 등의 작업을 수월하게 하기 위한 여러 가지 추가적인 이벤트들도 제공해 주고 있거든요. 예를 들면, 그들은 다음과 같아요.

이벤트설명
CancelCommandDataList 컨트롤에 있는 아이템에서 CommandName으로 cancel을 갖는 버튼을 클릭할 경우 발생하는 이벤트
DeleteCommandDataList 컨트롤에 있는 아이템에서 CommandName으로 delete를 갖는 버튼을 클릭할 경우 발생하는 이벤트
EditCommandDataList 컨트롤에 있는 아이템에서 CommandName으로 edit를 갖는 버튼을 클릭할 경우 발생하는 이벤트
ItemCommandDataList 컨트롤에 있는 아이템에서 어떠한 버튼이든지 클릭될 경우 발생하는 이벤트
UpdateCommandDataList 컨트롤에 있는 아이템에서 CommandName으로 update를 갖는 버튼을 클릭할 경우 발생하는 이벤트

표를 잘 살펴보면, DataList 컨트롤 내부에 버튼 컨트롤이 존재할 경우, 그 버튼 컨트롤의 CommandName에 따라 4가지 정도의 이벤트가 더 지원된다는 것을 알 수 있을 것입니다. 즉, 좀 전의 예제와 같이 CommandName으로 "edit" 라는 값을 갖는 버튼이 클릭된다면, EditCommand 라는 이벤트도 발생한다는 것이지요. 그러므로, 사실 "edit"라는 CommandName 속성 값을 갖는 버튼이 클릭되었을 경우의 처리는 ItemCommand 가 아닌 EditCommand 에서 하는 것이 보다 효과적이라 볼 수 있다는 것이옵니다. 그렇다면, 소스를 그렇게 한번 바꾸어 보도록 해요.

EditCommand

웹 폼 디자인 모드로 가서 DataList를 선택한 다음 [속성 창]에서 번개 모양의 버튼을 클릭한 뒤, 출력되는 이벤트들 중에서 EditCommand를 선택하고, 우측 칸에서 더블 클릭을 하십니당.

그러면, 코드 비하인드 페이지로 저절로 이동하면서, 자동으로 DataList1_EditCommand 이벤트 처리기가 생성되어져 있을 거예요. 이미 언급했듯이, 이는 DataList 내의 버튼 컨트롤 중 CommandName속성의 값으로 "edit"를 갖는 버튼 컨트롤이 눌렸을 경우 발생하는 이벤트입니다. 그렇다면, 이제 이 곳에 다음과 같은 코드를 작성해 보도록 하세요.(그리고, 기존에 ItemCommand에 작성한 edit와 관계된 if 문은 제거하도록 하시옵소서~~)

private void DataList1_EditCommand(object source,
    System.Web.UI.WebControls.DataListCommandEventArgs e)
{
    DataList1.EditItemIndex = e.Item.ItemIndex;
    BindDataList();
}

private void DataList1_ItemCommand(object source,
    System.Web.UI.WebControls.DataListCommandEventArgs e)
{
    DataList1.SelectedIndex = e.Item.ItemIndex;
    BindDataList();
}

아주 잘했어요. 참 잘했어요~~~  오옷? 느끼스럽다?? 그렇다면,어서 서둘러 컴파일하고 결과를 확인해 보도록 하세요. 느끼함을 날려버리기 위해서라도 말입니다. ^^;

잘 동작하죠? 그렇습니다. 하지만, 뭔가 이상한 점은 느껴지지 않나요? 여러아이템을 번갈아 가면서, [변경] 버튼을 클릭해 보세요. 아이템이 편집 모드로 바뀌는 것 뿐 아니라, 선택 모드도 같이 적용되고 있는 것을 확인할 수 있을 겁니다. 이게 왠 일이래~~~ -_-+ 하지만, 사실 그럴 수 밖에 없답니다. DataList 컨트롤 내의 모든 버튼 컨트롤은 클릭 시 무조건 기본적으로 ItemCommand 이벤트도 호출하기 때문이지요.

즉, 바뀐 코드대로라면 CommandName 값이 "edit"인 버튼이 눌릴 경우, 일단 무조건적으로 ItemCommand 이벤트가 수행되고, 이어서 EditCommand가 수행된다는 것입니다. 그리고, 각각의 이벤트 처리기내에서는 각각 BindDataList() 함수를 호출하고 있기에, 결과적으로 두 번의 데이터 바인딩이 일어나고 있는 것이구요. 이것은 비효율적이지 않을 수 없잖습니꺄~~~. 해서, 이 소스를 조금 더 효과적으로 바꾸는 방법은 다음과 같아요.

우선, ItemTemplate 내의 [선택] 버튼 컨트롤에게도 CommandName을 부여합니다. 다음과 같이 말이죠.

        <p>
            <asp:Button Runat="server" Text="선택" CommandName="select"></asp:Button>
            <asp:Button Runat="server" Text="변경" CommandName="edit"></asp:Button>
        </p>
    </DIV>
</ItemTemplate>

그리고, 각각의 이벤트 함수를 다음과 같이 변경합니다

private void DataList1_ItemCommand(object source,
    System.Web.UI.WebControls.DataListCommandEventArgs e)
{
    if (e.CommandName == "select")
    {
        DataList1. EditItemIndex = -1;
        DataList1.SelectedIndex = e.Item.ItemIndex;
        BindDataList();
    }
}

private void DataList1_EditCommand(object source,
    System.Web.UI.WebControls.DataListCommandEventArgs e)
{
    DataList1. SelectedIndex = -1;
    DataList1.EditItemIndex = e.Item.ItemIndex;
    BindDataList();
}

이렇게 바꾸면, ItemCommand 이벤트 처리기의 코드는 버튼 컨트롤의 CommandName 값이 "select"인 경우에만 동작하게 될 것이며, CommandName 값이 "edit"인 경우에는 무시될 것이기에 보다 효과적이라고 볼 수 있습니다.

그리고, 소스에서는 CommandName 값이 "select" 인 경우에는 DataList의 EditItemIndex 값을 -1로 부여하고 있으며, CommandName 값이 "edit" 인 경우에는 DataList의 SelectedIndex 값을 -1로 부여하고 있는데요, 이 -1 이라는 값은 각각의 설정을 취소하겠다는 의미입니다. 즉, 어떤 아이템이 [선택]되었을 경우에는 기존에 [변경] 모드로 존재하던 아이템을 원래의 상태로 되돌리겠다는 것을 의미하는 것이구요, 어떤 아이템이 [변경]되는 경우에는 기존에 [선택] 모드로 존재하던 아이템을 원래의 상태로 되돌리겠다는 것을 의미하는 것입니다. 만일, 이러한 코드를 추가하지 않으면, 결과 화면에서 [선택]과 [변경]이 각각 따로 노는 것을 볼 수 있을 거예요.

이제, 버튼의 CommandName이 edit 인 경우에는 ItemCommand이벤트의 내부 처리는 건너뛰게 될 것이고, EditCommand 의 처리에만 집중하게 될 것입니다. 그리고, 버튼의 CommandName이 select 인 경우에는 ItemCommand 내부의 처리에만 집중하게 될 것이고 말입니다. 그렇습니다. 계획한 대로 동작하게 만든 것이죠~~~

UpdateCommand

좋습니다. 좋구요~~ 이번에는 남아있는 3개의 이벤트를 한번에 다루어 보도록 해요. CancelCommand, DeleteCommand, UpdateCommand 가 바로 그것인데요, 이들은 각각 "cancel", "delete", "update" 란 CommandName을 가진 버튼이 클릭될 경우 호출되는 이벤트라는 것을 기억하세요. 물론, 각각의 이벤트가 호출되기 전에 이들은 분명 ItemCommand 이벤트도 거치게 될 것입니다. 이들도 모두 버튼 컨트롤이니 말입니다. 하지만, ItemCommand 이벤트 내의 실제 처리는 CommandName이 select인 경우에만 수행될 것이기에, ItemCommand 이벤트 처리기내의 코드들에 대해서는 이제 더 이상 신경을 쓸 필요가 없습니다. 그렇겠죠? 

cancel, update, delete 라는 업무는 [변경] 모드에서수행되어야 할 작업들입니다. 그러므로, 이러한 버튼이 위치해야 할 곳은 [변경] 모드인 EditItemTemplate 내부가 되어야 할 것이라는 것은 어렵지 않게 예상하실 수 있을 것입니다. 다음과 같은 코드를 EditItemTemplate에 추가로 작성해 보도록 하세요. (참고로, 이 모든 처리가 추가된 코드는 다운로드 받은 파일 중에서 DataListEx1plus4.aspx라는 이름으로 제공되고 있습니다)

    <EditItemTemplate>
        <DIV>
            <IMG hspace="10" align="left" src='http://localhost/quickstart/ASPPlus/images/Title-
                <%# DataBinder.Eval(Container.DataItem, "title_id") %>.gif' >
            제목 :
            <asp:TextBox Runat="server" BorderStyle="Groove" width="250" ID="title"
                NAME="title" Text='<%# DataBinder.Eval(Container.DataItem, "title") %>'>
            </asp:TextBox>
            <BR>
            가격 :
            <asp:TextBox Runat="server" BorderStyle="Groove" ID="price" NAME=" price "
                Text='<%# DataBinder.Eval(Container.DataItem, "price") %>'></asp:TextBox>
            <BR>
         <asp:TextBox Runat="server" BorderStyle="Groove" TextMode="MultiLine" Rows="5"
                Width="300" Text='<%# DataBinder.Eval(Container.DataItem, "notes") %>'
                ID="notes" NAME=" notes "></asp:TextBox>
            <p>
                <asp:Button Runat="server" Text="업데이트" CommandName="update"
              CommandArgument='<%# DataBinder.Eval(Container.DataItem, "title_id") %>'>
                </asp:Button>
                <asp:Button Runat="server" Text="삭제" CommandName="delete"
              CommandArgument='<%# DataBinder.Eval(Container.DataItem, "title_id") %>'>
                </asp:Button>
                <asp:Button Runat="server" Text="취소" CommandName="cancel"
              CommandArgument='<%# DataBinder.Eval(Container.DataItem, "title_id") %>'>
                </asp:Button>
            </p>
        </DIV>
    </EditItemTemplate>

각각의 버튼이 자신의 아이템에 해당하는 title_id 값을 CommandArgument로 설정하고 있는 것을 잘 기억하기 바래요. 각각의 버튼이 클릭될 경우, 어떤 책이 업데이트 및 삭제되어야 하는지를 서버에서 알 수 있으려면 그 값(title_id)을 서버로 넘겨줄 수 있어야 할 것이고, 그를 위한 최적의 장소는 버튼 컨트롤의 CommandArgument이기 때문입니다. 또한, 서버측의 XXXCommand 이벤트 코드에서도 버튼 컨트롤의 CommandName 값과 CommandArgument 값은 쉽게 얻어낼 수 있기 때문에 각 책의 title_id 값은 버튼의 CommandArgument로서 주는 것이 바람직할 것이기도 합니다. 일단, 현재의 상태에서 페이지를 컴파일하고 결과를 살펴보도록 하죠. [변경] 버튼이 클릭될 경우, 이러한 버튼들은 나타날 것이랍니다. 다음과 같이 말이죠 ^^

하지만, 우리는 아직 각각의 버튼이 클릭되었을 경우에의 처리는 작성되지 않았습니다. 그것을 지금부터 하나씩 작성해 나가보도록 해요. 시작은 UpdateCommand로 하겠습니다. 웹 폼 디자인 모드로 가서 DataList를 선택한 다음 [속성 창]에서 번개 모양의 버튼을 클릭한 뒤, 출력되는 이벤트들 중에서 UpdateCommand를 선택하고, 우측 칸에서 더블 클릭을 하세요. (아구.. 복잡하죠???  ^^)

그러면, 코드 비하인드 페이지로 이동하며, 자동으로 DataList1_UpdateCommand 이벤트 처리기가 생성되어져 있을 것입니다. 이미 언급했듯이, 이는 DataList 내의 버튼 컨트롤 중 CommandName속성의 값으로 "update"를 갖는 버튼 컨트롤이 눌렸을 경우 발생하는 이벤트입니다. 자... 이제 이 곳에 다음과 같은 코드를 작성해 보도록 합시다요~

    private void DataList1_UpdateCommand(object source,
        System.Web.UI.WebControls.DataListCommandEventArgs e)
    {
        string title = ((TextBox)e.Item.FindControl("title")).Text;
        string price = ((TextBox)e.Item.FindControl("price")).Text;
        string notes = ((TextBox)e.Item.FindControl("notes")).Text;
        string title_id = (string)e.CommandArgument;

        string strSQL = "UPDATE Titles SET title=@title, price=@price, notes=@notes "
            + " WHERE title_id=@title_id";

        SqlConnection Con = new SqlConnection(connectStr);
        SqlCommand Cmd = new SqlCommand(strSQL, Con);

        Cmd.Parameters.Add("@title", SqlDbType.VarChar, 80);
        Cmd.Parameters.Add("@price", SqlDbType.Money);
        Cmd.Parameters.Add("@notes", SqlDbType.VarChar, 200);
        Cmd.Parameters.Add("@title_id", SqlDbType.VarChar, 6);

        Cmd.Parameters["@title"].Value = title;
        Cmd.Parameters["@price"].Value = price;
        Cmd.Parameters["@notes"].Value = notes;
        Cmd.Parameters["@title_id"].Value = title_id;

        Con.Open();
        Cmd.ExecuteNonQuery();
        Con.Close();

        DataList1.EditItemIndex = -1;
        BindDataList();
    }

코드에서 실제로 데이터베이스에 특정 데이터를 Update 하는 부분은 여기서 별도로 언급하지는 않을 것입니다. 여러분이 이미 ADO.NET의 사용법에 대한 어느정도의 내공이 있다고 가정하고 이 강좌를 진행하고 있기 때문이지요. ^^ (양해해 주세요. ADO.NET의 사용법에 대해서는 나중에 별도로 다루어보는 시간을 갖도록 할테니까요 ^^)

이 예제에서의 문제는 사용자가 텍스트박스에 변경한 값을 어떻게 가져오느냐!! 입니다. 각 컨트롤의 고유한 ID는 동적으로 재 설정되기에 프로그래밍 코드에서 각각의 컨트롤을 ID로 찾아 들어가는 것은 매우 어려운 편입니다. 그렇다면, 어떻게 해야 할까요? 알고보면 모든 것은 간단하지요 ^^. 그 모든 해결방법을 메서드의 인자인 DataListCommandEventArgs 개체가 제공해 주니까요.

DataListCommandEventArgs 개체의 Item 속성은 현재 아이템 자체를 나타내고 있는 개체이며, 그 Item 개체는 FindControl 이라는 유용한 메서드를 제공한답니다. 이는 현재의 아이템(즉, 템플릿) 내에서 특정 이름을 갖는 컨트롤을 찾아오는 역할을 하기에, e.Item.FindControl("컨트롤의 이름") 과 같은 코드를 통해서 해당 컨트롤의 참조를 쉽게 얻어올 수가 있어요. 단, 그 컨트롤은 Control 타입으로 넘어오기에 이를 사용하기 전에는 반드시 자신의 정확한 타입으로 형 변환을 시켜준 다음 사용할 필요가 있다는 점은 주의하셔야 합니다.

해서, 소스 중에 있는((TextBox)e.Item.FindControl("title"))라는 코드는 현재 사용자가 이벤트를 발생시킨 항목(아이템)에서 title 이라는 이름을 갖는 컨트롤을 찾은 다음, 즉 e.Item.FindControl("title") 를 수행한 다음 그 컨트롤을 TextBox 타입으로 형변환 하는 코드인 것입니다. 그러므로, 이런 식으로 각각의 TextBox에 입력된 값을 얻어올 수 있는 것이죠.

string title = ((TextBox)e.Item.FindControl("title")).Text;
string price = ((TextBox)e.Item.FindControl("price")).Text;
string notes = ((TextBox)e.Item.FindControl("notes")).Text;

하지만, 현재 아이템의 title_id의 값은 좀 더 쉽게 얻어낼 수 있는데요, 이는 우리가 그 값을 버튼 컨트롤의 CommandArgument로 지정해 두었기 때문입니다. 버튼 컨트롤의 CommandName과 CommandArgument은 서버측 이벤트 메서드의 두 번째 인자인 DataListCommandEventArgs를 통해서 쉽게 얻어올 수가 있어요. 다음과 같이 말이죠.

string title_id = (string)e.CommandArgument;

각각의 값들을 모두 얻어냈다면, 이후의 작업은 데이터베이스를 열고, UPDATE 질의를 수행하는 것입니다.  모든 데이터베이스 작업이 끝났다면 Connection 개체를 Close 하고 난 다음, 현재 [변경] 모드로 되어져 있는 아이템을 원래의 모드로 되돌리기 위해서 다음과 같이 EditItemIndex 값을 -1로 되돌리고, 데이터를 다시금 바인딩 하면 됩니다.

DataList1.EditItemIndex = -1;
BindDataList();

모두 이해되었다면, 페이지를 컴파일하고 실행해보도록 하세요. 그리고, [변경] 모드에서 데이터를 적절히 수정한 다음, [update] 버튼을 눌러 그 내용이 실제로 변경되는지 확인해 보도록 하세요. 우리의 기대대로 매우 잘 동작할 것임이 자명합니다. ^^

CancelCommand

이제는 CancelCommand 부분을 한번 다루어 보도록 하겠습니다. 이전과 같은 방법으로 웹 폼 디자인 모드로 가서 DataList를 선택한 다음 [속성 창]에서 번개 모양의 버튼을 클릭한 뒤, 출력되는 이벤트들 중에서 CancelCommand를 선택하고, 우측 칸에서 더블 클릭을 하세요. 그러면, 코드 비하인드 페이지로 이동되며, 자동으로 DataList1_DeleteCommand 이벤트 처리기가 생성되어져 있을 것입니다. 그 구역에 다음과 같은 코드를 작성해 보도록 하겠습니다.

    private void DataList1_CancelCommand(object source,
        System.Web.UI.WebControls.DataListCommandEventArgs e)
    {
        DataList1.EditItemIndex = -1;
        BindDataList();
    }

작업을 취소하는 cancel 일 경우는 어떠한 작업도 필요치 않습니다. 단지, 현재 [변경] 모드인 것을 기존의 상태로 되돌리기만 하면 되는 것이죠. 해서, 소스는 DataList 의 EditItemIndex 값을 -1로 설정하고, 데이터 바인드를 반복하는 것이 전부인 것이랍니다.

DeleteCommand

마지막으로, DeleteCommand 의 코드도 같은 방법으로 작성해 보도록 하겠습니다. [속성 창]에서 번개 모양의 버튼을 클릭한 뒤, DeleteCommand를 선택하고, 우측 칸에서 더블 클릭을 하면 코드 비하인드 페이지로 이동할 것이며, 자동으로 DataList1_DeleteCommand 이벤트 처리기는 생성되어질 것입니다. 기존과 마찬가지로 말입니다 ^^. 

특정 레코드를 삭제하기 위해서는 단지 해당 레코드의 기본 키 컬럼 값만을 알면 되며, titles 테이블에서의 그 키는 title_id 이므로 이번의 코드는 그다지 특별한 내용은 없습니다. 굳이 소스를 보여준다면 코드는 다음과 같을 것 같네요. (그러나, 이를 작성하기는 하되 실행하지는 말아주세요)

    private void DataList1_DeleteCommand(object source,
        System.Web.UI.WebControls.DataListCommandEventArgs e)
    {
        string title_id = (string)e.CommandArgument;

        string strSQL = "DELETE Titles WHERE title_id = @title_id";

        string connectStr = "Server=(local); database=Pubs; user id=sa";
        SqlConnection Con = new SqlConnection(connectStr);
        SqlCommand Cmd = new SqlCommand(strSQL, Con);

        Cmd.Parameters.Add("@title_id", SqlDbType.VarChar, 6);
        Cmd.Parameters["@title_id"].Value = title_id;

        Con.Open();
        Cmd.ExecuteNonQuery();
        Con.Close();

        DataList1.EditItemIndex = -1;
        BindDataList();
    }

코드에서 특별히 새로운 것은 없습니다. 단지, DELETE 질의를 수행하는 것이 전부이지요. 하지만, 이 코드를 작성하고 막상 페이지를 실행하여 특정 아이템을 삭제하려 한다면 예외가 발생할 겁니다. 이는 데이터베이스 테이블들의 관계성에 따른 문제로써, titles 테이블은 여러 다른 테이블들과 관계를 맺고 있어서, 함부로 titles 테이블의 데이터를 삭제할 수가 없기 때문에 발생하는 예외입니다. 이는 Titles 테이블 자체의 특수성으로 인한 문제이지 로직상의 문제는 아니라는 점을 말씀드리고 싶네요 ^^

해서, 실제 코드에서는 코드의 마지막 부분인 다음 구역을 제외하고는 모두 주석처리를 하도록 하겠슴다.

DataList1.EditItemIndex = -1;
BindDataList();

C#에서의 주석처리는 각각의 라인 앞에 // 라는 문자를 달아주면 됩니다. 혹은 블록 단위로 주석을 걸어주고 싶다면 /* */ 를 사용할 수도 있습니다.

이제 페이지는 완성되었습니다. 여러분은 DataList를 통해서 원하는 데이터들의 출력을 쉽게 만들어 낼 수 있을 것이며, 각각의 아이템을 선택, 변경, 업데이트, 삭제할 수 있을 것입니다. 축하합니다. ^^;

DataKeyField

이제 DataList 에 대한 이야기도 어느덧 막바지에 이르고 있네요. DataList를 마무리하는 차원에서 이번에는 이 컨트롤이 가지고 있는 속성 중 매우 유용한 속성인 DataKeyField에 대한 이야기를 해보도록 하겠습니다.

DataKeyField는 지정된 데이터 원본의 키 값을 지정하기 위해서 사용되는 속성으로, 이를 사용하면 템플릿 아이템 내에 키 값을 표시하거나 나타내지 않고도 그 키 값을 사용할 수가 있습니다. 즉, 각각의 아이템의 특정 키 컬럼 값을 DataList 내에 내부적으로 저장해 놓고 사용할 수가 있다는 이야기이지요. 잘 이해가 가지 않나요? 첨에는 그럴 수 있습니다. 그렇다면 예를 들어보도록 하겠습니다. 위의 예제에서 특정 아이템의 값들을 변경하거나 혹은 삭제할 경우 우리는 어떻게 처리하였었던가요? 즉, 현재 어떤 아이템의 값을 변경하거나 삭제하려 하는 것인지 어떻게 알 수 있었죠?

예제에서는 어떤 특정 아이템의 값들을 변경하기 위해서, [업데이트] 버튼이 눌릴 경우 CommandArgument 속성의 값으로 해당 항목의 "title_id" 값을 넘기고, 그 값을 얻어와서 처리했었습니다. 바로 다음의 코드를 통해서 말입니다.

string title_id = (string)e.CommandArgument;

그리고, 이를 얻어오기 위해서, EditItemTemplate 내의 버튼들에다가CommandArgument 값들을 지정해 주었었죠. 다음과 같이 말입니다.(굳이 이 코드를 반복해서 보여드릴 필요가 있을까? 생각했지만, 뭐... 어떻습니까? 그쵸??? 공간은 넉넉하니까요~~~ 핫핫핫 )

    <asp:Button Runat="server" Text="업데이트" CommandName="update"
        CommandArgument='<%# DataBinder.Eval(Container.DataItem, "title_id") %>'>
    </asp:Button>
    <asp:Button Runat="server" Text="삭제" CommandName="delete"
        CommandArgument='<%# DataBinder.Eval(Container.DataItem, "title_id") %>'>
    </asp:Button>
    <asp:Button Runat="server" Text="취소" CommandName="cancel"
        CommandArgument='<%# DataBinder.Eval(Container.DataItem, "title_id") %>'>
    </asp:Button>

이처럼 버튼의 CommandArgument 속성을 통해서 현재 버튼이 어떤항목의 버튼인지 알려주지 않는다면, 각각의 이벤트 처리기에서 현재 [업데이트]를 하고자 하는 항목이 어떤 항목인지를 알아내기는 쉽지 않았을 것입니다. 그렇습니다. 이전에는 이렇게 처리했었지요. 그렇다고 이런 식으로 처리한 기존의 방법이 나쁘다는 것은 아닙니다. 그 방법도 좋지만, 이번에 알려주는 방법도 상당히 쓸만한 방법이라는 것이죠. 어떤 방식을 선택하던 지는 여러분의 몫입니다. (개인적으로는 이번에 알려드릴 DataKeyField 속성을 사용하는 방법을 더 선호합니다. 이 방법을 사용하면 코드량이 대폭 줄어들기 때문이지요)

여러분이 DataList의 DataKeyField 속성으로 현재 바인드된 데이터들의 키 컬럼을 지정한다면, DataList는 내부적으로 그러한 컬럼 값들을 아이템의 순서대로 보관하게 되며, 그 값들을 DataKeys 라는 컬렉션을 통해 접근할 수 있도록 한답니다.

즉, 예제의 경우 DataKeyField 속성의 값을 "title_id" 라고 지정하게 되면, DataList는 현재 바인드된 데이터들 중에서 title_id 컬럼의 값들만을 뽑아서 차례대로 DataList의 DataKeys 컬렉션에 저장해 놓는다는 것이죠. 그러므로, DataList.DataKeys[0] 은 현재 출력된 첫번째 아이템의 title_id 값이 되며, DataList.DataKeys[1] 은 현재 출력된 두 번째 아이템의 title_id 값이 된다는 이야기이구요, 이 값을 내부적으로 가지고 있게 된다는 의미입니다. 그리고, 우리가 필요할 경우는 언제든지 그 값을 불러올 수도 있고 말입니다. 멋지죠??? 엇?? 말이 어렵게 느껴지시나요? 그렇다면, 프로그래머들의 대화수단인 "예제"를 통해서 이해해보도록 하겠습니다.

먼저, 다음과 같이 DataList의 선언 태그부분에 DataKeyField 속성의 값을 추가하도록 하시어요.

<asp:DataList id="DataList1" runat= "server" GridLines="Both" Width= "800"
    RepeatColumns="2" RepeatDirection="Vertical" DataKeyField="title_id">

이렇게 바꾸는 것 만으로, 각 아이템의 title_id 컬럼 값은DataList가 자체적으로 저장하고 있게 됩니다. 그렇다면, 이제 EditItemTemplate 내의 [업데이트] 나 [삭제] 버튼은 CommandArgument 속성의 값을 가지고 있을 필요가 없어요. 그들의 도움이 없어도, 값을 이젠 더 쉽게 얻어올 수가 있게 되었으니까요. 그러니깐, 그 부분을 이제 다음과 같이 지워버리도록 하세요.

    <EditItemTemplate>
        <DIV>
        <IMG hspace="10" align="left" src='http://localhost/quickstart/ASPPlus/images/Title-
            <%# DataBinder.Eval(Container.DataItem, "title_id") %>.gif' >
        제목 :
        <asp:TextBox Runat="server" BorderStyle="Groove" width="250" ID="title"
            NAME="title" Text='<%# DataBinder.Eval(Container.DataItem, "title") %>'>
        </asp:TextBox>
        <BR>
        가격 :
        <asp:TextBox Runat="server" BorderStyle="Groove" ID="price" NAME=" price "
            Text='<%# DataBinder.Eval(Container.DataItem, "price") %>'></asp:TextBox>
        <BR>
        <asp:TextBox Runat="server" BorderStyle="Groove" TextMode="MultiLine" Rows="5"
            Width="300" Text='<%# DataBinder.Eval(Container.DataItem, "notes") %>'
            ID="notes" NAME=" notes "></asp:TextBox>
        <p>
            <asp:Button Runat="server" Text="업데이트" CommandName= "update">
               </asp:Button>
            <asp:Button Runat="server" Text="삭제" CommandName= "delete">
               </asp:Button>
            <asp:Button Runat="server" Text="취소" CommandName= "cancel">
               </asp:Button>
        </p>
        </DIV>
    </EditItemTemplate>

그리고, DataList1_UpdateCommand 이벤트 처리기의 코드도 다음과 같이 변경되어야 합니다. (이렇게 변경된 코드는 다운로드 받은 파일들 중에서 DataListEx1plus5.aspx라는 이름으로 제공되고 있습니다)

    private void DataList1_UpdateCommand(object source,
        System.Web.UI.WebControls.DataListCommandEventArgs e)
    {
        string title = ((TextBox)e.Item.FindControl("title")).Text;
        string price = ((TextBox)e.Item.FindControl("price")).Text;
        string notes = ((TextBox)e.Item.FindControl("notes")).Text;
        string title_id = DataList1.DataKeys[e.Item.ItemIndex].ToString();
        
        …

달라진 부분은 현재 업데이트되는 아이템의 title_id 값을 얻어오는 부분입니다. 기존에는 [업데이트] 버튼의 CommandArgument 값을 읽어왔지만, 지금의 경우에는 DataList의 DataKeys 컬렉션에서 현재 아이템의 순서 값을 사용하여 읽어오면 되는 것이죠. 현재 아이템의 출력 순서는 e.Item.ItemIndex를 통해서 알아낼 수 있으므로, 현재 [업데이트]하는 항목의 title_id 컬럼의 값은 DataList1.DataKeys[e.Item.ItemIndex]이 될 것입니다.

DataList1_DeleteteCommand 이벤트 처리기의 경우도 위와 동일하게 변경해주면 됩니다

지금 하는 이야기의 요점은 어떻게 해당 아이템의 키 값을 얻어오느냐 입니다. 해당 아이템의 키 값을 얻어오지 못하면, 그 아이템의 데이터를 변경할 방법이 없으니 말입니다. 그 키 값을 Button의 CommandArgument를 통해서 얻어올 수도 있고, 지금처럼 DataKeyField 속성을 사용하여 간단하게 얻어올 수도 있습니다. 모두 좋은 방법이며, 여러분이 보기에 나은 방법을 사용하면 되는 것이죠.

마음이 조급하신 분들은 제 이야기가 머리 속에 잘 받아들여지지 않을 수도 있을 것 같네요. 여러분이 ASP.NET으로 하고 싶은 것들은 어쩌면 게시판, 어쩌면 쇼핑몰, 어쩌면 커뮤니티, 혹은 메일 보내기 등등의 눈에 보이는 멋진 작업들일 테니 말입니다.

여러분들은 왜 이러한 컨트롤들을 이토록 구체적으로 알아야 하는지, 그것이 어떤 의미가 있는지 의심스러울 것이고, 여러분에게 중요한 것은 이런 컨트롤들의 사용법이 아니라 실제로 ASP.NET 이라는 기술을 어디에 어떻게 사용하는 지 일지도 모릅니다. 이러한 컨트롤의 사용법보다는 하나의 게시판을 만들어 내는 것이 여러분에게는 더욱 현실적인 목표일 수 있으니 말입니다. 그렇다는 사실을 저도 모르는 바는 아닙니다. 하지만, 이 강좌는 나중에 여러분이 이 강좌를 다시 볼 경우에도 도움이 되어줄 수 있기를 바라는 마음으로 작성하고 있습니다. 어쩌면, 과중한 업무로 인해 현재 여유가 없는 여러분들이 이 강좌에 관심을 갖지 않을 수 있다는 것도 알고 있습니다. 하지만, 조금 여력이 생겼거나, 일단 급한 불은 끈 상태라면 여러분은 기본적인 지식없이 만들어 낸 게시판이나 포럼, 커뮤니티를 안정적으로 그리고, 조금 더 효율적으로 만들고 싶어질 것이며, 그게 여러분에게 주어질 다음 번의 과제일 수도 있을 겁니다. 그러한 경우에 직면할 경우, 이 강좌는 여러분에게 큰 도움이 되어줄 것이라 믿고 있답니다.(제가 이 부분을 공부하면서 그랬으니까요 ㅠ_ㅠ) 

여러분에게 필요하지 않을 이야기를 강좌로 다룰리는 없지 않습니까???  아닌가?? 강좌를 때우기 위해서??? 설마.... 음....  -_-+

제 변론이 아니더라도.... 뭔가 그리드 관련 컨트롤들을 공부하는것이 중요하다는 느낌은 충분히 받았을 것이라 생각합니다. 사실 가끔씩 이러한 자극은 필요한 것 같아요. 우리는개발자, 기억력이 그리 좋지 못한 개발자들이니까요. 고로, 한번 불이 붙은 열정도 이내 식어버리기 일쑤이고, 딜레마에도쉽게 빠져들곤 하져. 그래서, 이러한 자극은 자주 필요한 것 같습니다. 그리고, 신념도 필요하구요. 지금 여러분이 하고 있는 공부는 무조건 여러분에게 힘이 되는 지식입니다.(그렇게 믿도록 노력하세요) 공부하는 동안에는 의심을 갖지 마세요. 그러한 의심은 여러분에게 전혀 득이 되지 않을 겁니다. 모든 의심은 공부를 마무리한 다음에 가져보아도 늦지 않다고 생각합니다.

아직 완전하지 못한 지식으로 의심하는 것은 여러분에게 불안만을 가중시킬 뿐이니까요. 주변에 여러분의 힘을 빠지게 하는 이야기를 하는 사람이 있다면, 물어보세요. 그들이 얼마나 그 기술에 대해서 알고 있는지.. 과연 제대로 기술을 알고 이야기하는지..  언제나 그렇듯이 빈 수레가 요란한 법입니다. 진정한 고수는 그 어떠한 기술도 폄하하지 않아요....

막판에 사담이 길었네요.. 사담 후세인도 아니면서 말입니다... 휘이이~~~잉~~~   ㅠ_ㅠ

죄송합니다. 썰렁한 분위기 만들다니..ㅠ_ㅠ
저는 냅다 다음 강좌로 건너가서기다리겠습니다.얼렁 오세요~~~~  ^^


authored by


 
 
.NET과 Java 동영상 기반의 교육사이트

로딩 중입니다...

서버 프레임워크 지원 : NeoDEEX
based on ASP.NET 3.5
Creative Commons License
{5}
{2} 읽음   :{3} ({4})