In my previous article I wrote about an importance of handling different message types properly. In this article we'll create a simple ASP.NET user control and apply CSS styles shown in previous article.
Let me explain why we need a user control. If you want every aspx page to support same notification logic, you will need a same functionality on each page. Thus, a user control emerges as logic solution. This can be placed on each aspx page or on a Master Page if you use it. This way you can render any information or an error in the same manner on any place in your application. You can, for example, use this control to show your error messages.
Let's see what functionalities we want to implement:
- We want our control to render four different message types (described in previous article). Thus we'll need a way to inform our control which CSS class to implement
- We need the ability to pass the text to be displayed
- At the end, we want to have a close button on our control to enable a user to hide the message after reading. Beside this, we have to provide the developers with the ability to choose wether to show close button or not.
To do this, we'll create a new user control and apply the design that supports the requests above:
<div class="container">
<asp:Panel ID="MessageBox" runat="server">
<asp:HyperLink runat="server" id="CloseButton" >
<asp:Image runat="server" ImageUrl="~/images/close.png"
AlternateText="Click here to close this message" />
</asp:HyperLink>
<p>
<asp:Literal ID="litMessage" runat="server"></asp:Literal></p>
</asp:Panel>
</div>
And CSS classes that style this control:
body{
font-family:Arial, Helvetica, sans-serif;
font-size:13px;
}
.info, .success, .warning, .error, .validation {
border: 1px solid;
margin: 10px 0px;
background-repeat: no-repeat;
background-position: 10px center;
}
.info {
color: #00529B;
background-color: #BDE5F8;
background-image: url('images/info.png');
}
.success {
color: #4F8A10;
background-color: #DFF2BF;
background-image:url('images/success.png');
}
.warning {
color: #9F6000;
background-color: #FEEFB3;
background-image: url('images/warning.png');
}
.error {
color: #D8000C;
background-color: #FFBABA;
background-image: url('images/error.png');
}
.container
{
}
.info p, .success p, .warning p, .error p {
padding: 0px 50px;
}
.info a, .success a, .warning a, .error a {
float: right;
padding: 10px;
cursor:pointer;
}
.container img {
border: none;
}
We have one DIV that implements class "container". It will act as a most outer container. I left that class blank but you can apply some styles here, e.g. width. Next, we'll have one Panel control that will be accessible from the server, one Literal control that will render a message and one HyperLink with an Image that will be our Close button. That's our design.
Let's see what is happening in the code behind of our user control.
We'll have one boolean property that will indicate wether to render Close button or not.
public bool ShowCloseButton { get; set; }
Next, we'll declare an Enum that will hold our four different message types:
public enum MessageType
{
Error = 1,
Info = 2,
Success = 3,
Warning = 4
}
Now, we need a method that will show the panel with the message and apply correct class.
public void Show(MessageType messageType, string message)
{
CloseButton.Visible = ShowCloseButton;
litMessage.Text = message;
switch (messageType)
{
case MessageType.Error:
MessageBox.CssClass = "error";
break;
case MessageType.Info:
MessageBox.CssClass = "info";
break;
case MessageType.Success:
MessageBox.CssClass = "success";
break;
case MessageType.Warning:
MessageBox.CssClass = "warning";
break;
}
this.Visible = true;
}
This method do a few things:
- It will show/hide Close button according to our ShowCloseButton property.
- It will apply a message to a Literal
- It will apply a CSS class based on MessageType Enum
Let me explain a few things here. First, I chose Literal instead of Label control, because Label is rendered in SPAN element and Literal to pure text.
Next, our Close button will be a HyperLink because it has to be accessible from the server. You are probably asking yourself why. There are two reasons for this. First, close button will have to be displayed ONLY if our ShowCloseButton property is set to true. If so, we have to attach "onclick" event handler to a HyperLink and pass it a ClientID of our Panel control. Why this?
There is a difference between an ID and a ClientID. Each server control will have a ClientID different form ID you gave it. ClientID consists of a control ID and all parent control's IDs. This is how JavaScript see our control. And if we want to find it on the client we'll search for a ClientID. ClientID typically looks like: ParentControl1ID_ParentControl2ID_ControlID.
If this isn't simple enough let me explain it this way - if we have more than one MessageBox panel on a page, document.getElementById won't find the right one if we try to get this element with its ID. You have to provide a full client name with all parent controls.
protected void Page_Load(object sender, EventArgs e)
{
if (ShowCloseButton)
CloseButton.Attributes.Add("onclick", "document.getElementById('" +
MessageBox.ClientID + "').style.display = 'none'");
}
That's why we'll attach onclick event handler on the server.
This will work, but I am not satisfied with that large "switch" block in our Show method. We can optimize this a little. Since our class names and Enum items are the same, we can replace a complete "switch" block with a single line of code:
public void Show(MessageType messageType, string message)
{
CloseButton.Visible = ShowCloseButton;
litMessage.Text = message;
MessageBox.CssClass = messageType.ToString().ToLower();
this.Visible = true;
}
This line will read the NAME of Enum item that we passed to our Show method and assign it to MessageBox panel as a CSS class.
What else can we do? We can create four wrapper methods to make it easier for developers:
public void ShowError(string message)
{
Show(MessageType.Error, message);
}
public void ShowInfo(string message)
{
Show(MessageType.Info, message);
}
public void ShowSuccess(string message)
{
Show(MessageType.Success, message);
}
public void ShowWarning(string message)
{
Show(MessageType.Warning, message);
}
This isn't required, but I prefer to have more choices during development. So the final code will look like this
public partial class MyMessageBox : System.Web.UI.UserControl
{
#region Properties
public bool ShowCloseButton { get; set; }
#endregion
#region Load
protected void Page_Load(object sender, EventArgs e)
{
if (ShowCloseButton)
CloseButton.Attributes.Add("onclick", "document.getElementById('" +
MessageBox.ClientID + "').style.display = 'none'");
}
#endregion
#region Wrapper methods
public void ShowError(string message)
{
Show(MessageType.Error, message);
}
public void ShowInfo(string message)
{
Show(MessageType.Info, message);
}
public void ShowSuccess(string message)
{
Show(MessageType.Success, message);
}
public void ShowWarning(string message)
{
Show(MessageType.Warning, message);
}
#endregion
#region Show control
public void Show(MessageType messageType, string message)
{
CloseButton.Visible = ShowCloseButton;
litMessage.Text = message;
MessageBox.CssClass = messageType.ToString().ToLower();
this.Visible = true;
}
#endregion
#region Enum
public enum MessageType
{
Error = 1,
Info = 2,
Success = 3,
Warning = 4
}
#endregion
}
Now, let's see how our user control can be shown on a pages:
<uc1:MyMessageBox ID="MyMessageBox1" runat="server" ShowCloseButton="true" />
<uc1:MyMessageBox ID="MyMessageBox2" runat="server" ShowCloseButton="false" />
<uc1:MyMessageBox ID="MyMessageBox3" runat="server" ShowCloseButton="true" />
<uc1:MyMessageBox ID="MyMessageBox4" runat="server" />
You can just drag&drop a control on a form and set (or omit) ShowCloseButton property. In a code behind, you can show this control in many ways:
MyMessageBox1.ShowInfo("This is an information. This MessageBox works!");
MyMessageBox2.Show(MyMessageBox.MessageType.Success, "Your profile has been changed");
MyMessageBox3.ShowError("This is an error message");
MyMessageBox4.ShowWarning("This is a warning!");
Conclusion
You saw how to create ASP.NET user control that can handle different message types. You also saw how to implement a Close button on a server control.
If you want to try this you can download a sample code shown in this article.
I am aware that this code isn't perfect, although it did a great job for me on several projects. Did you ever need or do something similar? Do you have any other ideas how this could be implemented? Share it!