2009-10-21 12 views
7

Próbuję napisać proste narzędzie webcontrol do wyświetlania komunikatów jednoliniowych na stronie internetowej - aktualizacje statusu, komunikaty o błędach itp. Komunikaty będą pochodzić z innych elementów sterujących na stronie, wywołując metodę na kontrolerze sieciowym. Jeśli formant nie ma żadnych komunikatów do czasu renderowania, nie chcę, aby był renderowany na stronie - chcę ustawić Control.Visible = false. Wydaje się to jednak działać tylko w przypadku renderowania bez odświeżania. Oto kod, którego używam:W którym momencie cyklu kontrolnego działa Kontrola. Czy możliwe jest zatrzymanie renderowania?

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 

} 

Próbowałem również wstawić czek do CreateChildControls z tym samym wynikiem.

+0

Należy pamiętać, że skoro nie jest to atrybut kodujący zawartość kodu CssClass lub kod HTML, użytkownik może być podatny na ataki przy użyciu wstrzykiwań, jeśli nie jest to robione gdzie indziej. – daveidmx

Odpowiedz

3

Zamiast modyfikowania „visible” własność, spróbuj tego:

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

Należy zauważyć, że jeśli opcja Widoczne zostanie ustawiona na wartość false, funkcja Render() nie będzie wywoływana, więc to podejście nie może uczynić kontroli widoczną ponownie. Dopóki całkowicie opuszczasz Visible, nic ci nie jest. – stevemegson

+1

Ooo, to naprawdę sprytne! Pozostawia widoczną właściwość do innych celów. Lepsze niż moje rozwiązanie! –

0

Proponuję za pomocą OnInit zamiast:

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

Wystąpiłoby to zbyt wcześnie. Moje wiadomości są dodawane przez inne kontrolki podczas ich metod OnLoad i zdarzeń. Jeśli wstawię ten krok do OnInit, nigdy nie będę miał żadnych wiadomości do pokazania. –

+0

Rozumiem, po prostu myślę, że włamywanie się do obiektu sterującego w celu wywołania zdarzenia może być trudne do utrzymania. –

5

I faktycznie zdobione ten sam, a myślałem, że odpowiedź byłaby przydatna dla społeczności.

Wygląda to na formant, który ma formant Control.Visible ustawiony na false faktycznie zatrzymuje się po zdarzeniu Page_Load. Sztuczka polega na tym, że właściwość Control.Visible jest ładowana do ViewState. Więc jeśli nie ma żadnych komunikatów na trafieniu pierwszej strony, kontrola ustawia się na Visible = false i nigdy nie dociera do CreateChildControls lub OnPreRender.

Rozwiązaniem jest zresetowanie widoczności kontrolki w jednym z wcześniejszych zdarzeń, które nie są pomijane. Poniższa zmiana rozwiązać mój problem:

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

Testowałem z OnPreRender i wydarzenie nie zostało wywołane tak jak powiedziałeś, nigdy o tym nie myślałem, ale domyślam się, że jeśli kontrola jest ustawiona na Visible = False, to nie ma nic do renderowania. –

2

Jeśli miał kod, który musi działać na prerender nawet jeśli kontrola jest niewidoczna (tak że ustawienie Visible=true w OnLoad nie jest rozwiązaniem), możesz wykorzystać fakt, że zdarzenie PreRender strony zawsze będzie się uruchamiać.

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

Dotyczy to również możliwości, że rodzic rodzica (lub inny przodek) jest niewidoczny. W takim przypadku kontrolka OnPreRender nie uruchomi się, nawet jeśli upewnisz się, że Visible = true na samym sterowaniu.

+0

Hmm, to by działało. Interesujące podejście. –

Powiązane problemy