login register Sysop! about ME  
qrcode
    최초 작성일 :    2002년 10월 02일
  최종 수정일 :    2002년 10월 02일
  작성자 :    cassatt
  편집자 :    Taeyo (김 태영)
  읽음수 :    65,535

강좌 목록으로 돌아가기

필자의 잡담~

페이지 추가/컨트롤 설정

이번 강좌에선 지난 강좌에서 작성했던 글 쓰기 페이지에서 등록한 글을 목록으로 보여줄, 글 목록 페이지를 만들어보겠습니다. 페이지 이름은 List.aspx 입니다.

솔루션 탐색기, 해당 프로젝트가 선택된 상태에서 파일 메뉴에서 '새 항목 추가'를 선택합니다. 혹은 해당 프로젝트를 오른쪽 클릭하신 후 추가->새항목 추가 를 선택하셔도 됩니다. 그럼 '새 항목 추가' 창이 뜨는데요, 거기서 템플릿에서 Web Form 을 선택하고, 파일이름을 'List.aspx'로 입력한 후 '열기'를 클릭합니다. 다음 그림과 같습니다.

그럼 프로젝트에 List.aspx가 추가됩니다.

추가된 List.aspx를 오른쪽 클릭해서, '시작 페이지로 설정'을 선택해서 시작페이지로 합니다. ( 오른쪽 그림 참조 ) 그렇게 하지 않으면 시작버튼 눌렀을때, 현재의 시작 페이지인 Write.aspx 부터 시작하기 때문에 좀 귀찮습니다.

그리고 글쓰기 페이지(Write.aspx) 때와 마찬가지로 페이지 바탕 아무곳이나 오른쪽 클릭해서 속성을 선택,  페이지 레이아웃을 FlowLayout으로 바꿉니다. 이것은 다른 모든 페이지에도 마찬가지입니다.

글쓰기 페이지 경우와 마찬가지로, 우선은 필요한 컨트롤들을 끌어다 놓고 시작해 보겠습니다. 글 목록 페이지이니,  DB 레코드들을 목록으로 표현해줄 컨트롤이 필요하겠는데요, 그를 위해선 DataGrid, DataList, Repeater 등을 쓸수 있습니다. 강좌에서는 DataGrid 가 가장 많은 기능을 제공하고, 비쥬얼하게 작업할수 있으니 DataGrid를 써보겠습니다.
그 외에도 '총 XX개의 글, XX/XX페이지' 같은 페이지 번호 표시할 부분도 필요하고, 페이지 이동하는 부분도 필요하고, 글쓰기 버튼도 필요하겠습니다. 도구 상자를 열어, HTML 란의 Table 을 이용해 레이아웃 잡으면서, Web Forms란에서 Label, HyperLink 3개, DataGrid 를 끌어다놓아 다음 그림처럼 만듭니다.

가운데의 테이블 형태로 있는 것이 DataGrid 끌어다 놓은 모습입니다.  컨트롤들의 ID, 속성을 다음처럼 바꿉니다.
 

컨트롤 (ID) 그외 속성/설명
Label lblRecordCount Text : (비워둡니다)
첫번째 HyperLink lnkPrevBtn Text : [이전페이지]
두번째 HyperLink lnkNextBtn Text : [다음페이지]
세번째 HyperLink lnkWriteBtn Text : [글쓰기]
NavigateUrl : Write.aspx
DataGrid dgrdMainList (일단 아이디만 바꿉니다)

첫번째 Label 은 '총 xx개의 글, xx/xx 페이지' 라고, 총 글의 수와 현재 페이지 번호를 표시할 위치입니다. 첫번째, 두번째 HyperLink 는 이전페이지/다음페이지로 이동하기 위한 것이고요, 마지막 HyperLink 는 글쓰기 페이지(Write.aspx)로 이동하기 위한 것입니다.
일단은 이전/다음 으로 이동하도록만 하지만, 다음에 이전/다음 대신 페이지번호로 이동 하는 링크( [<<][<] [1][2][3][4] [>][>>]  이런 식으로 페이지 번호로 이동하는 링크 )로 하는 방법도 다루겠습니다. 그것도 같이 다루면 괜히 복잡해질것 같아 일단 간단히만 합니다. 이번 강좌에서 중요한것은 DataGrid 이지, 페이지링크는 아니니까요.
DataGrid는 설정할 것이 많은데, 잠시후 설명하겠습니다.


