7
\$\begingroup\$

We have a hidden div in a master page. When we want to display a message, we send a function a message to display, and it turns that div from .Visible false to .Visible true, and fills the div with the message. For all intents and purposes, this works and we haven't really had much trouble with it. I just feel that there must be a more "standard" way of doing this. There are two downsides, which I'll detail at the end, but neither is site-breakingly critical.

ControlHelper.cs

public static void DisplayNotificationMessage(MasterPage master, List<string> errormessages, string title, MessageBoxImages imgtype)
{
    if (master.FindControl("divmsgpanel") != null)
    {
        master.FindControl("divmsgpanel").Visible = true;
    }

    if (master.FindControl("divdimmer") != null)
    {
        master.FindControl("divdimmer").Visible = true;
    }


    Label titlelabel = (Label)master.FindControl("lblmsgpaneltitle");

    if (titlelabel != null)
    {
        titlelabel.Text = title;
    }

    TextBox thetxtbox = (TextBox)master.FindControl("txtboxmsgcontents");

    if (thetxtbox != null)
    {
        thetxtbox.Text = String.Empty;
        foreach (string x in errormessages)
        {
            thetxtbox.Text += x + "\n\n";
        }
    }

    Image icon = (Image)master.FindControl("imgmessageicon");

    switch (imgtype)
    {
        case MessageBoxImages.Info:
            icon.ImageUrl = "~/images/icons/ico-msginfo96x96.png";
            break;
        case MessageBoxImages.Warning:
            icon.ImageUrl = "~/images/icons/ico-msgwarning96x96.png";
            break;
        case MessageBoxImages.Error:
            icon.ImageUrl = "~/images/icons/ico-msgerror96x96.png";
            break;
        default:
            icon.ImageUrl = "~/images/icons/ico-msginfo96x96.png";
            break;
    }
}

divdimmer is what we use to make the "background" go dark, so that the error message sticks out to the user. Here is a cropped screenshot of the final product:

message

As you can see, the "content" of the site (the page the user interacts with) goes dark, and the notification message appears.

In the master page, the following code-behind method "closes" the message box:

protected void btnmsgcloser_Click(object sender, EventArgs e)
{
    divmsgpanel.Visible = false;
    divdimmer.Visible = false;
}

And then in each content page, we can call the method to display the message box with dynamic content very easily:

public void Save()
{
    List<string> errormessages = ValidateInput();

    if (errormessages.Count == 0)
    {
        //no error, do work
    }
    else
    {
        ControlHelper.DisplayNotificationMessage(Master.Master, errormessages, "Failure", MessageBoxImages.Error);
    }
}

As I mentioned, there's a downside. One of the design requirements was for, upon successful submission of a page, to re-direct to some other page AND show a "success" message.

For example, we have a page with a calendar (calendar.aspx), and a page for event creation (addevent.aspx). The idea is that when you submit something via addevent.aspx, that you get re-directed to calendar.aspx, and you see a message like "Event creation successful!"

The only way I can figure out how to make both re-direct AND display a message is to use a query string. So for example, at the end of the event creation in addevent.aspx, we have:

Response.Redirect("calendar.aspx?createsuccess=true");

Then in the code-behind for calendar.aspx, on Page_Load, we check for a querystring and display the appropriate message:

protected void Page_Load(object sender, EventArgs e)
{
    if (Request.QueryString["deletesuccess"] == "true")
    {
        List<string> successmessage = new List<string>();
        successmessage.Add("The event has been deleted.");
        ControlHelper.DisplayNotificationMessage(Master.Master, successmessage, "Success", MessageBoxImages.Info);
    }
    else if (Request.QueryString["editsuccess"] == "true")
    {
        List<string> successmessage = new List<string>();
        successmessage.Add("The event has been edited.");
        ControlHelper.DisplayNotificationMessage(Master.Master, successmessage, "Success", MessageBoxImages.Info);
    }
    else if (Request.QueryString["createsuccess"] == "true")
    {
        List<string> successmessage = new List<string>();
        successmessage.Add("The event has been created.");
        ControlHelper.DisplayNotificationMessage(Master.Master, successmessage, "Success", MessageBoxImages.Info);
    }
}

