19

...and it makes no sense why. T-T

In my Application_Startup event handler I have code that looks kinda like this:

private void Application_Startup(object sender, StartupEventArgs e)
{
    string errorMessage;

    if(CheckStartUpConditions(out errorMessage))
    {
        (new MainWindow()).Show();
    }
    else
    {
        MessageBox.Show(errorMessage, "Application Startup", 
            MessageBoxButton.OK, MessageBoxImage.Error);

        Shutdown();
    }
}

private bool CheckStartUpConditions(out string errorMessage)
{
    errorMessage = string.Empty;  

    if(...)
        errorMessage += "Please login to xxx. ";

    if(...)
        errorMessage += "Please install xxx.";

    if(string.IsNullOrEmpty(errorMessage))
        return true;
    else
        return false;
}

The message box makes an brief appearance for like a second before going "POOF!" It doesn't wait for me to click "OK" or on the "X" button. I'm really stumped as to why this is occuring, so any help would be greatly appreciated.

I've tried commenting out the call to Shutdown just for kicks and giggles, and it still behaves the same way.

Also, the application also has a SplashScreen, so I don't know if that's effecting this.

EDIT: I added more code if that helps. The message box is showing the correct error message. Just won't stay long enough for the users to read it. >:(

EDIT PART 2: Okay...I think I've found the culprit. :( I changed the build action on the image I'm using as my splash from SplashScreen to None and the message box will now stay and wait for user input. I don't understand why the SplashScreen is screwing with the MessageBox. >:(

