System.Windows.MessageBox在用户输入之前就消失了!

20

...但是它没有任何意义。T-T

在我的Application_Startup事件处理程序中,我有类似这样的代码:

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

消息框出现了一瞬间,然后就消失了。它不等待我点击“确定”或“X”按钮。我真的对为什么会发生这种情况感到困惑,所以非常感谢任何帮助。

我已经尝试注释掉对 Shutdown 的调用,但它仍然表现出相同的方式。

此外,应用程序还有一个 SplashScreen,所以我不知道是否影响了这个问题。

编辑:我添加了更多代码,如果有帮助的话。消息框显示了正确的错误信息,只是不停留足够长的时间供用户阅读。 >:(

第二次编辑:好的...我想我已经找到了罪魁祸首。 :( 我将用作启动画面的图像的构建操作从 SplashScreen 更改为 None,现在消息框将保持并等待用户输入。我不明白为什么 SplashScreen 会影响 MessageBox。 >:(


你在测试应用程序中使用了启动画面吗?谢谢! - Ashley Grenon
2
我敢打赌,你的问题是WPF框架认为你的启动屏幕是主窗体,并在其关闭时关闭了应用程序。但我对WPF一无所知,因此无法建议如何进行调查! - David Heffernan
好的,我刚刚用启动画面制作了一个虚拟应用程序,它导致消息框消失了。:( - Ashley Grenon
@David - 应用程序没有关闭,只是消息框。 :( 我想我需要对启动屏幕进行更多的研究。 >__> - Ashley Grenon
1
在这里找到了一些解决方法:http://connect.microsoft.com/VisualStudio/feedback/details/600197/wpf-splash-screen-dismisses-dialog-box 我会看看哪一个对我最有帮助。(编辑 - 尽管它们都似乎是hack方法 :( ) - Ashley Grenon
显示剩余7条评论
7个回答

30

这个消息框会立即消失,因为它没有所有者。如果您指定选项MessageBoxOptions.DefaultDesktopOnly,则桌面将被分配为所有者,并且消息框将在没有主窗口的应用程序上正常工作。

MessageBox.Show(
    "Message", 
    "Title",
    MessageBoxButton.YesNoCancel, 
    MessageBoxImage.Question, 
    MessageBoxResult.Cancel,
    MessageBoxOptions.DefaultDesktopOnly);

2
这个非常好用。它是所有解决方案中最简单的一个。 - Gábor

14

在Alexey Ivanov的建议下,我成功地使用了一个新窗口作为父窗口

System.Windows.Forms.MessageBox.Show(new System.Windows.Forms.NativeWindow(), errorMessage, "Application Startup", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);

1
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - denver
这是最好的答案。我和 OP 一模一样地遇到了相同的问题。奇怪的是 SplashScreen 干扰了消息框的行为。 - markokstate
使用 WPF MessageBox 时,new Window() 这个技巧不起作用。 - Beauty

7
尝试使用一个接受 System.Windows.Window 参数的重载方法,并传递 Null 值,使您的消息框成为应用程序的顶层窗口,独立于可能存在的所有其他窗口。我猜您的消息框是由启动画面表单拥有的。当启动画面关闭时,框架会关闭消息框。因此,使您的消息框无主人应该可以解决问题。

2
提供窗口所有者的重载不允许我传入null,但是这个答案解释了我的问题所在。 :) - Ashley Grenon
@townsean 我认为你可以创建一个实现IWin32Window接口的类,并将Handle属性的值返回为null。希望能帮到你。 - Alexey Ivanov
我在关机时遇到了同样的问题,我以为消息框会一直停留直到用户按下“确定”按钮,然后执行剩余的代码,包括Current.Shutdown(); 当然这里没有启动画面,所以我不确定发生了什么。 - Ingó Vals
2
这个答案是错误的,传递 null 会导致一个 ArgumentNullException - epalm
1
很好的解释,带有闪屏。根据您的想法,可以创建一个辅助窗口(而不是NULL)作为第一个参数。Window helperWin = new Window() { WindowState = WindowState.Minimized, Title = "..." }; helperWin.Show(); MessageBox.Show(helperWin, "message", "title", MessageBoxButton.OK, MessageBoxImage.Exclamation); helperWin.Close(); 在WPF中进行了测试(我没有测试过Forms)...但更好的解决方案在Russell的答案中,使用参数MessageBoxOptions.DefaultDesktopOnly - Beauty
显示剩余2条评论

4
创建透明隐藏窗口并将其用作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;
        }

3

如果您将闪屏实现为代码而不是作为图像构建操作,则可以保留您的闪屏并使用标准的WPF MessageBox。

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

1

Alexey是正确的,启动画面会关闭消息框。

避免这种情况的简单方法是使用本地MessageBox函数:

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

0

您需要告诉WPF当第一个窗口关闭时不要关闭。请看这个链接:http://msdn.microsoft.com/en-us/library/system.windows.application.shutdownmode.aspx。您需要将应用程序设置为显式关闭(而不是在第一个窗口关闭后关闭):

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

另一种选择是将您的MainWindow设置为StartupUri(而不是您的启动画面),然后在MainWindow的loaded事件中加载您的启动画面。然后,您可以执行任何需要加载或耗时的操作,隐藏您的启动画面,并重新显示您的主窗口。


好的,应用程序不会关闭;只有消息框会关闭。 - Ashley Grenon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接