서버 컨트롤 속성 예제

Visual Studio 2010

업데이트: 2007년 11월

이 예제에서는 하위 속성을 포함하는 속성 및 간단한 속성을 유지하는 Book 컨트롤을 만드는 방법을 보여 줍니다.

간단한 속성은 문자열 형식 또는 문자열에 쉽게 매핑되는 형식의 속성입니다. 이 속성은 별도의 작업 없이 컨트롤의 여는 태그에 특성으로 유지됩니다. Boolean, Int16, Int32, Enum 같은 .NET Framework 클래스 라이브러리의 기본 값 형식 및 String 형식을 사용하는 속성이 간단한 속성입니다. 다시 게시할 때마다 상태 관리를 위해 간단한 속성을 ViewState 사전에 저장하는 코드를 추가할 수 있습니다.

속성 형식이 자체적으로 속성을 포함하는 클래스인 경우 이러한 속성을 복합 속성이라고 하며, 이 경우 포함된 속성을 하위 속성이라고 합니다. 예를 들어 WebControlFont 속성 형식은 BoldName 같은 속성을 포함하는 FontInfo 클래스입니다. BoldNameWebControlFont 속성에 대한 하위 속성입니다. ASP.NET 페이지 프레임워크에서는 하이픈으로 구분된 구문(예: Font-Bold="true")을 사용하여 컨트롤의 여는 태그에 하위 속성을 유지할 수 있지만 하위 속성을 컨트롤 태그(예: <font Bold="true">)에 유지하면 페이지에서 더 쉽게 읽을 수 있습니다.

비주얼 디자이너에서 하위 속성을 컨트롤의 자식으로 유지할 수 있게 하려면 몇 가지 디자인 타임 특성을 속성 및 속성 형식에 적용해야 합니다. 기본 지속성은 컨트롤 태그에 하이픈으로 구분된 특성입니다. 또한 이 항목의 뒷부분에 나오는 "코드 설명" 단원의 내용에서 알 수 있듯이 하위 속성을 포함하는 속성에도 뷰 상태를 사용하기 위해 사용자 지정 상태 관리가 필요합니다.

이 예제에 정의된 Book 컨트롤은 웹 페이지에서 카탈로그의 도서 관련 정보를 표시하기 위해 사용할 수 있는 컨트롤입니다. Book 컨트롤은 다음과 같은 속성을 정의합니다.

  • Author 속성은 형식이 사용자 지정 형식 Author인 하위 속성을 포함합니다. Author 형식에는 FirstNameLastName처럼 Author 속성의 하위 속성인 고유 속성이 있습니다.

  • BookType 속성은 형식이 사용자 지정 열거형 BookType인 간단한 속성입니다. BookType 열거형에는 FictionNonFiction과 같은 값이 있습니다.

  • CurrencySymbol 속성은 형식이 기본 제공 String 형식인 간단한 속성입니다.

  • Price 속성은 형식이 기본 제공 Decimal 형식인 간단한 속성입니다.

  • Title 속성은 형식이 기본 제공 String 형식인 간단한 속성입니다.

BookType, CurrencySymbol, PriceTitle 속성은 모두 간단한 속성이므로 페이지 지속성을 위해 특수한 특성이 필요하지 않습니다. 기본적으로 페이지 프레임워크에서는 다음 예제와 같이 이러한 속성을 컨트롤 태그의 특성으로 유지합니다.

<aspSample:Book Title="Wingtip Toys Stories" 
  CurrencySymbol="$" 
  Price="16" 
  BookType="Fiction">
</aspSample:Book>

다음 예제와 같이 Author 속성 및 Author 클래스 속성에는 컨트롤 태그 내에 지속성을 설정하기 위해 디자인 타임 특성이 필요합니다.

<aspSample:Book >
  <Author FirstName="Judy" LastName="Lew" />
</aspSample:Book>

Book 컨트롤은 ViewState 사전에 간단한 속성을 저장합니다. 그러나 Book 컨트롤은 다시 게시할 때마다 Author 속성이 속성의 상태를 관리할 수 있도록 사용자 지정 상태 관리를 구현해야 합니다.

