Question

I am writing an application (c# + wpf) where all modal style dialogs are implemented as a UserControl on top of a translucent grid covering the main Window. This means there is only one Window and it maintains the look and feel of all the firms applications.

To show a MessageBox, the syntax is as following:

CustomMessageBox b = new CustomMessageBox("hello world");
c.DialogClosed += ()=>
{
   // the rest of the function
}
// this raises an event listened for by the main window view model,
// displaying the message box and greying out the rest of the program.
base.ShowMessageBox(b); 

As you can see, not only is the flow of execution actually inverted, but its horribly verbose compared to the classic .NET version:

MessageBox.Show("hello world");
// the rest of the function

What I am really looking for is a way to not return from base.ShowMessageBox until the dialog closed event has been raised by it, but I cant see how it is possible to wait for this without hanging the GUI thread and thus preventing the user ever clicking OK. I am aware I can take a delegate function as a parameter to the ShowMessageBox function which kind of prevents the inversion of execution, but still causes some crazy syntax/indenting.

Am I missing something obvious or is there a standard way to do this?

Was it helpful?

Solution

You might want to take a look at this article on CodeProject and this article on MSDN. The first article walks you through manually creating a blocking modal dialog, and the second article illustrates how to create custom dialogs.

OTHER TIPS

The way to do this is by using a DispatcherFrame object.

var frame = new DispatcherFrame();
CustomMessageBox b = new CustomMessageBox("hello world");
c.DialogClosed += ()=>
{
    frame.Continue = false; // stops the frame
}
// this raises an event listened for by the main window view model,
// displaying the message box and greying out the rest of the program.
base.ShowMessageBox(b);

// This will "block" execution of the current dispatcher frame
// and run our frame until the dialog is closed.
Dispatcher.PushFrame(frame);

You could make your function into an iterator that returns an IEnumerator<CustomMessageBox>, then write it like this:

//some code
yield return new CustomMessageBox("hello world");
//some more code

You would then write a wrapper function that takes the enumerator and calls MoveNext (which will execute all of the function until the next yield return) in the DialogClosed handlers.

Note that the wrapper function would not be a blocking call.

Set up another message loop in the message box class. Something like :

public DialogResult ShowModal()
{
  this.Show();

  while (!this.isDisposed)
  {
    Application.DoEvents();
  } 

   return dialogResult;
}

If you look at Windows.Form in Reflector you will see it does something like this..

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top