자료 가져오기

목록이 표현되려면 자료를 테이블에서 가져와야 겠죠? 그를 위해선 첫번째로 연결 객체인 SqlConnection 필요하겠습니다. 글쓰기 때와 마찬가지로, 도구 상자의 '데이터' 란에서 SqlConnection을 페이지에 끌어다 놓습니다. 그리고 속성란에서, 우선은 (Name)을 dbConnection으로 바꾸고요, Dynamic Properties 란 확장, ConnectionString 란의 [...] 버튼을 클릭, '동적 속성' 창에서 '구성 파일의 키에 속성 매핑' 체크박스를 선택하시면 밑의 텍스트박스가 활성화되고 'dbConnection.ConnectionString' 이라 입력되어 있을겁니다.

 

Write.aspx에서도 보았었습니다.
'확인'을 클릭하고, 밑의 '데이터'란의 ConnectionString 항목 보시면, 입력하지 않았는데도 연결문자열이 들어가 있을 겁니다. Write.aspx 작업할때 Web.config 파일에 저장했던, 그 키에 해당하는 값을 가져온 것이죠. 이것이 연결 문자열을 키와 매핑시키는 이유입니다. 한번 입력해 두면 다음번엔 입력할 필요가 없고요, 한 곳에 저장되니 관리하기도 쉽습니다.

그리고 자료를 가져올 객체가 필요하겠는데요, 자료를 가져오기 위해 SqlCommand객체를 사용해서 SqlDataReader로 읽을 수도 있습니다만, 이번엔 SqlDataAdapter를 써보겠습니다. 도구상자 '데이터' 란에 SqlDataAdapter 를 끌어 페이지 아무곳나 놓습니다. 그럼 편집 페이지 하단에 sqlDataAdapter1 이란 객체가 생기면서 '데이터 어댑터 구성 마법사'가 시작되는데요, 직접 속성을 입력할 것이니 '취소'를 눌러 취소합니다.
그리고 속성을 다음처럼 편집합니다.

  • (Name) dbDataAdapterGetSequences
  • DeleteCommand : (없음) ( 작은 화살표 눌러 '(없음)' 선택하시면 됩니다 )
  • InsertCommand : (없음)
  • UpdateCommand : (없음)
  • SelectCommand : [+] 눌러 확장하신 후, 다음을 입력합니다.
    • Connection : dbConnection
    • CommandText : select seq from cstVSBoard order by seq desc
오른쪽 그림이 데이터셋 속성 편집한 모습입니다.

방금 작성한 데이터셋은 게시판 테이블에서 seq 필드만 전부 가져오기 위한 것입니다.
seq 는 자동 증가형(identity)으로 된 일련번호로, 글을 구분하기 위한 것이기도 하고, 역순으로 하면 최근 글부터 시작하는 목록에서의 글의 순서이기도 합니다. 이 게시판에선 seq 필드만 모두 가져와서, 그중 해당 페이지의 글을 알아내서 그 글의 레코드를 다시 가져오는 방식으로 페이징 할 생각입니다. 로직은 잠시후 설명드리겠고요, 위 처럼 설정하신 후엔 속성란 아래부분에서 '데이터 미리보기'를 클릭해 보세요. 오른쪽 그림 하단에도 링크가 보입니다.

 

'데이터 집합 채우기' 버튼을 눌러 결과 란에 자료가 나오면 성공입니다. 글을 하나만 입력했다면 위 그림처럼 1 이란 레코드 하나만 나올겁니다.

