控制生命周期中的什么时候Control.Visible停止渲染?

时间:2009-10-21 01:54:30

标签: c# asp.net

我正在尝试编写一个简单的实用程序webcontrol来显示网页内的单行消息 - 状态更新,错误消息等。通过调用webcontrol上的方法,消息将来自页面上的其他控件。如果控件在预渲染时没有任何消息,我不希望它在页面上呈现 - 我希望它设置Control.Visible = false。这似乎只适用于非回发渲染。这是我正在使用的代码:

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中,结果相同。

4 个答案:

答案 0 :(得分: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);
}

答案 1 :(得分:3)

不要修改'Visible'属性,请尝试以下方法:

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

答案 2 :(得分: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也不会触发。

答案 3 :(得分: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()));
        }
    }
}