It doesn't make a lot of sense that the WinForms message box function isn't working in a WPF application. After all, both APIs call the native Win32 MessageBox function.
The issue might be related to the code in the System.Windows.Forms.MessageBox implementation that attempts to disable all of the windows in preparation for displaying a modal dialog. That might not be interacting properly with some of the WPF plumbing, producing some strange behavior. Speculation, of course; I'm not an expert on WPF.
I did, however, peruse the System.Windows.MessageBox implementation in the reference source, and couldn't help but notice that it omits the code that the WinForms implementation has for disabling other windows. It just calls the Win32 MessageBox function directly, which is what I would have done in either case. I'm sure the WinForms team has a good reason for their decision, I just don't know what it is.
So what to do? Like everyone else, my first inclination would be to tell you to use the MessageBox function specifically designed for use in WPF applications. But like you said, it doesn't support the Retry or Cancel buttons. There's no good reason why not, the WPF team just doesn't appear to have exposed access to this functionality. Maybe the UI folks at Microsoft are trying to discourage use of Retry and Cancel buttons? Anyway, you can get what you want by P/Invoking the Win32 MessageBox function:
private const int MB_RETRYCANCEL = 0x00000005L;
private const int IDCANCEL = 2;
private const int IDRETRY = 4;
private const int MB_DEFBUTTON1 = 0x00000000;
private const int MB_DEFBUTTON2 = 0x00000100;
private const int MB_ICONERROR = 0x00000010;
private const int MB_ICONWARNING = 0x00000030;
private const int MB_ICONINFORMATION = 0x00000040;
[DllImport("user32.dll", CharSet=CharSet.Auto)]
public static extern int MessageBox(HandleRef hWnd,
string text,
string caption,
int type);
and calling it yourself, directly:
switch (MessageBox(new HandleRef(null, owner), // your owner window
"My Message Text", // your message
"Message", // the dialog box title/caption
MB_RETRYCANCEL | MB_ICONERROR | MB_DEFBUTTON1))
{
case IDRETRY:
{
// ...
}
case IDCANCEL:
{
// ...
}
default:
{
throw new NotSupportedException("MessageBox is displayed only with Retry and Cancel buttons; any other response is not supported and should be impossible.");
}
}
result
will be either IDRETRY
or IDCANCEL
. You can specify whatever icon you want, or omit it to have no icon. And MB_DEFBUTTON1
specifies that the Retry button is the default. Use MB_DEFBUTTON2
to make the Cancel button the default.
But really, you should be using the TaskDialog, not a MessageBox. I figured WPF would have a wrapper for this, but a web search indicates it does not. The Windows API Code Pack does, obsoleted or not.