이제 위 테이블로 해당 페이지의 seq 범위를 알아낸 후, 해당 페이지 레코드를 실제로 가져올 명령 객체를 설정해보겠습니다. 도구상자 '데이터'란에서 SqlCommand를 끌어 놓고, 다음처럼 속성을 설정합니다.

  • (name) : dbCommandGetArticles
  • Connection : dbConnection
  • CommandText :
    select seq,writer,email,title,readed, writeDate from cstVSBoard
    where seq between @seqStart and @seqEnd
    order by seq desc
  • Paramters :
    ParameterName SqlDbType
    @seqStart Int
    @seqEnd Int


페이징 소스 작성 및 테스트

이제 지금까지 설정한 DB관련 객체를 이용해서, 원하는 페이지의 글을 DataGrid에 바인딩할 로직을 작성할 차례입니다.

게시판 목록에선, 수많은 글을 전부 한페이지에 보여줄순 없기때문에, 보통 '페이징'이라 부르는 UI를 써서 여러 페이지에 나눠서 보여주게 됩니다. 페이징은, DataGrid에서 지원하기도 하는데요, 여기서는 페이징하는 로직을 직접 작성하겠습니다.
DataGrid에서 지원하는 페이징은 모든 레코드의 필요한 필드를 가져와서, 그중 해당 페이지의 레코드만 보여주는 것입니다. 그래서 글이 수만개 되면 좀 느려집니다. 사실 어느 페이지를 보여주기 위해선 해당 페이지의 자료만 있으면 되는 것인데, 모든 레코드를 가져온다는 것 자체가 비효율적인 것이겠죠.
그런데 원하는 페이지의 레코드만 가져오는 것이 그리 쉽지만은 않은것 같습니다. 중간만 끊어 가져오는 것도 그렇고, 그럼에도 총 레코드 갯수는 알아야 몇 페이지까지 존재하는지 알수 있어야 합니다.
여러 로직이 있겠습니다만, 여기서는 seq 필드만 모두 가져와서, 그것으로 글의 갯수와, 현 페이지의 seq 범위를 알아내고, 그 범위에 따라 다시 select 문을 호출하도록 해서 페이징하겠습니다. 레코드 전체를 가져온다 해도, int형의 하나의 필드만 가져오기 때문에 속도가 빠릅니다. 비교적 간단한 로직임에도 DataGrid 자체 페이징 보다 열배이상 빨라질수 있습니다. ( 이보다 더빠른 로직도 있는데, 소스가 좀 복잡하게 됩니다. 다른 강좌에서 다루겠습니다 )

솔루션 탐색기에서 List.aspx를 오른쪽 클릭, '코드보기'를 선택해서 코드로 전환합니다. 아마도 Page_Load 이벤트 부분에 커서가 가있을텐데요, 그 함수를 다음처럼 작성합니다.

