방법: 동적으로 ASP.NET 웹 서버 컨트롤 템플릿 만들기

Visual Studio 2010

업데이트: 2007년 11월

템플릿 컨트롤로 작업할 때는 런타임이 될 때까지 필요한 템플릿이 무엇인지 또는 템플릿에 어떤 텍스트나 컨트롤을 포함시켜야 하는지 알 수 없을 수도 있습니다. 이 경우에는 코드에서 동적으로 템플릿을 만들 수 있습니다.

0e39s2ck.alert_note(ko-kr,VS.100).gif참고:

템플릿을 사용자 정의 컨트롤로 만들어 페이지의 컨트롤에 동적으로 바인딩해도 됩니다. 자세한 내용은 방법: 템플릿 기반 ASP.NET 사용자 정의 컨트롤 만들기를 참조하십시오.

DataList, Repeater, GridView, FormView, DetailsView 등 템플릿을 사용하는 모든 컨트롤에 대해 코드를 사용하여 템플릿을 만들 수 있습니다. GridView 컨트롤의 경우, 다른 컨트롤과 같이 행 레이아웃 템플릿을 사용하지 않고 열을 정의하는 템플릿을 사용합니다.

0e39s2ck.alert_note(ko-kr,VS.100).gif참고:

다른 템플릿 컨트롤과 비교할 때 GridView 컨트롤에 대한 템플릿 열을 만드는 데는 조금 다른 점이 있습니다. 자세한 내용은 GridView 웹 서버 컨트롤에서 사용자 지정 열 만들기를 참조하십시오.

동적 템플릿을 만들려면 필요할 때 인스턴스화할 수 있는 템플릿 클래스를 만듭니다.

