2009-10-21 4 views
7

Ich versuche, ein einfaches Dienstprogramm Webcontrol zu schreiben, um einzeilige Nachrichten innerhalb einer Webseite anzuzeigen - Status-Updates, Fehlermeldungen, etc. Die Nachrichten kommen von anderen Steuerelementen auf der Seite, durch Aufruf einer Methode im Webcontrol. Wenn das Steuerelement bis zu dem Zeitpunkt, zu dem es gerendert werden soll, keine Nachrichten mehr enthält, möchte ich nicht, dass es auf der Seite überhaupt gerendert wird. Ich möchte, dass es Control.Visible = false setzt. Dies scheint jedoch nur für das Rendering ohne Postback zu funktionieren. Hier ist der Code Ich verwende:An welchem ​​Punkt im Control Lifecycle hört Control.Visible auf zu rendern?

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 

} 

Ich habe versucht, zu dem Scheck innerhalb Create setzen, mit dem gleichen Ergebnis.

+0

Seien Sie sich bewusst, dass Sie anfällig für Injection-Angriffe sind, wenn Sie keine Codierung für Ihre CssClass- oder HTML-Codierung für Ihre Inhalte vornehmen, wenn dies nicht an anderer Stelle geschieht. – daveidmx

Antwort

3

Statt die ‚Visible‘ Eigenschaft ändern, versuchen Sie dies:

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

Beachten Sie, dass Render() nicht aufgerufen wird, wenn Visible auf false festgelegt wird, sodass dieses Steuerelement das Steuerelement nicht wieder sichtbar machen kann. Solange du Visible alleine verlässt, geht es dir gut. – stevemegson

+1

Ooo, das ist wirklich schlau! Und lässt die sichtbare Eigenschaft für andere Zwecke verfügbar. Besser als meine Lösung! –

0

Ich schlage vor, mit OnInit statt:

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

Dies würde zu früh auftreten. Meine Nachrichten werden während ihrer OnLoad- und event-Methoden von anderen Steuerelementen hinzugefügt. Wenn ich diesen Schritt in OnInit lege, werde ich nie irgendwelche Nachrichten haben, die ich zeigen kann. –

+0

Verstehen Sie, ich denke nur, dass das Hacken der Steuereigenschaft zum Abfeuern Ihres Ereignisses schwer aufrechtzuerhalten ist. –

5

ich dies tatsächlich herausgefunden mich, und ich dachte, die Antwort auf die Gemeinschaft nützlich sein würde.

Es scheint, als ob ein Steuerelement, das Control.Visible auf false gesetzt hat, tatsächlich nach dem Page_Load -Ereignis anhält. Der Trick dabei ist, dass die Control.Visible-Eigenschaft in ViewState geladen wird. Wenn also keine Nachrichten auf der ersten Seite angezeigt werden, setzt sich das Steuerelement auf Visible = false und erreicht nie wieder CreateChildControls oder OnPreRender.

Die Lösung besteht darin, die Sichtbarkeit des Steuerelements in einem der früheren Ereignisse zurückzusetzen, die nicht übersprungen werden. Die folgende Änderung mein Problem gelöst:

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

Ich getestet mit OnPreRender und das Ereignis wird nicht aufgerufen, wie Sie angegeben, ich hatte nie darüber nachgedacht, aber ich denke, es macht Sinn, wenn das Steuerelement auf Visible = False festgelegt ist, gibt es nichts zu rendern. –

2

Wenn Sie hatten Code, der auf PreRender auch wenn die Steuerung unsichtbar ausgeführt werden muss (so Diese Einstellung Visible=true in OnLoad ist keine Lösung), Sie könnten die Tatsache nutzen, dass das PreRender-Ereignis der Seite immer ausgelöst wird.

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; 
} 

Dies betrifft auch die Möglichkeit, dass der Elternteil (oder der andere Vorgänger) des Steuerelements unsichtbar ist. In diesem Fall wird der OnPreRender des Steuerelements nicht ausgelöst, selbst wenn Sie sicherstellen, dass Visible = true für das Steuerelement selbst ist.

+0

Hmm, das würde funktionieren. Interessanter Ansatz. –

Verwandte Themen