private void Page_Load(object sender, System.EventArgs e)
{
  int recordCount,pageCount,page;
  const int pageSize = 15; // 한 페이지의 글의 갯수

  // cstVSBoard에서 seq 필드 전체를 가져와서 
  // DataTable인 dtSeq에 담습니다.
  System.Data.DataTable dtSeq=new DataTable();
        
  dbConnection.Open();	
  dbDataAdapterGetSequences.Fill(dtSeq);

  // dtSeq 의 행의 수(Rows.count)로
  // 게시판 글의 총 갯수를 알아냅니다.
  recordCount=dtSeq.Rows.Count;
  if(recordCount==0) 
  {
    pageCount=0;
    page=1;
  }
  else 
  {
    // 총 페이지 수를 알아냅니다.
    pageCount=(int)(recordCount-1)/pageSize+1;

    // 현 페이지 번호를 알아냅니다. 
    try 
    {
      page=int.Parse(Request.QueryString["p"]);
    }
    catch(Exception)
    {
      page = 1;
    }
    if(page<1) page=1;
    if(page>pageCount) page=pageCount;

    // 현페이지에 해당하는 seq의 범위를 알아냅니다.

    int recordPosStart = (page-1)*pageSize;
    int recordPosEnd = (page)*pageSize-1;
    if(recordPosEnd>=recordCount ) recordPosEnd=recordCount-1;

    int seqEnd=(int)dtSeq.Rows[recordPosStart][0];
    int seqStart=(int)dtSeq.Rows[recordPosEnd][0];

    // 해당 범위의 레코드를 가져옵니다.

    dbCommandGetArticles.Parameters["@seqStart"].Value=seqStart;
    dbCommandGetArticles.Parameters["@seqEnd"].Value=seqEnd;

    // 레코드들을 DataGrid에 바인딩합니다.

    dgrdMainList.DataSource = 
      dbCommandGetArticles.ExecuteReader(CommandBehavior.CloseConnection);
    dgrdMainList.DataBind();
  }
  dbConnection.Close();

  lblRecordCount.Text = 
    String.Format("총 <b>{0}</b> 개의 글, <b>{1}</b>/{2} 페이지"
    , recordCount, page, pageCount);

  // 이전 페이지, 다음페이지 링크를 설정합니다.
  lnkPrevBtn.NavigateUrl="List.aspx?p="+(page-1);
  lnkNextBtn.NavigateUrl="List.aspx?p="+(page+1);

  if(page<=1)
    lnkPrevBtn.Visible=false;
  if(page>=pageCount)
    lnkNextBtn.Visible=false;
}
소스는 리마크로 간단히 설명해두었습니다. 여러분도 나름대로 페이징 로직을 구현해 보시기 바랍니다.

이제 완전히 완성된 것은 아닙니다만, 테스트해볼 수는 있습니다. DataGrid에는 자동으로 컬럼을 만드는 기능이 있어서( AutoGenerateColumns=true ), 아무 설정 안해도 ( 예쁘게는 안나와도 ) 자료의 내용은 출력됩니다. 시작 버튼을 눌러 테스트 해보세요.

글 여러개를 추가해서 페이징도 테스트해보세요. 위 그림은 레코드 40개 넣어서 테스트한 것입니다. 아래에 [이전페이지], [다음페이지] 링크으로 이전/다음 페이지로 이동할수 있고, [글쓰기] 버튼으로 글을 추가할 수 있습니다. 위에는 40개의 글이 있고, 현재 3개 페이지 중 1페이지라고 표시되어있습니다.


DataGrid 편집

골격은 거의 완성되었고, 이제 DataGrid를 편집해서 원하는 필드만, 좀더 예쁘게 나오도록 하는 것이 남았습니다. DataGrid를 편집해 보겠습니다.

약간 디자인 해놓고 시작하죠. 데이터그리드를 오른쪽 버튼 클릭, 메뉴에서 '자동서식'을 선택합니다. 그럼 다양한 서식을 선택할수 있는데요, 제경우엔 그중 '기본 1'을 선택하겠습니다. 원하시는 것을 선택해보세요.

그럼 그리드에 색이 들어가면서 약간은 디자인된 상태가 됩니다. VS.NET에서 자동으로 서식을 정해주는 것인데요, 나중에 맘에 안들면 '자동 서식 제거'를 선택해서 제거할수도 있고, HTML 소스로 직접 변경하셔도 됩니다.

그리고 DataGrid 속성란에서 다음 속성을 변경합니다.

  • AutoGenerateColumns : false
  • EnableViewState : false
  • Width : 600

지금까지는 그리드가 자동으로 컬럼을 만들도록 했지만, 컬럼을 지정해서 원하는 모양으로 나오도록 하기 위해 AutoGenerateColumns를 false로 주었습니다. Width는 원하는 크기대로 주시면 됩니다.
그리고 이 페이지에선 PostBack 버튼을 사용하지 않기 때문에 ViewState를 유지할 필요가 없어 EnableViewState를 false로 합니다. true/false 로 바꿔가며 실행해서 소스보기 해보시면 어떤 차이가 있는지 확인하실수 있습니다. __VIEWSTATE 란 히든 필드 크기가 팍 줍니다.

