Emulating ShowDialog functionality
I am writing an application (c# + wpf) where all modal style dialogs are implemen开发者_运维百科ted 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?
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.
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..
精彩评论