Ashley Grenon
  • 9,305
  • 4
  • 41
  • 54
  • I cannot reproduce this issue. I put a MessageBox in this event on a test application and it stays on the screen until I close it. Can you create a new test application on your machine and try it there? Maybe it is something specific to your setup or your project. Doing it on a new application would tell us if it were your Visual Studio or machine versus your application itself. – IAmTimCorey May 07 '11 at 18:50
  • Did you use a splashscreen in your test app? Thanks!!! – Ashley Grenon May 07 '11 at 19:02
  • 2
    I'll bet that your problem is that the WPF framework thinks your splashscreen is the main form and closes the app when it closes. But I don't know anything about WPF and so can't advise how to investigate! – David Heffernan May 07 '11 at 19:05
  • Okay, I just made a dummy app with a splash screen it causes the message box to go poof. :( – Ashley Grenon May 07 '11 at 19:05
  • @David - The app doesn't close, just the message box. :( I guess I have do some more research into the SplashScreen. >__> – Ashley Grenon May 07 '11 at 19:06
  • Is you splash screen still displayed on the screen when MessageBox gets displayed? Try to use an overload that accepts `IWin32Window` parameter and pass `Null` value to make your MessageBox a top-level window of your application, which is independend of all other windows that may exist. – Alexey Ivanov May 07 '11 at 19:09
  • 1
    Found a few workaround here: http://connect.microsoft.com/VisualStudio/feedback/details/600197/wpf-splash-screen-dismisses-dialog-box I'll see which one gives me the best of luck. (EDIT - they all seem like hacks though :( ) – Ashley Grenon May 07 '11 at 19:09
  • @Alexey - yeah for the latter part of the time, it's like they both disappear at the same time. – Ashley Grenon May 07 '11 at 19:11
  • @townsean And that makes sense. I guess your MessageBox gets owned by splashscreen form. When splashscreen is closed, the framework closes the MessageBox. So making your MessageBox ownerless should do the trick. (I'm not proficient in .net, only in native Win32.) – Alexey Ivanov May 07 '11 at 19:16
  • @Alexey - After reading up on the Window.Owner property that makes a lot of sense. I found out there's an overload to the show method that allows me to specify the owner. Thanks!!! :) – Ashley Grenon May 07 '11 at 19:26
  • Now, I was thinking...in the hack where I call two identical MessageBoxes and the first closes, but the second stays open who is the window owner? In my application there's no other window created yet. So, I was just curious. – Ashley Grenon May 07 '11 at 19:50
  • @townsean You can use Spyxx utility from Visual Studio to find that out. It will show you the owner. (This utility is not .net specific but it is very helpful if you try to understand window hierarchy.) – Alexey Ivanov May 07 '11 at 19:54

7 Answers7

29

The message box vanishes immediately because it has no owner. If you specify the option MessageBoxOptions.DefaultDesktopOnly, the desktop will be assigned as the owner, and the message box will work correctly on an application with no main window.

MessageBox.Show(
    "Message", 
    "Title",
    MessageBoxButton.YesNoCancel, 
    MessageBoxImage.Question, 
    MessageBoxResult.Cancel,
    MessageBoxOptions.DefaultDesktopOnly);
Russell Phillips
  • 777
  • 6
  • 11
13

Based on Alexey Ivanov's suggestion, I successfully used a new window as the parent

System.Windows.Forms.MessageBox.Show(new System.Windows.Forms.NativeWindow(), errorMessage, "Application Startup", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
Neil
  • 3,899
  • 1
  • 29
  • 25
  • 1
    So just use the WinForms messagebox instead of the WPF one. This worked for me, where I was experiencing an issue due to a tray application not having a main form. It should be noted that this adds a new dependency that a WPF application would not normally have. – denver Mar 05 '15 at 18:08
  • This is the best answer. I had the EXACT issue as the OP. Strangely the SplashScreen was interfering with the behavior of the message box. – markokstate Jul 12 '16 at 13:18
  • With a WPF MessageBox this trick with `new Window()` doesn't work. – Beauty May 04 '21 at 12:18
7

Try to use an overload that accepts System.Windows.Window parameter and pass Null value to make your MessageBox a top-level window of your application, which is independent of all other windows that may exist. I guess your MessageBox gets owned by splashscreen form. When splashscreen is closed, the framework closes the MessageBox. So making your MessageBox ownerless should do the trick.

Michi-2142
  • 1,170
  • 3
  • 18
  • 39
Alexey Ivanov
  • 11,541
  • 4
  • 39
  • 68
  • 2
    The overload that provides a window owner doesn't allow me to pass in null, but this answer explains what's causing my woes. :) – Ashley Grenon May 07 '11 at 20:06
  • @townsean I think you can create a class which implements IWin32Window interface and return `null` as the value of `Handle` property. Hope it helps. – Alexey Ivanov May 07 '11 at 20:27
  • I'm having the same problem on Shutdown, I thought the messagebox would hang around until user presses ok and then execute rest of code including Current.Shutdown(); Of course there is no splash screen here so I'm not sure what's going on. – Ingó Vals Aug 21 '12 at 17:28
  • @IngóVals Usually when you call `MessageBox`, it does not exit until user closes it. I don't know how .Net works well, only conceptually, however I know the underlying Win32 API. The answer to your question depends on when you call these methods. I'd suggest you ask a separate question with detailed explanation when you show a MessageBox. – Alexey Ivanov Aug 21 '12 at 19:30
  • The WPF MessageBox.Show takes a Window not an IWin32Window. – denver Mar 05 '15 at 18:17
  • 2
    This answer is wrong, passing null results in an `ArgumentNullException` – epalm Dec 06 '18 at 21:29
  • 1
    Good explanation with the splashscreen. Based on your idea it workes to create a helper window (instead of NULL) for the first parameter. `Window helperWin = new Window() { WindowState = WindowState.Minimized, Title = "..." }; helperWin.Show(); MessageBox.Show(helperWin, "message", "title", MessageBoxButton.OK, MessageBoxImage.Exclamation); helperWin.Close();` Tested with WPF (with Forms I didn't test) ... But the better solution is in Russell's answer with Parameter `MessageBoxOptions.DefaultDesktopOnly`. – Beauty May 04 '21 at 12:19
4

Create transparent hidden window and use it as an owner of the MessageBox:

private Window CreateHiddenWindow()
        {
            var window = new Window
            {
                AllowsTransparency = true,
                Background = System.Windows.Media.Brushes.Transparent,
                WindowStyle = WindowStyle.None,
                Top = 0,
                Left = 0,
                Width = 1,
                Height = 1,
                ShowInTaskbar = false
            };

            window.Show();

            return window;
        }
andrey.tsykunov
  • 2,896
  • 2
  • 32
  • 21
3

You can keep your splash screen and use a standard WPF MessageBox if you implement the splash screen in code instead of as an image build action.

App.xaml.cs:

var splashScreen = new SplashScreen("path/to/splash_image.bmp");
splashScreen.Show(false); //make sure to use 'false' here to prevent auto-closing

string errorMessage;

if(CheckStartUpConditions(out errorMessage))
{
    (new MainWindow()).Show();
}
else
{
    //standard WPF MessageBox may now be used here
    MessageBox.Show(errorMessage, "Application Startup", 
        MessageBoxButton.OK, MessageBoxImage.Error);

    Shutdown();
}

//explicitly close the splash screen now
splashScreen.Close(TimeSpan.FromSeconds(1));
HotN
  • 4,216
  • 3
  • 40
  • 51
1

Alexey is right, the splash screen closes the message box.

A simple way to avoid this is to use the native MessageBox function:

[DllImport("user32.dll", CharSet = CharSet.Unicode)]
public static extern int MessageBox(IntPtr hWnd, String text, String caption, uint type);

public static void Main()
{
   ...
   MessageBox(new IntPtr(0), "Hello World!", "MyApp", 0);
Andreas Kahler
  • 2,283
  • 1
  • 17
  • 17
0

You need to tell WPF not to shutdown when the first window does. Look at this: http://msdn.microsoft.com/en-us/library/system.windows.application.shutdownmode.aspx. You want to set your application to shutdown explicitly (instead of after the first window closes):

<Application
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    StartupUri="MainWindow.xaml"
    ShutdownMode="OnExplicitShutdown">
</Application>

Your other choose is to set your MainWindow as the StartupUri (instead of your splash screen) and then load your splash screen in the MainWindow's loaded event. Then you would do whatever loading or time intensive stuff you need to do, hide your splash screen, and re-show your main Window.

Matt West
  • 2,874
  • 1
  • 19
  • 13