AutoGenerateColumns를 false로 했으니, 컬럼을 하나하나 정해주어야 겠죠? 그리드를 오른쪽 클릭해서 메뉴에서 '속성 작성기'를 선택합니다. 그럼 'dgrdMainList 속성' 이란 창이 뜨는데, 거기서 왼쪽에서 '열'을 선택합니다.

그리고 그림처럼 '바인딩된 열'을 선택, [>] 버튼으로 '선택한 열'란에 추가하고, 머리글텍스트를 '번호', 데이터 필드를 'seq'를 입력합니다. 같은 식으로 제목, 이름, 날짜, 조회 등을 추가합니다. 다음과 같습니다.
 

열 형식 머리글 텍스트 데이터 필드 데이터 형식 지정 식
바인딩된 열 번호 seq (입력안함)
템플릿 열 제목 (입력안함) (입력안함)
템플릿 열 이름 (입력안함) (입력안함)
바인딩된 열 날짜 writeDate {0:yyyy-MM-dd}
바인딩된 열 조회 readed (입력안함)

번호, 날짜, 조회 처럼 데이터 값 그대로 출력만 하면 되면 바인딩된 열을 쓸수 있습니다. 그리고 하이퍼링크라면 하이퍼링크 열을 쓸수 있어서, 제목이나 이름을 하이퍼링크 열로 할수도 있는데요, 약간이라도 로직이 들어가야 한다면 바인딩된 열이나 하이퍼링크 열을 쓸수가 없어 '템플릿 열'을 써야 합니다. 템플릿 열의 경우 표시할 내용을 직접 편집해야 합니다. 잠시후 하게됩니다.

그리고 왼쪽의 '서식'란을 눌러 서식을 편집합니다. 디자인과 관련된 부분이겠는데, 사용법도 익힐겸 약간만 편집해보겠습니다.

위 그림 처럼, 열에서 원하는 항목을 선택해서 편집하시면 됩니다. 번호란 확장해 보니 머리글, 바닥글, 항목 세가지가 있는데요, 이중 머리글, 항목 둘을 같이 편집합니다. 다음처럼 항목을 편집합니다.

  • 번호 : (항목/머리글 모두) 가운데 맞춤, '셀에서 텍스트 줄바꿈' 체크 해제
  • 제목 : ( 기본값대로 놔둡니다 )
  • 이름 : (항목/머리글 모두) 가운데 맞춤, '셀에서 텍스트 줄바꿈' 체크 해제
  • 날짜 : (항목/머리글 모두) 가운데 맞춤, '셀에서 텍스트 줄바꿈' 체크 해제
  • 조회 : (항목/머리글 모두) 가운데 맞춤, '셀에서 텍스트 줄바꿈' 체크 해제

제목을 제외한 다른 모든 항목들을 가운데 정렬하고, 텍스트 줄바꿈( <td> 의 nowrap 에 해당됩니다 )을 하지 않도록 했습니다. 이렇게 하면 제목을 길게 입력했을 경우에도 대충 정렬됩니다.
제목이 줄바꿈되는 거야 어쩔수 없지만, 날짜가 줄바꿈 되거나 하면 테이블이 엉망이 되거든요. 이 상태에서 제목란의 너비를 10000px 로 아주 크게 주면, 제목란이 최대화, 다른 란은 최소화 되면서 어지간한 경우에도 대충 정렬되어 나오는(?) 레이아웃이 됩니다. 일부 게시판이 그러한 식으로 정렬하더군요. 여러분도 여러 방식으로 해보세요.

