【问题标题】:Modal Messagebox from background thread来自后台线程的模态消息框
【发布时间】:2014-08-13 22:16:49
【问题描述】:

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

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

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

接下来,从后台线程启动。这会产生一个无模式消息框,我假设是因为它不在 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 线程上调用的,那为什么它不像前面的例子那样是 Modal 的呢?

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!");
        });
    }

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

为什么最后两个示例中的行为不同?

【问题讨论】:

  • 好问题。我在看FileSystemWatcher.SynchronizingObject,这让我想知道......

标签: wpf modal-dialog messagebox background-thread


【解决方案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 已关闭。我尝试查找所有者,但随后出现空引用异常。

【讨论】:

  • 感谢您的回复,看来我不会得到答案:(
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-08
  • 1970-01-01
  • 2012-02-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多