Book 컨트롤을 프로덕션 수준으로 구현하여 출판사, 출판 날짜 등의 기타 도서 관련 데이터에 대한 속성을 정의할 수 있습니다. 또한 Author 속성을 컬렉션 속성으로 대체할 수 있습니다. 컬렉션 속성을 구현하는 데 대한 내용은 웹 컨트롤 컬렉션 속성 예제를 참조하십시오.

4s70936s.alert_note(ko-kr,VS.100).gif참고:

페이지 개발자는 페이지 또는 페이지의 개별 컨트롤에 대해 뷰 상태를 해제할 수 있습니다. 다시 게시할 때마다 컨트롤에서 내부 기능을 위해 중요한 상태를 유지해야 하는 경우, ASP.NET 2.0에 정의된 컨트롤 상태 메커니즘을 사용할 수 있습니다. 컨트롤 상태에 대한 내용은 컨트롤 상태와 뷰 상태 비교 예제에서 설명합니다.

// Book.cs
using System;
using System.ComponentModel;
using System.Security.Permissions;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace Samples.AspNet.CS.Controls
{
    [
    AspNetHostingPermission(SecurityAction.Demand,
        Level = AspNetHostingPermissionLevel.Minimal),
    AspNetHostingPermission(SecurityAction.InheritanceDemand, 
        Level=AspNetHostingPermissionLevel.Minimal),
    DefaultProperty("Title"),
    ToolboxData("<{0}:Book runat=\"server\"> </{0}:Book>")
    ]
    public class Book : WebControl
    {
        private Author authorValue;
        private String initialAuthorString;

        [
        Bindable(true),
        Category("Appearance"),
        DefaultValue(""),
        Description("The name of the author."),
        DesignerSerializationVisibility(
            DesignerSerializationVisibility.Content),
        PersistenceMode(PersistenceMode.InnerProperty),
        ]
        public virtual Author Author
        {
            get
            {
                if (authorValue == null)
                {
                    authorValue = new Author();
                }
                return authorValue;
            }

        }

        [
        Bindable(true),
        Category("Appearance"),
        DefaultValue(BookType.NotDefined),
        Description("Fiction or Not"),
        ]
        public virtual BookType BookType
        {
            get
            {
                object t = ViewState["BookType"];
                return (t == null) ? BookType.NotDefined : (BookType)t;
            }
            set
            {
                ViewState["BookType"] = value;
            }
        }

        [
        Bindable(true),
        Category("Appearance"),
        DefaultValue(""),
        Description("The symbol for the currency."),
        Localizable(true)
        ]
        public virtual string CurrencySymbol
        {
            get
            {
                string s = (string)ViewState["CurrencySymbol"];
                return (s == null) ? String.Empty : s;
            }
            set
            {
                ViewState["CurrencySymbol"] = value;
            }
        }


        [
        Bindable(true),
        Category("Appearance"),
        DefaultValue("0.00"),
        Description("The price of the book."),
        Localizable(true)
        ]
        public virtual Decimal Price
        {
            get
            {
                object price = ViewState["Price"];
                return (price  == null) ? Decimal.Zero : (Decimal)price;
            }
            set
            {
                ViewState["Price"] = value;
            }
        }

        [
        Bindable(true),
        Category("Appearance"),
        DefaultValue(""),
        Description("The title of the book."),
        Localizable(true)
        ]
        public virtual string Title
        {
            get
            {
                string s = (string)ViewState["Title"];
                return (s == null) ? String.Empty : s;
            }
            set
            {
                ViewState["Title"] = value;
            }
        }

        protected override void RenderContents(HtmlTextWriter writer)
        {
            writer.RenderBeginTag(HtmlTextWriterTag.Table);

            writer.RenderBeginTag(HtmlTextWriterTag.Tr);
            writer.RenderBeginTag(HtmlTextWriterTag.Td);
            writer.WriteEncodedText(Title);
            writer.RenderEndTag();
            writer.RenderEndTag();

            writer.RenderBeginTag(HtmlTextWriterTag.Tr);
            writer.RenderBeginTag(HtmlTextWriterTag.Td);
            writer.WriteEncodedText(Author.ToString());
            writer.RenderEndTag();
            writer.RenderEndTag();

            writer.RenderBeginTag(HtmlTextWriterTag.Tr);
            writer.RenderBeginTag(HtmlTextWriterTag.Td);
            writer.WriteEncodedText(BookType.ToString());
            writer.RenderEndTag();
            writer.RenderEndTag();

            writer.RenderBeginTag(HtmlTextWriterTag.Tr);
            writer.RenderBeginTag(HtmlTextWriterTag.Td);
            writer.Write(CurrencySymbol);
            writer.Write("&nbsp;");
            writer.Write(String.Format("{0:F2}", Price));
            writer.RenderEndTag();
            writer.RenderEndTag();

            writer.RenderEndTag();
        }

        protected override void LoadViewState(object savedState)
        {
            base.LoadViewState(savedState);

            Author auth = (Author)ViewState["Author"];
            if (auth != null)
            {
                authorValue = auth;
            }
        }

        protected override object SaveViewState()
        {
            if (authorValue != null)
            {
                String currentAuthorString = authorValue.ToString();
                if (!(currentAuthorString.Equals(initialAuthorString)))
                {
                    ViewState["Author"] = authorValue;
                }
            }

            return base.SaveViewState();
        }

        protected override void TrackViewState()
        {
            if (authorValue != null)
            {
                initialAuthorString = authorValue.ToString();
            }
            base.TrackViewState();
        }

    }
}