템플릿 클래스를 만들려면

  1. System.Web.UI.ITemplate 인터페이스를 구현하는 새 클래스를 만듭니다.

  2. 필요한 경우, 클래스에서 만들 템플릿의 형식(ItemTemplate, AlternatingItemTemplate 등)을 결정할 때 사용되는 값을 클래스의 생성자에 전달합니다.

    0e39s2ck.alert_note(ko-kr,VS.100).gif참고:

    생성자에 템플릿 형식을 전달할 때 형식 안전성을 유지하려면 ListItemType 형식을 사용하여 생성자에 매개 변수를 추가합니다. ListItemType 열거형에서는 Repeater, DataList 및 기타 목록 컨트롤에 대해 사용 가능한 템플릿 형식을 정의합니다.

  3. 클래스에서 InstantiateIn 메서드를 구현합니다. 이 메서드는 ITemplate 인터페이스의 멤버입니다.

    이 메서드를 통해 텍스트 및 컨트롤의 인스턴스를 지정된 컨테이너에 삽입할 수 있습니다.

  4. InstantiateIn 메서드에서 템플릿 항목의 컨트롤을 만들고 속성을 설정한 다음 부모의 Controls 컬렉션에 추가합니다.

    InstantiateIn 메서드에 전달된 참조를 통해 부모 컨트롤에 액세스할 수 있습니다.

    0e39s2ck.alert_note(ko-kr,VS.100).gif참고:

    Controls 컬렉션에 정적 텍스트를 직접 추가할 수는 없지만, Literal 컨트롤 또는 LiteralControl 컨트롤 등의 컨트롤을 만들고 Text 속성을 설정한 다음 이 컨트롤을 부모 컬렉션에 추가할 수는 있습니다.

  5. 데이터 바인딩이 필요한 컨트롤에 대해서는 컨트롤의 DataBinding 이벤트를 처리할 메서드를 만들고 바인딩합니다. 이 이벤트는 템플릿 항목과 해당 템플릿과 관련된 컨트롤이 모두 만들어진 후에 발생하며 데이터를 페치하여 컨트롤에서 사용할 수 있도록 합니다.

    0e39s2ck.alert_note(ko-kr,VS.100).gif참고:

    템플릿에 컨트롤을 만드는 경우에는 디자인 타임에 템플릿을 정의할 때처럼 데이터 바인딩 식을 문자열로 포함할 수 없습니다. 데이터 바인딩 식은 템플릿이 만들어지기 전에 코드로 변환되기 때문입니다.

    DataBinding 이벤트에 대한 처리기에서 컨트롤의 내용을 조작할 수 있습니다. 필수적인 것은 아니지만, 보통 임의의 위치에서 데이터를 페치하여 컨트롤의 Text 속성이나 기타 속성에 할당합니다.

    0e39s2ck.alert_note(ko-kr,VS.100).gif참고:

    ASP.NET 웹 페이지의 데이터 바인딩에 대한 자세한 내용은 ASP.NET을 사용하여 데이터 액세스를 참조하십시오.

    동적 템플릿에 데이터 바인딩을 추가하려면 다음 작업을 수행해야 합니다.

    • 템플릿에서 만든 컨트롤에 데이터 바인딩 이벤트 처리기를 추가합니다.

    • 바인딩 대상이 되는 처리기를 만듭니다. 바인딩할 데이터를 이 처리기에서 가져온 다음, 바인딩되는 컨트롤의 해당 속성에 할당합니다.

      0e39s2ck.alert_note(ko-kr,VS.100).gif참고:

      템플릿에 여러 형식의 컨트롤이 있는 경우 각 컨트롤 형식마다 서로 다른 데이터 바인딩 이벤트 처리기를 만들어야 합니다.

    다음 코드 예제에서는 ITemplate 인터페이스를 구현하는 MyTemplate이라는 템플릿 클래스를 보여 줍니다. MyTemplate 클래스에서는 만들려는 템플릿의 형식을 나타내기 위해 ListItemType 열거형 값을 받는 생성자를 정의합니다. 템플릿 형식에 따라 코드에서 서로 다른 형식의 컨트롤이 작성됩니다. 이 컨트롤은 PlaceHolder 컨트롤에 추가된 다음 부모 컨트롤의 Controls 컬렉션에 다시 추가됩니다. ItemAlternatingItemListItemType에 대해 Item_DataBinding이라는 이벤트 처리기가 만들어집니다.

    교대로 반복되는 항목 템플릿에 대해 서로 다른 배경색을 가진 HTML 표가 렌더링된 웹 페이지의 결과로 만들어집니다.

    public class MyTemplate : System.Web.UI.ITemplate
    {
        System.Web.UI.WebControls.ListItemType templateType;
        public MyTemplate(System.Web.UI.WebControls.ListItemType type)
        {
            templateType = type;
        }
    
        public void InstantiateIn(System.Web.UI.Control container)
        {
            PlaceHolder ph = new PlaceHolder();
            Label item1 = new Label();
            Label item2 = new Label();
            item1.ID = "item1";
            item2.ID = "item2";
    
            switch (templateType)
            {
                case ListItemType.Header:
                    ph.Controls.Add(new LiteralControl("<table border=\"1\">" +
                        "<tr><td><b>Category ID</b></td>" + 
                        "<td><b>Category Name</b></td></tr>"));
                    break;
                case ListItemType.Item:
                    ph.Controls.Add(new LiteralControl("<tr><td>"));
                    ph.Controls.Add(item1);
                    ph.Controls.Add(new LiteralControl("</td><td>"));
                    ph.Controls.Add(item2);
                    ph.Controls.Add(new LiteralControl("</td></tr>"));
                    ph.DataBinding += new EventHandler(Item_DataBinding);
                    break;                    
                case ListItemType.AlternatingItem:
                    ph.Controls.Add(new LiteralControl("<tr bgcolor=\"lightblue\"><td>"));
                    ph.Controls.Add(item1);
                    ph.Controls.Add(new LiteralControl("</td><td>"));
                    ph.Controls.Add(item2);
                    ph.Controls.Add(new LiteralControl("</td></tr>"));
                    ph.DataBinding += new EventHandler(Item_DataBinding);
                    break;
                case ListItemType.Footer:
                    ph.Controls.Add(new LiteralControl("</table>"));
                    break;
            }
            container.Controls.Add(ph);
        }
    }
    
    
    

