2009-10-21 69 views
7

我正在嘗試編寫一個簡單的實用程序webcontrol,以在網頁中顯示單行消息 - 狀態更新,錯誤消息等。通過調用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裏面,結果也一樣。

+0

請注意,由於您不是將您的CssClass或html編碼爲內容的屬性編碼,因此您可能容易遭受注入攻擊,如果這不在其他地方進行。 – daveidmx 2012-02-22 16:04:10

回答

3

而是修改爲「Visible」屬性,試試這個:

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

請注意,如果Visible設置爲false,則不會調用Render(),因此此方法無法再次使控件可見。只要你完全離開Visible就可以了。 – stevemegson 2009-10-22 15:39:39

+1

噢,這真的很聰明!並將可見屬性留作其他用途。比我的解決方案更好! – 2009-10-23 18:09:53

0

我建議使用的OnInit代替:

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

這會發生得太早。我的消息在其OnLoad和事件方法期間由其他控件添加。如果我將這一步放入OnInit,我將永遠不會顯示任何消息。 – 2009-10-21 14:24:12

+0

瞭解,我只是認爲黑客控制屬性來解僱你的事件可能很難維持。 – 2009-10-21 14:58:42

5

其實我想通了這一點我自己,我想答案應該是對社會有益的。

它看起來像一個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); 
} 
+2

我使用OnPreRender進行了測試,事件沒有像你所說的那樣被調用,我從來沒有想過這件事,但我想這是有道理的,如果控件設置爲Visible = False,那麼沒有什麼可呈現的。 – 2009-10-21 02:36:06

2

如果你有代碼,必須在PreRender運行,即使控制是不可見的(所以OnLoad中的設置Visible=true不是解決方案),那麼您可以利用Page的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

嗯,這將工作。有趣的方法。 – 2009-10-23 18:06:29