Book 컨트롤의 Author 속성에 적용된 DesignerSerializationVisibilityAttributePersistenceModeAttribute 특성에 대해서는 웹 컨트롤 컬렉션 속성 예제에서 설명합니다. 이러한 특성은 Author 클래스의 속성을 유지하고 serialize하는 데 필요합니다.

뷰 상태 메커니즘은 다시 게시할 때마다 상태를 유지하기 위해 ASP.NET에서 사용하는 기법을 말합니다. 이 메커니즘은 페이지 처리가 끝날 때 페이지 및 컨트롤 트리의 상태를 문자열 표현으로 serialize하고 다시 게시할 때 이 문자열을 deserialize합니다. 기본적으로 페이지는 이 문자열을 숨김 필드 형식으로 브라우저에 보냅니다. 자세한 내용은 ASP.NET 상태 관리 개요를 참조하십시오.

간단한 속성의 상태를 관리하려면 이 속성을 컨트롤의 ViewState 속성에 저장되는 읽기/쓰기 속성으로 정의합니다. Book 컨트롤은 간단한 속성(BookType, CurrencySymbol, Price, Title)을 이 방법으로 정의합니다. ViewState 속성에 저장하는 속성의 상태는 별도의 작업 없이 자동으로 관리됩니다.

하위 속성이 있는 속성을 관리하려면 이 속성을 읽기 전용으로 정의하거나, 개체의 상태를 관리하는 코드를 작성할 수 있습니다. 이를 위해 다음과 같은 메서드를 재정의합니다.

ViewState 속성의 StateBag 형식은 상태 관리 기능이 기본으로 제공되는 사전입니다. StateBag 클래스는 TrackViewState, SaveViewStateLoadViewState 메서드를 정의하는 IStateManager 인터페이스를 구현합니다. StateBag 클래스는 이러한 메서드를 구현하여 초기화 후에 컨트롤 속성의 변경 내용을 추적하고, 페이지 요청이 끝나면 수정된 항목을 저장하고, 다시 게시하는 경우 저장된 상태를 항목에 로드합니다. StateBag 클래스는 페이지 요청에 대해 OnInit 메서드가 실행된 후에 항목이 설정되는 경우 이 항목을 수정된 것으로 표시하여 항목을 추적합니다. 예를 들어 페이지를 초기화한 후에 페이지에서 코드를 실행하여 Book 컨트롤의 Title 속성을 설정하면 ViewState["Title"] 항목이 변경됩니다. 따라서 ViewState에서 "Title"키 아래에 저장된 값이 수정된 것으로 표시됩니다. 자세한 내용은 ASP.NET 페이지 수명 주기 개요를 참조하십시오.

