2009-10-21 5 views
7

웹 페이지에 한 줄 메시지 (상태 업데이트, 오류 메시지 등)를 표시하는 간단한 유틸리티 webcontrol을 작성하려고합니다. 메시지는 웹 컨트롤에서 메서드를 호출하여 페이지의 다른 컨트롤에서 가져옵니다. 컨트롤이 미리 랜더링 될 때까지 메시지가 없다면 페이지에 렌더링을 원하지 않습니다. Control.Visible = false로 설정하고 싶습니다. 이것은 포스트 백 렌더링이 아닌 경우에만 작동하는 것처럼 보입니다. 여기에 내가 사용하고 코드는 다음과 같습니다컨트롤 수명주기의 어느 시점에서 Control.Visible이 렌더링을 중지합니까?

public class MessageList : WebControl 
{ 

#region inner classes 

    private struct MessageItem 
    { 
     string Content, CssClass; 

     public MessageItem(string content, string cssClass) 
     { 
      Content = content; 
      CssClass = cssClass; 
     } 

     public override string ToString() 
     { return "<li" + (String.IsNullOrEmpty(CssClass) ? String.Empty : " class='" + CssClass + "'") + ">" + Content + "</li>"; } 
    } 

    private class MessageQueue : Queue<MessageItem> { } 

#endregion 

#region fields, constructors, and events 

    MessageQueue queue; 

    public MessageList() : base(HtmlTextWriterTag.Ul) 
    { 
     queue = new MessageQueue(); 
    } 

    protected override void OnLoad(EventArgs e) 
    { 
     this.Controls.Clear(); 
     base.OnLoad(e); 
    } 

    protected override void OnPreRender(EventArgs e) 
    { 
     this.Visible = (queue.Count > 0); 

     if (this.Visible) 
     { 
      while (queue.Count > 0) 
      { 
       MessageItem message = queue.Dequeue(); 
       this.Controls.Add(new LiteralControl(message.ToString())); 
      } 
     } 

     base.OnPreRender(e); 
    } 

#endregion 

#region properties and methods 

    public void AddMessage(string content, string cssClass) 
    { queue.Enqueue(new MessageItem(content, cssClass)); } 

    public void AddMessage(string content) 
    { AddMessage(content, String.Empty); } 

#endregion 

} 

내가 같은 결과로, 너무을 CreateChildControls 내부 검사를 넣어했습니다.

protected override void OnInit(EventArgs e) 
{ 
    base.OnInit(e); 

    this.Visible = (queue.Count > 0); 

    if (this.Visible) 
    { 
     while (queue.Count > 0) 
     { 
      MessageItem message = queue.Dequeue(); 
      this.Controls.Add(new LiteralControl(message.ToString())); 
     } 
    } 
} 
+0

콘텐츠를 CssClass 또는 html로 인코딩하는 특성이 아니기 때문에 다른 곳에서 수행되지 않는 경우 주입 공격에 취약 할 수 있습니다. – daveidmx

답변

3

을,이 시도 :

protected override void Render(HtmlTextWriter writer) 
    { 
     if (queue.Count > 0) 
      base.Render(writer); 
    } 
+0

Visible이 false로 설정되면 Render()가 호출되지 않으므로이 방법으로는 컨트롤을 다시 볼 수 없습니다. Visible을 전적으로 내버려 두는 한 괜찮습니다. – stevemegson

+1

우우, 정말 똑똑 하네! 그리고 보이는 속성을 다른 용도로 사용할 수있게합니다. 내 솔루션보다 낫다! –

0

내가 대신하는 OnInit 사용하는 것이 좋습니다.

Control.Visible을 false로 설정 한 컨트롤은 실제로 Page_Load 이벤트 다음에 언젠가 멈 춥니 다. 여기서 트릭은 Control.Visible 속성이 ViewState에로드된다는 것입니다. 따라서 첫 페이지 히트에 메시지가 없으면 컨트롤은 Visible = false로 설정되고 다시 CreateChildControls 또는 OnPreRender에 도달하지 않습니다.

해결 방법은 건너 뛰지 않은 이전 이벤트 중 하나에서 컨트롤의 가시성을 재설정하는 것입니다. 다음의 변화는 내 문제 해결 다음 '가시'속성을 수정하는 대신

protected override void OnLoad(EventArgs e) 
{ 
--> this.Visible = true; 
    this.Controls.Clear(); 
    base.OnLoad(e); 
} 
+0

너무 일찍 발생합니다. 내 메시지는 OnLoad 및 이벤트 메서드 중에 다른 컨트롤에 의해 추가됩니다. OnInit에이 단계를 추가하면 어떤 메시지도 표시되지 않습니다. –

+0

이해하십시오. 이벤트를 시작하기 위해 컨트롤 속성을 해킹하는 것이 유지 관리가 어려울 수도 있습니다. –

5

가 실제로 자신이 알아 낸, 나는 대답은 지역 사회에 도움이 될 것이라고 생각 :

+2

OnPreRender를 사용하여 테스트 한 결과, 사용자가 명시한대로 이벤트가 호출되지 않았다고 생각하지 않았지만 컨트롤이 Visible = False로 설정된 경우 렌더링 할 내용이 없다고 생각됩니다. –

2

그렇게 (컨트롤이 보이지 않는 경우에도 사전 렌더링에서 실행해야하는 코드가 있다면 OnLoad의 Visible=true 설정이 해결책이 아님) 페이지의 PreRender 이벤트가 항상 실행된다는 사실을 활용할 수 있습니다.

protected void AlwaysPreRender(object sender, EventArgs e) 
{ 
    if (/* some condition */) 
    { 
     this.Visible = true; 
    } 
    // else leave Visible as it was 
} 

protected override void OnLoad(EventArgs e) 
{ 
    Page.PreRender += this.AlwaysPreRender; 
} 

이것은 또한 컨트롤의 부모 (또는 다른 조상)가 보이지 않을 가능성을 다룹니다. 이 경우 컨트롤 자체에서 Visible = true를 보장하더라도 컨트롤의 OnPreRender는 실행되지 않습니다.

+0

흠, 그게 효과가있다. 재미있는 접근법. –

관련 문제