Once again, this works. But it has two downsides:

1) it splits the related code between two locations (we send the code from addevent.aspx and then pick it up via query string in calendar.aspx)

2) as the querystring is part of the URL, if the page is re-loaded, each time it will display the same message. For example, let's say we have a user who does the following:

  • visits calendar.aspx
  • clicks the "Add Event" button and is re-directed to addevent.aspx
  • submits a new event in addevent.aspx
  • is re-directed back to calendar.aspx?createsuccess=true
  • user thinks, "hey this is pretty handy, I'll bookmark this page."
  • they've just bookmarked "calendar.aspx?createsuccess=true", and therefore every time they open the bookmark, they're going to get a "The event has been created." message.

I would list our requirements/needs/goals, but we're actually pretty flexible, as long as we can avoid a spaghetti code monster. We previously messed around with jquery. I was probably doing something wrong, but I didn't find it easy to pass a message/alert box dynamic content from the code-behind. I vaguely remember getting something up and running at the beginning of the project, but it was a huge mess between hidden elements in the .aspx page, code-behind, and javascript. It seemed overly verbose and not very easy to maintain, which is what led us to create our own solution (detailed above), in which we have one central method called throughout the entire site.

\$\endgroup\$
5
\$\begingroup\$

Not actually 100% sure if this will work for you but could you use Session variables to achieve what you are after?

    public sealed class MessageInfo
    {
        private readonly string title;

        private readonly string text;

        public MessageInfo(string title, string text)
        {
            this.title = title;
            this.text = text;
        }

        public string Title
        {
            get
            {
                return this.title;
            }
        }

        public string Text
        {
            get
            {
                return this.text;
            }
        }
    }

    public sealed class MessageBox
    {
        private readonly Page parent;

        public MessageBox(Page parent)
        {
            if (parent == null)
            {
                throw new ArgumentNullException("parent");
            }

            this.parent = parent;
        }

        private MessageInfo Message
        {
            get
            {
                return this.parent.Session["MessageBox"] as MessageInfo;
            }

            set
            {
                this.parent.Session["MessageBox"] = value;
            }
        }

        public void NextMessage(string title, string message)
        {
            NextMessage(new MessageInfo(title, message));
        }

        public void NextMessage(MessageInfo msgInfo)
        {
            Message = msgInfo;
        }

        private void Clear()
        {
            NextMessage(null);
        }

        public bool CanShow()
        {
            return !string.IsNullOrEmpty(Message.Text);
        }

        public void Show()
        {
            if (!CanShow())
            {
                return; // do nothing or perhaps throw exception?
            }

            ControlHelper.DisplayNotificationMessage(this.parent.Master.Master, Message.Text, Message.Title, MessageBoxImages.Info);
        }

        public void ShowOnce()
        {
            Show();

            // clear immediately
            Clear();
        }
    }

and used in your target page like:

protected void Page_Load(object sender, EventArgs e)
{
   var msgBox = new MessageBox(this);
   if(msgBox.CanShow())
   {
      msgBox.ShowOnce();
   }
}

and set from your calling page like:

protected void Deleted(object sender, EventArgs e)
{
   new MessageBox(this).NextMessage("Success", "The event has been deleted");
}
\$\endgroup\$
  • \$\begingroup\$ I certainly hope they stick to your intents :) \$\endgroup\$ – Jesse C. Slicer Sep 10 '12 at 20:15
  • \$\begingroup\$ @JesseC.Slicer yes definitely! Although whether my intent was in a good direction is another question :) \$\endgroup\$ – dreza Sep 10 '12 at 20:44
  • \$\begingroup\$ I've used a similar solution for an MVC site when moving between views on a checkout. Using Session also means that you could have the message persist between pages, until the user has dismissed it. Only downside is situations where Session is not available/not sticky. \$\endgroup\$ – Lazlow Sep 11 '12 at 19:31
  • 1
    \$\begingroup\$ By using the session the user cannot use this particular page in two tabs in parallel. This is an indicator of session misuse. \$\endgroup\$ – usr Sep 13 '12 at 18:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.