Click here to Skip to main content
Email Password   helpLost your password?

Introduction

Some applications need a more advanced message box than MessageBox class provided by .NET. This article presents a .NET library called MessageForm that can be used instead of .NET MessageBox getting more features and improvements.

General Features of MessageForm Comparing with MessageBox

Features

MessageForm

MessageBox

can contain any number of buttons

+

-
(provides only up 3 predefined buttons)

text and color of the buttons are specified by parameters

+

-

can display ‘apply-my-answer-by-default’ checkbox so that user can make his/her answer applied by default in the future

+

-

allows selecting and copying message; it is handy thing when you want to get path or error string from message box + -

window's content can be seen independently on its size

+
(MessageForm’s size is always less than the display; if its content is too large then the scroll bar is provided)

-
(if message is too long, it goes out of the screen so that you cannot read it all)

allows setting icon in the window's title bar

+
(by default it displays icon of the hosting application)

-

thread safe

+
(As an option, Message class also provides thread synchronization so that messages of different threads are showed strongly in turn)

+

brings message box to the top of windows on the desktop; it is important feature for alerts + +/-
(if the application showing message box is windowless, the message box can be from the beginnig "lost" under the rest windows on the desktop)

accepts Image type as well as Icon type when setting icon beside message

+

-

can be fitted/enhanced further

+
(open source)

-

Description

The MessageForm library consists of 2 classes:

MessageForm Class

MessageForm class implements the message box window basing on System.Windows.Forms.Form. Usually you do not want to use it because of using Message class instead. On the other hand, MessageForm provides more flexible settings than Message does.

Message Class

The goal of Message is to make use of the advanced message box in your code as simple as possible. It provides a collection of predefined MessageForm instances most frequently used. That means you have usually to work with Message class only. If its predefined methods do not meet your needs, you can use MessageForm directly or enhance Message with your own ones.

