Today's tip is more than a tip. It's a full project which contains a sample of a control I call the MessageCenter. When developing interactive applications, it's important to provide the user convenient feedback in a consistent location. In my current application I am working on, there are three types of messages (which are typical for most applications) -- errors, informational messages, and warnings.
I wanted to make sure each one appeared different enough so the user could quickly determine which ones needed the most attention. There are a lot of ways I could have accomplished this, such as a class/collection which maintained the type of message, and each class has it's own CSS for displaying. However, I opted for a siumpler solution which is available to every ASP.Net page -- The Validators collection (part of the page object).
The Validators collection maintains a list of objects which implement the IValidator interface. This collection is automatically bound to the ValidationSummary control on the page before (for client-side validation) and after a postback. During a postback for example, you can add a new error to the Page.Validators collection by calling the Add method, and supply a class which implements the IValidator interface.
In the sample project, I implemented three classes -- ValidationError, ValidationNotification and ValidationWarning -- to specify my three different types of messages. Each implements the IValidator interface essentially the same way. I can use the ErrorMessage property of the interface to display the message I want to convey to the end user.
In my page base class, I implemented members to easily add these messages to the Page.Validators collection, as shown below:
public void DisplayError(string message)
{
this.Validators.Add(new ValidationError(message));
}
public void DisplayError(string message, params string[] p)
{
DisplayError(String.Format(message, p));
}
public void DisplayMessage(string message)
{
this.Validators.Add(new NotificationValidator(message));
} Note in some of the methods, I can pass in a list of parameters, so I can format the message displayed with a variety of details.
The MessageCenter.ascx control is where the work is done. When added to a page, it provides a ValidationSummary control to handle the clientside validation, and a Repeater which handles the postback messages. With some work, you could integrate the two, but that is way beyond what I needed.
During the Page_Load event of the MessageCenter control, I bind the Page.Validators collection to the Repeater. I also remove these from Page.Validators collection afterwards, as I don't want them displaying in the ValidationSummary control I use for client validation.
protected void Page_Load(object sender, EventArgs e)
{
rptNotification.DataSource = this.Page.Validators;
rptNotification.DataBind();
rptNotification.Visible = (this.Page.Validators.Count != 0);
for (int idx = (this.Page.Validators.Count - 1); idx >= 0; idx--)
{
IValidator val = this.Page.Validators[idx];
this.Page.Validators.Remove(val);
}
}During the ItemDataBound event of the repeater, I determine the type of IValidator, and set the appropriate image to the row of data. I bind the IValidator class ErrorMessage property to the label inside the repeater row as well, and set the appropriate CSS class so it displays in the color format I like.
protected void rptNotification_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
try
{
if ((e.Item.ItemType == ListItemType.Item) || ((e.Item.ItemType == ListItemType.AlternatingItem)))
{
IValidator val = Page.Validators[e.Item.ItemIndex];
Image img = (Image)e.Item.FindControl("imgNotice");
if (img != null)
{
if (val is NotificationValidator)
img.ImageUrl = "~/images/info.png";
if (val is ValidationError)
img.ImageUrl = "~/images/error.png";
if (val is ValidationWarning)
img.ImageUrl = "~/images/warning.png";
}
Label lblInfo = (Label)e.Item.FindControl("lblDetails");
if (lblInfo != null)
{
lblInfo.Text = val.ErrorMessage;
if (val is NotificationValidator)
lblInfo.CssClass = "NotificationItem";
if (val is ValidationError)
lblInfo.CssClass = "ErrorItem";
if (val is ValidationWarning)
lblInfo.CssClass = "WarningItem";
}
}
}
catch (Exception ex)
{
//TODO: Log the error
}
}
}
The end result is a control which sits on top of the page (and is only visible when there are messages to display) and looks like this:
Notification[1].zip (38.27 KB)UPDATE: Had a bug in the original file, so I updated the project (and cleaned out all the ancillary junk in it as well) and posted it again.