Guy
Guy

Reputation: 3381

Emulating ShowDialog functionality

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?

Upvotes: 5

Views: 3703

Answers (4)

Cameron MacFarland
Cameron MacFarland

Reputation: 71946

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);

Upvotes: 6

Mongus Pong
Mongus Pong

Reputation: 11477

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..

Upvotes: 1

Chris Shouts
Chris Shouts

Reputation: 5437

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.

Upvotes: 5

SLaks
SLaks

Reputation: 888203

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.

Upvotes: 0

Related Questions