# Tuesday, August 10, 2010
« Tip of the Day: The evolution of dynamic... | Main | More adventures in hosting - Why I would... »
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.

Comments are closed.