Book 컨트롤은 Author 속성을 읽기 전용 속성으로 정의하고 사용자 지정 상태 관리를 다음과 같이 구현합니다.

  • TrackViewState 메서드에서 Book 컨트롤은 먼저 초기 Author 속성을 문자열로 저장한 다음, 기본 클래스의 TrackViewState 메서드를 호출하여 상태 추적을 시작합니다.

  • SaveViewState 메서드에서 Book 컨트롤은 Author 속성이 초기 값에서 변경되었는지 여부를 확인합니다. 속성이 변경된 경우 Book 컨트롤은 "Author" 키를 사용하여 Author 속성을 ViewState 사전에 저장합니다. 그런 다음 Book 컨트롤은 기본 클래스의 SaveViewState 메서드를 호출합니다. 상태 추적 기능이 설정되어 있으므로 ViewState에 저장된 Author 개체는 자동으로 수정 표시된 후 기본 클래스에 대한 뷰 상태의 일부로 저장됩니다.

  • LoadViewState에서 Book 컨트롤은 먼저 기본 클래스의 LoadViewState 메서드를 호출합니다. 이 메서드를 호출하면 ViewState 사전이 자동으로 복원됩니다. 그런 다음 Book 컨트롤은 ViewState 사전에서 "Author" 아래에 저장된 항목이 있는지 여부를 확인합니다. 해당 항목이 있는 경우 컨트롤은 뷰 상태 값을 Author 속성에 로드합니다.

다음에 나오는 코드 목록에 정의된 Author 형식에는 Author 인스턴스를 뷰 상태에 저장할 수 있도록 사용자 지정 형식 변환기가 있습니다. 이 형식 변환기는 Author 인스턴스를 문자열로 변환하거나 문자열을 Author 인스턴스로 변환합니다. 형식 변환기를 정의하면 Author의 하위 속성을 비주얼 디자이너에 설정할 수 있습니다. 사용자 지정 형식 변환기에 대한 내용은 형식 변환기 예제에서 설명합니다. 뷰 상태에 저장할 수 있는 형식은 뷰 상태 serialization을 위해 ASP.NET에서 사용하는 LosFormatter 클래스의 제한을 받습니다. 가장 효과적으로 serialize되는 형식은 String 형식, .NET Framework 클래스 라이브러리의 기본 값 형식(예: Boolean, Int16, Int32, Enum, Pair, Triplet, Array, ArrayList, Hashtable) 및 이러한 기본 형식을 포함하는 모든 형식 등입니다. 또한 Pair, Triplet, Array, ArrayListHashtable처럼 형식 변환기가 정의되어 있는 사용자 지정 형식도 뷰 상태에 저장할 수 있습니다. 컨트롤에 대해 뷰 상태 serialization을 정의하는 경우 컨트롤 데이터를 이러한 형식 중 하나로 변환해야 합니다. 뷰 상태 serialization 메커니즘과 호환되지 않는 형식을 뷰 상태에 저장하면 컨트롤이 컴파일되기는 하지만 런타임에 오류가 발생합니다. 마지막으로, serialize할 수 있는 형식, 즉 ISerializable 인터페이스를 구현하거나 SerializableAttribute로 표시된 형식은 뷰 상태에 저장할 수 있지만 이러한 형식을 serialize하면 기본 형식을 serialize하는 것보다 훨씬 느리게 실행됩니다.

serialization을 위해 컨트롤에서 제공하는 상태 개체는 컨트롤의 뷰 상태입니다. 컨트롤의 ViewState 속성은 컨트롤의 뷰 상태 중 하나이며 별도의 작업 없이 뷰 상태 메커니즘에 자동으로 사용됩니다. Control 클래스는 SaveViewStateLoadViewState 메서드를 사용하여 ViewState 사전의 수정된 항목을 저장하고 로드하는 논리를 구현합니다. 뷰 상태의 나머지 부분은 SaveViewState 메서드 재정의를 통해 사용자 또는 컨트롤의 기본 클래스에서 뷰 상태에 저장하는 추가 개체입니다. SaveViewStateLoadViewState 메서드를 재정의하는 경우 기본 클래스의 해당 메서드를 호출해야 합니다.

