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();
}
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With