DataBinding 이벤트에 대한 처리기를 만들려면

  1. 템플릿 클래스의 일부이며 페이지의 정적(Visual Basic의 경우 Shared) 메서드 또는 클래스의 다른 메서드(InstantiateIn 등)와 동일한 수준의 역할을 수행하는 메서드를 만듭니다. 처리기의 이름은 이벤트 처리기를 바인딩할 때 사용했던 이름과 같아야 합니다.

  2. 다음과 같은 작업을 수행하여 데이터가 포함된 DataItem 개체에 대한 참조를 가져옵니다.

    1. 템플릿 항목에 대한 참조를 가져옵니다. 이는 컨트롤의 NamingContainer 속성에서 얻을 수 있습니다.

    2. 이 참조를 사용하여 이름 지정 컨테이너(템플릿 항목)의 DataItem 속성을 가져옵니다.

    3. DataItem 개체에서 개별 데이터 요소를 추출하고, 이 요소를 사용하여 바인딩하는 컨트롤의 속성을 설정합니다.

    다음 코드 예제에서는 동적 템플릿 안에서 데이터 바인딩을 수행하는 방법 중 하나를 보여 줍니다. 여기에서는 이전 절차를 통해 만든 LiteralLabel 컨트롤과 PlaceHolder 컨트롤에 대한 전체 데이터 바인딩 이벤트 처리기를 보여 줍니다. 이 이벤트 처리기는 페이지의 정적 메서드로 구현됩니다.

    static void Item_DataBinding(object sender, System.EventArgs e)
    {
        PlaceHolder ph = (PlaceHolder)sender;
        RepeaterItem ri = (RepeaterItem)ph.NamingContainer;
        Int32 item1Value = (Int32)DataBinder.Eval(ri.DataItem, "CategoryID");
        String item2Value = (String)DataBinder.Eval(ri.DataItem, "CategoryName");
        ((Label)ph.FindControl("item1")).Text = item1Value.ToString();
        ((Label)ph.FindControl("item2")).Text = item2Value;
    }
    
    
    

사용할 수 있는 동적 템플릿이 있으면 이 템플릿을 코드에서 인스턴스화할 수 있습니다.

동적 템플릿을 사용하려면

  1. 동적 템플릿의 인스턴스를 만들고 해당되면 여기에 항목 형식의 값을 지정합니다.

  2. ItemTemplate, AlternatingItemTemplate 또는 HeaderTemplate 속성과 같은 템플릿 컨트롤의 템플릿 속성 중 하나에 인스턴스를 할당합니다.

    다음 코드 예제에는 동적 템플릿을 Repeater 컨트롤과 함께 사용하는 방법을 보여 줍니다. 이 예제에서는 페이지가 로드되는 동안 컨트롤이 데이터 소스에 바인딩되기 전에 템플릿이 인스턴스화됩니다.

    다음 예제에서는 사용자가 Microsoft SQL Server 7.0 이상 버전의 Northwind 샘플 데이터베이스에 연결할 수 있는 것으로 가정합니다. 이 예제는 Categories 테이블의 레코드 목록을 반환합니다.

    protected void Page_Load(object sender, EventArgs e)
    {
        System.Data.SqlClient.SqlConnection conn =
            new System.Data.SqlClient.SqlConnection(
            ConfigurationManager.ConnectionStrings["Northwind"].ConnectionString);
    
        System.Data.SqlClient.SqlDataAdapter sqlDataAdapter1;
        System.Data.DataSet dsCategories1;
    
        sqlDataAdapter1 = new System.Data.SqlClient.SqlDataAdapter(
            "SELECT [CategoryID], [CategoryName] FROM [Categories]", conn);
        dsCategories1 = new System.Data.DataSet();
    
        Repeater1.HeaderTemplate = new MyTemplate(ListItemType.Header);
        Repeater1.ItemTemplate = new MyTemplate(ListItemType.Item);
        Repeater1.AlternatingItemTemplate =
           new MyTemplate(ListItemType.AlternatingItem);
        Repeater1.FooterTemplate = new MyTemplate(ListItemType.Footer);
        sqlDataAdapter1.Fill(dsCategories1, "Categories");
        Repeater1.DataSource = dsCategories1.Tables["Categories"];
        Repeater1.DataBind();
    }
    
    
    

