开发者

At what point in the control life cycle does Control.Visible stop rendering?

开发者 https://www.devze.com 2022-12-09 04:28 出处:网络
I am trying to write a simple utility webcontrol to display one-line messages inside a web page - status updates, error messages, etc. The messages will come from other controls on the page, by callin

I am trying to write a simple utility webcontrol to display one-line messages inside a web page - status updates, error messages, etc. The messages will come from other controls on the page, by calling a method on the webcontrol. If the control doesn't have any messages by the time it gets to pre-render, I don't want it to render on the page at all - I want it to set Control.Visible = false. This only seems to work for non-postback rendering though. Here's the code I'm using:

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

 开发者_JAVA技巧   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

}

I tried putting the check inside CreateChildControls too, with the same result.


I actually figured this out myself, and I thought the answer would be useful to the community.

It looks like a control which has Control.Visible set to false actually stops sometime after the Page_Load event. The trick here is that the Control.Visible property is loaded into ViewState. So if there are no messages on the first page hit, then the control sets itself to Visible = false, and never again reaches either CreateChildControls or OnPreRender.

The solution is to reset the control's visibility in one of the earlier events which aren't skipped. The following change solved my problem:

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


Instead of modifying the 'Visible' property, try this :

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


If you had code that must run on PreRender even if the control is invisible (so that setting Visible=true in OnLoad isn't a solution), you could take advantage of the fact that the Page's PreRender event will always fire.

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

This also deals with the possibility that the control's parent (or other ancestor) is invisible. In this case, the control's OnPreRender won't fire even if you ensure that Visible=true on the control itself.


I suggest using OnInit instead:

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

精彩评论

暂无评论...
验证码 换一张
取 消