The message box, in Windows Forms and WPF, is a useful, quick-and-dirty way to send an alert, display an error, and get simple input from the user. The message box is, however, modal.
Recently, I needed to use a message box in WPF but did not want to block the calling thread. The usual searches pointed to creating a message box-like window and calling Show, which returns immediately and allows the calling thread to continue. There is so much built into the message box, though, such as standard icons (information, warning, and error), standard Windows sounds, internationalization of the buttons, and message formatting, that replicating it robustly seemed difficult.
Instead of creating a new window, I used the BeginInvoke method of the delegate type to display the standard message box. For more information on asynchronous programming with the BeginInvoke see this article. In the example code below, MessageBox.Show is wrapped in a method that is run on a separate thread.
private delegate void ShowMessageBoxDelegate(string strMessage, string strCaption, MessageBoxButton enmButton, MessageBoxImage enmImage);
// Method invoked on a separate thread that shows the message box.
private static void ShowMessageBox(string strMessage, string strCaption, MessageBoxButton enmButton, MessageBoxImage enmImage) {
MessageBox.Show(strMessage, strCaption, enmButton, enmImage);
}
// Shows a message box from a separate worker thread.
public static void ShowMessageBoxAsync(string strMessage, string strCaption, MessageBoxButton enmButton, MessageBoxImage enmImage) {
ShowMessageBoxDelegate caller = new ShowMessageBoxDelegate(ShowMessageBox);
caller.BeginInvoke(strMessage, strCaption, enmButton, enmImage, null, null);
}
When the message box was modal, nothing could occur until it was acknowledged. An asynchronous message box does not block the calling thread, so that thread could create many copies of a message box before the first one is acknowledged. This behavior may be acceptable...no, probably not. However, the programmer may know this would never occur.
If repeated message boxes could occur, I found a simple way to prevent them until the first message box is acknowledged. The BeginInvoke method returns an object of the IAsyncResult type. This interface provides an IsCompleted property that will be set true once the asynchronous operation is completed.
To block repeated asynchronous message boxes, pass by reference a member IAsyncResult variable to the method shown below. This method will only show a new message box once the first one has been closed.
// Shows a message box from a separate worker thread. The specified asynchronous
// result object allows the caller to monitor whether the message box has been
// closed. This is useful for showing only one message box at a time.
public static void ShowMessageBoxAsync(string strMessage, string strCaption, MessageBoxButton enmButton, MessageBoxImage enmImage, ref IAsyncResult asyncResult) {
if ((asyncResult == null) || asyncResult.IsCompleted) {
ShowMessageBoxDelegate caller = new ShowMessageBoxDelegate(ShowMessageBox);
asyncResult = caller.BeginInvoke(strMessage, strCaption, enmButton, enmImage, null, null);
}
}
Download a sample Visual Studio 2008 solution that shows the methods above and how they might be called in an application. Hope you've found this solution useful and I would appreciate any improvements you might make. Thanks.
Download
Learn more about DMC's software and web development services.