Message is a thread-safe class so that you can use it from within several threads with no collision. The Message.ShowMessagesInTurn parameter defines how message boxes will be showed in a multithread environment. If it is true then message boxes are showed one after another. If it is false, Message shows message boxes invoked from different threads, simultaneously (that's like .NET MessageBox does).

The Message class has the following default settings:

These settings are the respective attributes of Message and so can be changed from your code that uses MessageForm or even directly within the MessageForm project. For example, coloration of the buttons can be toggled off by the following code:

//toggle off coloring buttons
Cliver.Message.ButtonColors = null;

Usage of MessageForm

Below are several examples of using Message and MessageForm classes. (More examples you can find in Test project within MessageForm solution.) The respective code follows the image.

Using Message Class

Message box with OK button (XP and Vista style):

1-button.JPG 1-button.JPG

Cliver.Message.Inform("Message.Ok test");

Message box with 2 custom buttons (XP and Vista style):

2-buttons.JPG 2-buttons.JPG

//returns clicked button index
int a = Cliver.Message.Show(SystemIcons.Error, "Connection lost", 0,
    "Try to reconnect", "Exit"); 

Message box with 3 custom buttons and checkbox:

3-buttons.JPG

 //Set message box caption once and forever 
 Cliver.Message.Caption = "Backup Application";

 //returned silent box state 
 bool r;
 //returned clicked button index
 int a;

 //show message box with 3 buttons
 a = Cliver.Message.Show(SystemIcons.Information, out r,
                @"Local file c:\test.txt differs from the backup copy", 0,
                "Backup the newest file",
                "Download the backup copy",
                "Do nothing for now"
                );

What if message box has to display unpredictably long text, for instance, an error stack? Sometimes the message can be so long that a .NET MessageBox will go out of the screen making the end of the message invisible. Here is an example how MessageForm treats such 'unsafe' cases:

scrollbar3.JPG

Using MessageForm Directly

Message box with 6 buttons, checkbox and custom message icon. Notice that MessageForm can accept Image type in place of Icon type.

MessageForm.JPG

How it looks in the classic style on screen with less resolution:

MessageForm2.JPG
Cliver.MessageForm mf = new MessageForm(
    "Using MessageForm directly",//caption
    //message
    "Copying files from: 'c:\\test' to: 'c:\\test2'\nFile 'test.txt' already exists.",
    new Color[6] {
        Color.LightCoral,
        Color.LightYellow,
        Color.Empty,
        Color.LightGreen,
        Color.LightBlue,
        Color.Empty,
    },//button colors
    new string[6] { 
        "Overwrite",
        "Overwrite if older", 
        "Skip", 
        "Rename",
        "Append",
        "Cancel"
    },//array of answers
    1,//default button
    "Apply to all",//silent box text
    new Bitmap("../../copying.jpg")//message icon, can be set from image
);

//set icon in the capture
mf.Icon = new Icon("../../computers308.ico");

//show message form
mf.GetAnswer();

//get state of silent checkbox
bool silent = mf.Silent;

Modifying MessageForm

The MessageForm library is written in pure C#. It builds its own window that's not a wrapper of the MessageBox class. It inherits System.Windows.Forms.Form so you can easily and flexibly modify it as you want by changing its code.

Also be aware that while automatic arranging controls in MessageForm the following values are not changed from their initial values:

Keeping that in your mind, you can tune the look of MessageForm in Visual Studio window design mode.

Also, pay attention to several attributes in the MessageFrom class that defines its layout as well.

Using the Code

In the attached code you can find:

The last version of MessageForm can be found at SourceForge

Be happy!

You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
GeneralFunny... [modified]
93Current
8:33 27 Jul '09  
Hi,

first let me say that this is a great work!

You may ask why I choose this title 'Funny...'. It is because I looked around everywhere, in Code Project and outside. There are some advanced message boxes written but none of them has the simplest 'advanced' public properties you can imagine: to set the BackColor, the ForeColor and other font properties and the BackgroundImage of the whole MessageBox. There are some more complex properties instead. Crazy, isn't it?

Maybe you can make it perfect?!

Regards.
93C.

modified on Monday, July 27, 2009 2:23 PM

GeneralNot working
stann435
1:09 11 Dec '08  
When I put this to the Test.Form1 class in the Test project and click button 3 I get two message boxes shown simultaneously even with Message.ShowMessagesInTurn set to true.

private void button3_Click(object sender, EventArgs e)
{
ThreadStart m = f;
t2 = new Thread(m);
t2.Start();
t = new Thread(m);
t.Start();
}

void f()
{
this.Invoke(new MethodInvoker(
delegate(){
Cliver.Message.Inform((i++).ToString());
}));
}

GeneralRe: Not working
Sergey Stoyan
6:22 13 Dec '08  
Can you trace why you have this problem?
1)be sure ShowMessagesInTurn is not changed in another place of the code;
2)be sure the second box is not produced by direct constructing MessageForm;
GeneralRe: Not working
stan_p
23:15 15 Dec '08  
There is nothing to trace in the test project. I simply create two threads which both shows a message box on the UI thread. It has to do something with how .net framework works with UI thread and the internal working of your MessageForm which i didn't look at.

In other words: The "in turn" functionality doesn't work when non UI threads are showing the message box on the UI thread.

You can easily test it yourself if you download your MessageForm from codeproject and replace the Test.Form1.button3_Click and Test.Form1.f methods in the Test project with methods from my first post. Then run and click button3. You will get two message boxes shown at the same time.
GeneralRe: Not working
Sergey Stoyan
23:53 15 Dec '08  
it is correct. You try to invoke the box from the same thread - so, of course, the lock does not stop creating the second box. The Message was developed for the practical goals and I cannot see why such exercises like yours are needed in the life. If you let me know why, I'll give a darn there.
GeneralRe: Not working
stan_p
19:22 10 Jan '09  
well... sorry but your note about "practical goals and exercises" is just stupid. You can run into the problem with "in turn" functionality not working very easily. A lot of applications have most of their code running on UI thread (in button click events, keypress events etc.), showing message boxes here and there. If you then add e.g a worker thread or timer which is triggering some events on the UI thread, because it needs to access UI, and you show a message dialog in such event (eg some notification to the user "Connection lost", "Work done" or anything), then you can get multiple message dialogs displayed simultaneously. You don't even need a worker thread. All you need is to display a message dialog from an event which is triggered by .net framework automatically, like the Paint event. Even if displaying a message box from paint event would be good only for debugging. Just because you cannot see why something would be needed doesn't mean that a good reason for it doesn't exists. It only means that your imagination is limited.
GeneralNice
ashu fouzdar
4:21 19 Aug '08  
I had found one more on CP. (I guess it was MemoryBox).

