2009-10-21 4 views
7

私は、Webページ内に1行のメッセージ(ステータス更新、エラーメッセージなど)を表示するための簡単なユーティリティwebcontrolを作成しようとしています。メッセージは、Webコントロール上のメソッドを呼び出すことによってページの他のコントロールから来ます。コントロールがレンダリングされるまでにメッセージがない場合は、ページ上にレンダリングしたくないので、Control.Visible = falseを設定します。これは、非ポストバックレンダリングでも機能するようです。ここで私が使用しているコードです:Controlライフサイクルのどの時点で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

答えて

3

代わりの「可視」プロパティを変更し、この試してください:あなたがコントロールが見えない場合でも、(そうのPreRender上で実行する必要がありますコードを持っていた場合

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

Visibleがfalseに設定された場合、Render()は呼び出されないため、この方法ではコントロールを再度表示することはできません。 Visibleだけを完全に残す限り、あなたは大丈夫です。 – stevemegson

+1

うん、それは本当に賢いです!可視プロパティを他の用途に利用できるようにします。私の解決策よりも良い! –

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メソッドとEventメソッドで他のコントロールによって追加されます。このステップをOnInitに入れると、私は決してメッセージを表示しません。 –

+0

わかりました、私はちょうどあなたのイベントを発生させるコントロールプロパティをハッキングするのは難しいかもしれないと思います。 –

5

を、私は実際に自分自身をこれを考え出した、と私は答えはコミュニティに有用であろうと思いました。

Control.Visibleがfalseに設定されているコントロールのように見えますが、実際にはPage_Loadイベントの後にいつか停止します。ここでのトリックは、Control.VisibleプロパティがViewStateにロードされることです。したがって、最初のページヒットにメッセージがない場合、コントロールはVisible = falseに設定され、再びCreateChildControlsまたはOnPreRenderに到達しません。

解決策は、スキップされなかった以前のイベントの1つでコントロールの可視性をリセットすることです。次の変更は、私の問題を解決しました:

protected override void OnLoad(EventArgs e) 
{ 
--> this.Visible = true; 
    this.Controls.Clear(); 
    base.OnLoad(e); 
} 
+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; 
} 

これは、コントロールの親(または他の祖先)が見えない可能性も扱います。この場合、コントロールのOnPreRenderは、コントロール自体にVisible = trueを設定しても発生しません。

+0

うーん、それはうまくいくだろう。興味深いアプローチ。 –

関連する問題