앞서 열거한 모든 구성 요소를 만든 후에 Repeater1이라는 Repeater 컨트롤을 페이지 태그에 추가하고 페이지를 실행합니다. 단일 파일 코드 모델을 사용하는 웹 페이지의 전체 코드와 태그는 다음과 같습니다.

<%@ Page Language="C#" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">

    public class MyTemplate : System.Web.UI.ITemplate
    {
        System.Web.UI.WebControls.ListItemType templateType;
        public MyTemplate(System.Web.UI.WebControls.ListItemType type)
        {
            templateType = type;
        }

        public void InstantiateIn(System.Web.UI.Control container)
        {
            PlaceHolder ph = new PlaceHolder();
            Label item1 = new Label();
            Label item2 = new Label();
            item1.ID = "item1";
            item2.ID = "item2";

            switch (templateType)
            {
                case ListItemType.Header:
                    ph.Controls.Add(new LiteralControl("<table border=\"1\">" +
                        "<tr><td><b>Category ID</b></td>" + 
                        "<td><b>Category Name</b></td></tr>"));
                    break;
                case ListItemType.Item:
                    ph.Controls.Add(new LiteralControl("<tr><td>"));
                    ph.Controls.Add(item1);
                    ph.Controls.Add(new LiteralControl("</td><td>"));
                    ph.Controls.Add(item2);
                    ph.Controls.Add(new LiteralControl("</td></tr>"));
                    ph.DataBinding += new EventHandler(Item_DataBinding);
                    break;                    
                case ListItemType.AlternatingItem:
                    ph.Controls.Add(new LiteralControl("<tr bgcolor=\"lightblue\"><td>"));
                    ph.Controls.Add(item1);
                    ph.Controls.Add(new LiteralControl("</td><td>"));
                    ph.Controls.Add(item2);
                    ph.Controls.Add(new LiteralControl("</td></tr>"));
                    ph.DataBinding += new EventHandler(Item_DataBinding);
                    break;
                case ListItemType.Footer:
                    ph.Controls.Add(new LiteralControl("</table>"));
                    break;
            }
            container.Controls.Add(ph);
        }
    }

    static void Item_DataBinding(object sender, System.EventArgs e)
    {
        PlaceHolder ph = (PlaceHolder)sender;
        RepeaterItem ri = (RepeaterItem)ph.NamingContainer;
        Int32 item1Value = (Int32)DataBinder.Eval(ri.DataItem, "CategoryID");
        String item2Value = (String)DataBinder.Eval(ri.DataItem, "CategoryName");
        ((Label)ph.FindControl("item1")).Text = item1Value.ToString();
        ((Label)ph.FindControl("item2")).Text = item2Value;
    }

    protected void Page_Load(object sender, EventArgs e)
    {
        System.Data.SqlClient.SqlConnection conn =
            new System.Data.SqlClient.SqlConnection(
            ConfigurationManager.ConnectionStrings["Northwind"].ConnectionString);

        System.Data.SqlClient.SqlDataAdapter sqlDataAdapter1;
        System.Data.DataSet dsCategories1;

        sqlDataAdapter1 = new System.Data.SqlClient.SqlDataAdapter(
            "SELECT [CategoryID], [CategoryName] FROM [Categories]", conn);
        dsCategories1 = new System.Data.DataSet();

        Repeater1.HeaderTemplate = new MyTemplate(ListItemType.Header);
        Repeater1.ItemTemplate = new MyTemplate(ListItemType.Item);
        Repeater1.AlternatingItemTemplate =
           new MyTemplate(ListItemType.AlternatingItem);
        Repeater1.FooterTemplate = new MyTemplate(ListItemType.Footer);
        sqlDataAdapter1.Fill(dsCategories1, "Categories");
        Repeater1.DataSource = dsCategories1.Tables["Categories"];
        Repeater1.DataBind();
    }


</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Dynamically Creating Templates</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
      <asp:Repeater id="Repeater1" runat="server"></asp:Repeater>
    </div>
    </form>
</body>
</html>


표시: