来自后台线程的模态消息框

时间:2014-08-13 22:16:50

标签: wpf modal-dialog messagebox background-thread

我注意到,当MessageBox是模态的时,似乎存在不一致的行为。

首先,从UI线程启动MessageBox。这会产生一个模态MessageBox,如预期的那样:

void MainThreadClick(object sender, RoutedEventArgs e)
    {
        MessageBox.Show("Hello!");
    }

接下来,从后台线程启动。这会产生一个无模式MessageBox,我假设因为它不在UI线程上?

void WorkerThreadClick(object sender, RoutedEventArgs e)
    {
        ThreadPool.QueueUserWorkItem((x) =>
        {
            MessageBox.Show("Hello!");
        });
    }

接下来,从后台线程启动,但调度到UI线程,导致它再次成为模态:

void WorkerThreadClick(object sender, RoutedEventArgs e)
    {
        ThreadPool.QueueUserWorkItem((x) =>
        {
            Application.Current.Dispatcher.Invoke(() =>
            {
                MessageBox.Show("Hello!");
            });
        });
    }

最后,这是一个奇怪的,与上面类似,但使用FileSystemWatcher线程会产生一个无模式对话框。为什么是这样? ...它是在UI线程上调用的,那么为什么它不像上一个示例那样是模态?

public MainWindow()
    {
        InitializeComponent();

        m_watcher = new FileSystemWatcher()
        {
            Path = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
            NotifyFilter = NotifyFilters.LastWrite,
            IncludeSubdirectories = true,
            Filter = "*.*"
        };

        m_watcher.Changed += OnFileSystemResourceChanged;
        m_watcher.EnableRaisingEvents = true;
    }

    void OnFileSystemResourceChanged(object _sender, FileSystemEventArgs _args)
    {
        Application.Current.Dispatcher.Invoke(() =>
        {
            MessageBox.Show("Hello!");
        });
    }

虽然我可以使用将Window所有者作为参数的MessagBox.Show()方法解决最后一个问题,但我想了解发生了什么。

为什么最后两个例子中的行为有所不同?

1 个答案:

答案 0 :(得分:1)

这个问题确实困扰了我一段时间。在进行一些分析时,我发现在最后一种情况下(FileSystemWatcher)所有者发生了变化(我还没有想到谁接管了所有权)。

我还发现有一个小但重要的区别。

在场景编号2中

void WorkerThreadClick(object sender, RoutedEventArgs e)
{
    ThreadPool.QueueUserWorkItem((x) =>
    {
        MessageBox.Show("Hello!");
    });
}

即使行为是无模式的,但是当我关闭MainWindow时,我的应用程序也会关闭。

FileSystemWatcher方案中,行为再次成为无模式,但当我关闭MainWindow时,应用程序不会关闭,除非我关闭MessageBox(所以我知道有人接管了所有权。谁拿走了我还不知道。)

修改

我在最后一个场景中更改了Shutdown模式

void OnFileSystemResourceChanged(object sender, FileSystemEventArgs args)
    {
        Application.Current.Dispatcher.Invoke(() =>
            {
                Application.Current.ShutdownMode=ShutdownMode.OnMainWindowClose;
                MessageBox.Show("Test");
            });
    }

即使这样,当我关闭MainWindow我的Application时,除非MessageBox关闭,否则{{1}}未关闭。我尝试找到所有者,但后来我得到了空引用异常。