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

wfo*_*orl 5 wpf modal-dialog messagebox background-thread

我注意到当 MessageBox 处于模式状态时,行为似乎不一致。

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

void MainThreadClick(object sender, RoutedEventArgs e)
    {
        MessageBox.Show("Hello!");
    }
Run Code Online (Sandbox Code Playgroud)

接下来,从后台线程启动。这会导致无模式 MessageBox,我猜是因为它不在 UI 线程上?

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

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

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

最后,这是一个奇怪的问题,与上面类似,但使用 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!");
        });
    }
Run Code Online (Sandbox Code Playgroud)

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

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

San*_*esh 2

这个问题确实困扰了我一段时间。经过一些分析,我发现在最后一种情况(FileSystemWatcher)中,所有者发生了变化(我还没有弄清楚谁接管了所有权)。

我还发现存在一个微小但重要的差异。

在场景 2 中

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

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

在这种FileSystemWatcher情况下,行为再次是无模式的,但是当我关闭MainWindow应用程序时,除非我关闭应用程序,否则应用程序不会关闭MessageBox(所以我知道有人已经接管了所有权。谁接管了它,我还不知道)。

编辑

我改变了Shutdown最后一个场景的模式

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

即使这样,当我关闭时,除非关闭,否则MainWindow我的不会关闭。我尝试找到所有者,但随后出现空引用异常。ApplicationMessageBox