But, This one is providing more options.

Really great

dnpro
"Very bad programmer"

GeneralOK, but a nicer solution exists on CP
PSU Steve
4:01 19 Aug '08  
www.codeproject.com/KB/vb/vdialog.aspx is a much better looking custom message box. Pretty sure it offers about the same options.
GeneralRe: OK, but a nicer solution exists on CP
sk8er_boy287
21:55 6 Oct '08  
I like this one better. Poke tongue Remember, diversity is a good thing, so don't try to stop it.
GeneralRe: OK, but a nicer solution exists on CP
Donsw
15:27 26 Jan '09  
this one is good, diversity is good as was pointed out.
GeneralMessage blocks UI thread if called when another thread is already showing a message
supercat9
15:08 25 Jul '08  
If a thread other than the main UI thread pops up one of your message boxes, and then the main UI thread tries to pop up another, the UI thread will block until the message box is acknowledged. I'm not sure the best approach, although one that almost works is to, instead of opening the message box from the main thread (which will block on the lock statement), open up a fake invisible modal dialog box, then have that box use another thread to pop up the message (or wait until it can do so). That thread should invoke 'close' on the fake dialog box, allowing program flow to proceed.

Rather icky; I'm sure there's got to be a better way to keep the message pump going while locking a form's controls. Unfortunately, I don't know what it is.

modified on Saturday, July 26, 2008 12:56 AM

GeneralRe: Message blocks UI thread if called when another thread is already showing a message [modified]
Sergey Stoyan
0:07 26 Jul '08  
The goal of Message class is to show message boxes in turn. What is a sense to show them simultaneously? However, if you need it, you can use directly MessageForm class that has no thread synchronization.

modified on Saturday, July 26, 2008 6:30 AM

GeneralRe: Message blocks UI thread if called when another thread is already showing a message
supercat9
9:48 26 Jul '08  
The issue is that if your message routine is called from a UI thread when another of your message boxes is showing, the locking primitive you use blocks all events on the UI thread. If you're going to try to control the behavior of message boxes that are shown on different threads, it would probably be good to do so in a fashion that works smoothly.

To demonstrate the issue I'm describing, create a form with a checkbox and two buttons. The checkbox is simply to verify that the form is "clickable". One of the buttons should pop up a message box by calling your message routine directly. The other should start a thread which then calls the message routine.

If the first button is clicked, the controls on the form will be disabled while the message box is displayed, but the form will still respond to Windows events (move, paint, etc.). If the second button is clicked, the message box will pop up but the controls on the form will still work "normally" even while the box is displayed (confirm that with the check box). If the first button is clicked while the message box is up, however, the form will stop responding to Windows events until the message box is acknowledged. If you drag the message box over the form, the contents will be erased and not redrawn. Worse, if another thread calls .Invoke on a UI object owned by the blocked thread, the thread too will be blocked.

I wish .net had included a nice way to run a message pump while waiting. Unfortunately, I don't know of any.
GeneralRe: Message blocks UI thread if called when another thread is already showing a message [modified]
Sergey Stoyan
3:22 29 Jul '08  
I was not so lazy to check what you said.
First of all, as it was mentioned in my previous message, you can use directly MessageForm class to avoid frozen UI in your test. See the code below:

CliverSoft.MessageForm mf;
mf = new CliverSoft.MessageForm("", t, null, null, 0, null, (Image)null);
mf.GetAnswer();

You can write your own shortcuts doing what you want.

Now, several thoughts.

Lock ‘primitive’ as you said, was added to Message class for the following purposes:
a) make the static variables in Message class safe;
b) show messages in turn;

There are several ways to overcome freezing the form:

1) Replace lock(lock_v){…} with

while (!System.Threading.Monitor.TryEnter(lock_v))
Application.DoEvents();

System.Threading.Monitor.Exit(lock_v);

In that way we’ll have (a) and (b) saved + any form unfrozen.
This way has the following disadvantage: if some thread of the application launched a message box and then user’s actions on IU have brought to one more message box, it is a good thing when the originating form is blocked because this will direct user’s attention onto the first message and then the second. Else the user will continue clicking on buttons and only put new message boxes to the queue.

2) Surround with locks only these places of the code where static variables are passed into MessageForm. In that way we’ll lose (b) but have the form unfrozen. It will be blocked correctly only when it has launched its message box. That is how .NET MessageBox does.
This way has the following disadvantages: if messages are shown simultaneously, their originate precedence can be easily lost that can bring to misunderstanding of the reason of messages. Also, if a thread launches messages in a error loop then a bunch of them will be displayed at once.

I agree that form frozen by lock in Message looks not good so probably I’ll implement something to make the UI blocked correctly in that case when it wants to launch the message box and waits until the message box launched by the other thread is closed.

modified on Tuesday, July 29, 2008 2:21 PM

GeneralRe: Message blocks UI thread if called when another thread is already showing a message [modified]
Sergey Stoyan
1:46 13 Aug '08  
Advanced message box supports now 2 modes as of the order of showing boxes:
1)if gui wants to show a message, it will be neatly frozen and waiting until previous messages thrown by another threads are closed;
2)messages originated by different threads are shown simultaneously like it is done in .NET MessageBox.
Please see Message.ShowMessagesInTurn flag to switch the mode.

modified on Wednesday, August 13, 2008 7:20 AM

GeneralVery good... a request for future upgrades
angel.escamilla
13:39 1 Apr '08  
Nice job, very helpfull. If possible for a future release to add an bmp or jpg image to the dialog box, that would be very good...

Cheers!

AngelX
GeneralRe: Very good... a request for future upgrades
Sergey Stoyan
21:38 1 Apr '08  
Thank you. I'll think on it. Currently Message accepts icons so you can convert image to icon for now:

Bitmap b = new Bitmap(@"c:\image.jpg");
mf.Icon = Icon.FromHandle(b.GetHicon());
GeneralRe: Very good... a request for future upgrades
The_Mega_ZZTer
6:10 25 Jul '08  
In my apps I tend to always use Images instead of Icons unless I'm going to pass the object to an existing .NET framework construct that takes an Icon, then I usually use Icon. It's easier to convert Icons to Images (Icon has a method for it.. .ToBitmap) and although it works the other way around, the Icon format is supposed to be less flexible (I don't think it can handle over 1-bit transparency, for example 32-bit PNGs).

Since you're just basing it off of a regular Form you can just use an Image instead of an Icon in the PictureBox, there's no lower-level stuff to worry about. On the other hand, if you have an option to set the form icon of the MessageForm, you'd want to make that an Icon-type property, since the lower-level Form.Icon takes an icon (and so does the even lower-level WinAPI that it wraps).

That's how I'd do it, anyway.
GeneralRe: Very good... a request for future upgrades
Sergey Stoyan
23:46 25 Jul '08  
The predefined Windows icons were good enough for me still so I had no need for images. Also I would like to save the succession to MessageBox. Allowing images as a parameter means redoubling the methods exposed by Message - maybe it will be done in the future.
GeneralRe: Very good... a request for future upgrades
Sergey Stoyan
0:37 28 Jul '08  
MessageForm class has now constructor that accepts Image type parameter to set the message icon.
GeneralRe: Very good... a request for future upgrades
angel.escamilla
23:11 20 Feb '09  
Now I can say this is excellent, I've just added the code to my test software, it works beautiful.
Thank you again. Big Grin
GeneralColors
Geno Carman
14:36 25 Mar '08  
Not a bad idea, but the use of colors reminds me of all those ugly VisualBasic programs.
GeneralRe: Colors
Sergey Stoyan
22:23 25 Mar '08  
Use of colors is only an option among the rest.
GeneralVery cool
MaxGuernsey
16:58 24 Mar '08  
The only suggestion I would have is to make the properties that are arrays of answer strings, arrays of colors and whatnot into a single array of Answer objects and then for each Answer object to have all of those properties. That is, obviously, a fairly small thing. It's a pretty cool utility.
GeneralRe: Very cool [modified]
Sergey Stoyan
23:35 24 Mar '08  
Rewarding suggestion. Thank you. I’ll take it to account while doing the next upgrade.

modified on Wednesday, March 26, 2008 3:26 AM


Last Updated 6 Oct 2008 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010