그리고, 아까 열 중에 '제목'과 '이름' 란은 템플릿 열로 하고 내용은 입력하지 않았었습니다. 제목이나 이름은 약간의 로직이 들어가야 하기 때문에 템플릿열로 했는데요, 그 내용을 입력할 차례입니다.
템플릿 열은 DataGrid를 오른쪽 클릭, '템플릿 편집' 선택해서 편집할수 있습니다만, 간단한 것이라 그냥 HTML 모드로 전환해서 편집하겠습니다. HTML 모드로 전환한 후 소스에서 TemplateColumn 으로 된 제목, 이름 란을 찾아 다음처럼 입력합니다. 파란색 부분이 입력할 부분입니다.

<asp:datagrid id="dgrdMainList" runat="server" ...(생략)... >

...(생략)...

    <asp:TemplateColumn HeaderText="제목">
      <ItemTemplate>
        <%# BindTitle(Container.DataItem) %>
      </ItemTemplate>
    </asp:TemplateColumn>
    <asp:TemplateColumn HeaderText="이름">
      <HeaderStyle Wrap="False"></HeaderStyle>
      <ItemStyle Wrap="False"></ItemStyle>
      <ItemTemplate>
        <%# BindWriter(Container.DataItem) %>
      </ItemTemplate>
    </asp:TemplateColumn>

...(생략)...

</asp:datagrid>
약간은 로직이 필요해서, BindTitle, BindWriter 라는 메서드를 정의해서 그 메서드를 호출하도록 하려는 것입니다. 코드 보기로 전환( 메뉴에서 보기-> 코드, 혹은 F7 누름 ) 해서 방금 넣은 BindTitle, BindWriter 라는 메서드를 클래스에 추가합니다. 다음 소스 파란색 부분입니다.

public class List : System.Web.UI.Page
{
...(생략)...

  protected string BindWriter( Object item)
  {
    string writer = (string)DataBinder.Eval(item, "writer");
    string email = (string)DataBinder.Eval(item, "email");
    writer=Server.HtmlEncode(writer);
    email=Server.HtmlEncode(email);
    if(email!="")
      writer=String.Format("<a href=\"mailto:{0}\">{1}</a>", email,writer);
    return writer;
  }

  protected string BindTitle( Object item)
  {
    int seq = (int) DataBinder.Eval(item, "seq");
    string title = Server.HtmlEncode((string)DataBinder.Eval(item, "title"));
    return String.Format("<a href=\"View.aspx?n={0}\">{1}</a>", seq,title);
  }

...(생략)...
}
이름의 경우, 메일 주소를 입력했으면 링크를 걸고, 입력 안했으면 링크없이 출력하게 됩니다. 제목란은 아직은 안만들었지만 글의 내용을 보여줄 View.aspx 라는 페이지를 seq 값과 함께 호출하도록 제목에 링크를 걸었습니다.
제목란의 경우 링크만 걸면 되기에 하이퍼링크 열을 써도 됩니다만, 사용자가 HTML 태그를 입력하면 태그가 실행되어 버리기 때문에 그것을 방지하기 위해 Server.HtmlEncode 메서드를 이용해서 태그가 실행 안되도록 할 필요가 있습니다. 간단한 로직이라 해도, 데이터 그리드의 하이퍼링크 열 사용하기는 어려워 템플릿 열로 했습니다.
이처럼 해당 열을 표현할때 로직이 필요하면, 템플릿 열로 정의한 후 필요하다면 메서드로 정의해서 <ItemTemplate></ItemTemplate> 란에 넣으면 됩니다.
완료

이제 목록 페이지는 어느 정도 완성된 셈입니다. 시작버튼을 눌러 실행해보세요. 제가 실행한 화면은 다음과 같습니다.

이전페이지/다음페이지 링크로 페이지를 앞 뒤로 이동할수 있고, 글쓰기 버튼으로 글을 입력할 수 있습니다. 메일주소를 입력했다면 이름에 링크가 걸려 있습니다.

제목을 클릭하면, 아직은 만들지 않았지만 글의 내용을 확인할 글보기 페이지, View.aspx 로 이동하게 됩니다. 다음 강좌에선 글 보기 페이지를 만들어보겠습니다.


authored by


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

로딩 중입니다...

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