NotifyParentPropertyAttributeFirstName, LastNameMiddleName 속성에 적용하고 이 특성의 생성자 인수를 true로 설정하면 비주얼 디자이너에서 이러한 속성의 변경 내용을 부모 속성, 즉 Author 인스턴스로 전파하고 serialize합니다.

// Author.cs
using System;
using System.Collections;
using System.ComponentModel;
using System.Globalization;
using System.Web.UI;

namespace Samples.AspNet.CS.Controls
{
    [
    TypeConverter(typeof(AuthorConverter))
    ]
    public class Author
    {
        private string firstnameValue;
        private string lastnameValue;
        private string middlenameValue;

        public Author()
            :
            this(String.Empty, String.Empty, String.Empty)
        {
        }

        public Author(string firstname, string lastname)
            :
            this(firstname, String.Empty, lastname)
        {
        }

        public Author(string firstname, 
                    string middlename, string lastname)
        {
            firstnameValue = firstname;
            middlenameValue = middlename;
            lastnameValue = lastname;
        }

        [
        Category("Behavior"),
        DefaultValue(""),
        Description("First name of author."),
        NotifyParentProperty(true),
        ]
        public virtual String FirstName
        {
            get
            {
                return firstnameValue;
            }
            set
            {
                firstnameValue = value;
            }
        }

        [
        Category("Behavior"),
        DefaultValue(""),
        Description("Last name of author."),
        NotifyParentProperty(true)
        ]
        public virtual String LastName
        {
            get
            {
                return lastnameValue;
            }
            set
            {
                lastnameValue = value;
            }
        }

        [
        Category("Behavior"),
        DefaultValue(""),
        Description("Middle name of author."),
        NotifyParentProperty(true)
        ]
        public virtual String MiddleName
        {
            get
            {
                return middlenameValue;
            }
            set
            {
                middlenameValue = value;
            }
        }

        public override string ToString()
        {
            return ToString(CultureInfo.InvariantCulture);
        }

        public string ToString(CultureInfo culture)
        {
            return TypeDescriptor.GetConverter(
                GetType()).ConvertToString(null, culture, this);
        }
    }
}


// BookType.cs
using System;

namespace Samples.AspNet.CS.Controls
{
    public enum BookType
    {
        NotDefined = 0,
        Fiction = 1,
        NonFiction = 2
    }
}


다음 예제에서는 Book 컨트롤을 사용하는 .aspx 페이지를 보여 줍니다.

<%@ Page Language="C#" Debug="true" Trace="true"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
  void Button_Click(object sender, EventArgs e)
  {
    Book1.Author.FirstName = "Bob";
    Book1.Author.LastName = "Kelly";
    Book1.Title = "Contoso Stories";
    Book1.Price = 39.95M;
    Button1.Visible = false;
  }  
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
  <head id="Head1" runat="server">
    <title>
      Book test page
    </title>
  </head>
  <body>
    <form id="Form1" runat="server">
      <aspSample:Book ID="Book1" Runat="server"  
        Title="Tailspin Toys Stories" CurrencySymbol="$" 
        BackColor="#FFE0C0" Font-Names="Tahoma" 
        Price="16" BookType="Fiction">
        <Author FirstName="Judy" LastName="Lew" />
      </aspSample:Book>
      <br />
      <asp:Button ID="Button1" OnClick="Button_Click" 
        Runat="server" Text="Change" />
      <asp:Button ID="Button2" Runat="server" Text="Refresh" />
      <br />
      <br />
      <asp:HyperLink ID="Hyperlink1" NavigateUrl="BookTest.aspx" 
        Runat="server">
        Reload Page</asp:HyperLink>
    </form>
  </body>
</html>


형식 변환기 예제에 나열된 AuthorConverter 클래스를 사용하여 이 예제의 클래스를 컴파일합니다.

사용자 지정 컨트롤 예제의 컴파일 및 사용에 대한 자세한 내용은 사용자 지정 서버 컨트롤 예제 빌드를 참조하십시오.

표시: