'CompositeControl'에 해당되는 글 2건

Programming/.NET

특정 페이지에 ListBox와 같은 컨트롤을 배치하고 Design화면을 보면 다음과 같이 컨트롤을 디자인 할 수 있는 화면을 볼 수 있습니다.

 

컨트롤을 직접 작성하는 경우 이와 같은 기능을 구현하기 위해서는 우선 컨트롤을 직접 디자인할 수 있도록 하는 컨트롤디자이너를 생성해야 합니다.

 

public class WebCustomControl1ControlDesigner : CompositeControlDesigner

 

컨트롤 디자이너는 CompositeControlDesigner 추상클래스를 상속받도록 합니다. 우선 컨트롤 디자이너는 클래스형태만 만들어둡니다.

 

[Designer(typeof(WebCustomControl1ControlDesigner))]
[ToolboxData("<{0}:WebCustomControl1 runat=\"server\" width=\"100%\"></{0}:WebCustomControl1>")]
public class WebCustomControl1 : CompositeControl

 

이제 컨트롤 디자이너가 들어갈 컨테이너 컨트롤을 작성합니다. 이 컨트롤은 CompositeControl 클래스를 상속받습니다.

 

Designer 특성은 해당 컨테이너에 들어갈 디자이너 컨트롤을 지정하며 ToolboxData는 사용자가 해당 컨트롤을 페이지에 배치할때 표시될 내요을 지정합니다. {0}은 접두사가 붙는 부분입니다.

 

[PersistenceMode(PersistenceMode.InnerProperty), DefaultValue(null)]
public virtual ITemplate View
{
    get;
    set;
}

protected override void CreateChildControls()
{
    Controls.Clear();

    ITemplate template = View;

    Panel p = new Panel();
    Controls.Add(p);

    if (template != null)
        template.InstantiateIn(p);
}

 

컨테이너 컨트롤인 WebCustomControl1 클래스 에는 화면에 표시될 ITemplate 내부 속성을 추가하고 디자이너 컨트롤을 생성할 CreateChildControls 메소드를 재정의합니다. 여기까지 하면 컨테이너 컨트롤의 내부를 모두 작성한 것입니다.

 

private WebCustomControl1 myControl;

 

이제 디자이너 컨트롤인 WebCustomControl1ControlDesigner 클래스를 작성합니다. 디자이너 컨트롤에서는 컨테이너 컨트롤에 직접 접근할 필요가 있으므로 WebCustomControl1 형식의 컨트롤변수를 생성합니다.

 

public override void Initialize(IComponent component)
{
    base.Initialize(component);
    myControl = (WebCustomControl1)component;
}

 

초기화 메소드를 재정의하여 위에서 선언한 myControl에 컨테이너 컨트롤을 담아두도록 합니다.

 

public override string GetDesignTimeHtml(DesignerRegionCollection regions)
{
    return DesignHtml();
}

 

컨트롤이 화면에 배치되면 GetDesignTimeHtml 메소드가 자동으로 호출되는데 디자인타임에 표시할 내용을 직접 작성할 것이므로 해당 메소드를 재정의합니다.

 

protected virtual string DesignHtml()
{
    StringBuilder sb = new StringBuilder();

    sb.Append(BeginDesignHtml());
    sb.Append(ContentDesignHtml());
    sb.Append(EndDesignHtml());

    return sb.ToString();
}

protected virtual String BeginDesignHtml()
{
    StringBuilder sb = new StringBuilder();
    sb.Append("<table border='10'>");
    sb.Append("<tr>");
    sb.Append("<td>");

    return sb.ToString();
}

protected virtual String EndDesignHtml()
{
    return "</tr></td></table>";
}

protected virtual String ContentDesignHtml()
{
    StringBuilder sb = new StringBuilder();
    sb.Append("디자인 화면");

    return sb.ToString();
}

 

GetDesignTimeHtml 메소드에서는 DesignHtml 이라는 메소드를 반환하는데 이때 DesignHtml 메소드가 진짜 디자인타임에 표시할 HTML을 생성하는 메소드입니다. 이 메소드는 BeginDesignHtml, ContentDesignHtml, EndDesignHtml 메소드를 차례로 호출하여 HTML 문자열을 얻는데 각각의 Html메소드를 보시면 실제 가져올 HTML의 내용을 구현하고 있습니다.

 

public override string GetEditableDesignerRegionContent(EditableDesignerRegion region)
{
    IDesignerHost host = (IDesignerHost)Component.Site.GetService(typeof(IDesignerHost));

    if (host != null)
    {
        ITemplate template = myControl.View;

        if (template != null)
            return ControlPersister.PersistTemplate(template, host);
    }

    return String.Empty;
}

public override void SetEditableDesignerRegionContent(EditableDesignerRegion region, string content)
{
    if (content == null) {
        myControl.View = null;
        return;
    }

    IDesignerHost host = (IDesignerHost)Component.Site.GetService(typeof(IDesignerHost));

    if (host != null) {
        ITemplate template = ControlParser.ParseTemplate(host, content);

        if (template != null)
            myControl.View = template;
    }
}

 

재정의한 GetEditableDesignerRegionContent 메소드와 SetEditableDesignerRegionContent 메소드는 각각 상황에 따라 필요한 HTML을 가져오거나 설정하기 위한 메소드입니다.

 

이제 컨트롤을 빌드 후 필요한 페이지에서 컨트롤을 끌어다 놓으면 디자인타임에 표시할 HTMl을 확인할 수 있습니다.

 

 

컨트롤을 작성할 시에 사용자로 부터 입력될 값은 속성을 통해 받을 수 있는데 이 속성의 특성에 따라 전용 편집기를 호출하여 속성값의 입력을 좀더 비주얼적으로 처리할 수 있습니다.

 

public string Url
{
    get
    {
        String s = (String)ViewState["Url"];
        return ((s == null) ? String.Empty : s);
    }

    set
    {
        ViewState["Url"] = value;
    }
}

 

예를 들어 위와 같이 Url 입력이 필요한 속성을 정의하였다면

 

[Editor(typeof(UrlEditor), typeof(UITypeEditor))]

 

해당 속성의 특성을 위와 같이 정의하여 Url입력에 필요한 입력상자를 호출할 수 있도록 처리할 수 있습니다.

0 0
Programming/.NET

서버 컨트롤안에서 RenderContents 메소드로 HTML을 렌더링을 통하여 특정 컨트롤을 생성하는 대신에 컨트롤을 직접 렌더링할 수도 있습니다.

 

public class WebCustomControl1 : CompositeControl

 

이를 위해 서버 컨트롤에서는 기존 WebControl 대신 CompositeControl 클래스로부터 상속받아야 합니다.

 

protected TextBox textbox = new TextBox();

protected override void CreateChildControls()
{
    this.Controls.Add(textbox);
}

 

예를 들어 TextBox 컨트롤을 생성하려면 해당 TextBox의 컨트롤 개체를 생성해 CreateChildControls 메소드를 재정의 하여 컨트롤을 추가하면 됩니다.

 

이것이 전부입니다. 기존의 RenderContents 메소드같은건 더이상 존재하지 않습니다.

 

다만 실제 위와같이 작성된 서버 컨트롤은 비록 TextBox와 같은 컨트롤을 포함하고 있다 하더라도 속성등을 통해 포함된 TextBox의 속성에는 접근할 수 없습니다. TextBox속성을 그대로 서버 컨트롤에서 구현하려면 원하는 속성을 직접 정의해 줘야 합니다.

 

protected override void CreateChildControls()
{
    this.Controls.Add(textbox);
    this.ChildControlsCreated = true;
}

 

먼저 해당 속성 구현을 위해 CreateChildControl 메소드에서 ChildControlsCreated 속성을 true로 설정합니다.

 

public string Text
{
    get {
        EnsureChildControls();
        return textbox.Text;
    }
    set {
        EnsureChildControls();
        textbox.Text = value;
    }
}

 

그 다음 속성을 구현하면 되는데 이때 사용된 EnsureChildControls() 메소드는 속성으로 접근될 해당 컨트롤이 실제 생성되어 있는지 여부를 판단합니다.

 

서버 컨트롤은 위에서 처럼 단순히 컨트롤 하나를 렌더링할 수 있지만 HTML요소를 포함하는 특정 템플릿 형식의 컨트롤을 표현할 수 있는 방안또한 제공하고 있습니다.

 

템플릿 컨트롤사용을 위해서는 우선 템플릿으로 활용할 컨트롤을 생성해야 합니다.

 

public class ContentBox : Label, INamingContainer
{
    public string message { get; internal set; }
}

 

ContentBox라는 컨트롤은 Label에서 상속받은 컨트롤이며 INamingContainer 인터페이스를 상속받습니다. 그리고 해당 컨트롤에서 특정 내용을 표시하기 위해 message라는 string형식의 속성하나를 두었습니다.

 

public class WebCustomControl1 : WebControl

 

템플릿 형식의 컨트롤 사용시에 서버 컨트롤은 WebControl로부터 상속받습니다.

 

[Browsable(false)]
public ContentBox lbl { get; internal set; }

 

이전에 생성한 ContentBox컨트롤의 개체를 생성하며 입력과 출력에 대한 속성을 설정합니다. 해당 개체는 직접 외부에 드러날 필요가 없으므로 Browsable특성을 false로 설정합니다.

 

[PersistenceMode(PersistenceMode.InnerProperty)]
[TemplateContainer(typeof(ContentBox))]
public virtual ITemplate lblTemplate { get; set; }

 

실제 화면에 표시하기 위한 템플릿을 생성합니다. 이 템플릿은 페이지 내부에서 속성으로 접근되며 ComtentBox형식으로 표현됩니다.

 

[Browsable(true)]
[DefaultValue("")]
public string message { get; set; }

 

컨트롤에서 설정가능한 속성을 추가합니다. 이 속성에서 설정한 값이 lblTemplate에 의해 표시될 것입니다.

 

public override void DataBind()
{
    EnsureChildControls();
    ChildControlsCreated = true;

    base.DataBind();
}

 

DataBind 메소드를 위와같이 재정의합니다. 페이지에서 DataBind함수가 호출되면 실제 템플릿이 설정된 속성으로 표시됩니다.

 

protected override void CreateChildControls()
{
    this.Controls.Clear();
    this.lbl = new ContentBox() { message = message };
    this.lblTemplate.InstantiateIn(this.lbl);

    Controls.Add(this.lbl);
}

 

CreateChildControls 메소드를 재정의 하여 템플릿이 컨트롤로 추가될수 있도록 구현합니다.

 

여기까지 서버 컨트롤을 작성하고 나면 이제 서버 컨트롤이 올라간 페이지에서 템플릿을 구현해야 합니다.

 

<cc1:WebCustomControl1 runat="server" ID="myControl" message="반갑습니다.">
    <lblTemplate>안녕하세요. <%# Container.message %></lblTemplate>
</cc1:WebCustomControl1>

 

서버 컨트롤에서 message 속성에 값을 입력하고 하위에 템플릿을 정의합니다. Container는 템플릿을 포함하고 있는 서버 컨트롤을 의미하며 서버 컨트롤의 message값을 받아 출력하도록 처리하고 있습니다.

'Programming > .NET' 카테고리의 다른 글

[ASP.NET] 서버 컨트롤 - 8 (디자인)  (0) 2017.03.03
[ASP.NET] 서버 컨트롤 - 7 (형변환)  (0) 2017.02.22
[ASP.NET] 서버 컨트롤 - 6 (컨트롤)  (0) 2017.02.08
[ASP.NET] HttpModule, HttpHandler  (0) 2017.02.02
[ASP.NET] AJAX  (0) 2017.01.24
[ASP.NET] 캐시 - 2  (0) 2017.01.17
0 0
1
블로그 이미지

클리엘