异步方法中的 C# 模态对话框ShowDialog 或 MessageBox.Show无法按预期工作

问题描述

我有一个最顶层的 WinForm,有一个简单的按钮,可以异步执行一些命令:

        private async void button1_Click(object sender,EventArgs e)
    {
        await System.Threading.Tasks.Task.Run(() =>
        {
            System.Threading.Thread.Sleep(2000);

            //Problem1: not works as "modal" dialog Box (Main form remains active!) 
            new Form().ShowDialog();

            //Problem2: not shown as "modal" messageBox (Main form remains active!)
            MessageBox.Show("Test");
        });
    }

在异步函数内部是 MessageBox.Show()ShowDialog() 方法,但是:

问题 1(已解决): 新表单未作为模态对话框打开(主表单仍处于活动状态且可访问!)

问题 2(已解决):MessageBox.Show() 方法的行为不像模态对话框(主窗体仍处于活动状态且可访问!)。

我需要 async-await 来防止主 UI 冻结,但我也希望内部的消息框(和子表单)显示为模式对话框。如何通过异步方法显示模式对话框(在主要的最顶层表单上)?

谢谢

解决方法

问题 1 的解决方案: ShowDialogAsync 扩展方法解决了这个问题。

问题 2 的解决方案:

        private async void button1_Click(object sender,EventArgs e)
    {

        var handle = this.Handle;
        await System.Threading.Tasks.Task.Run(() =>
        {
            System.Threading.Thread.Sleep(2000);

            //Solution for Problem2:

            NativeWindow win32Parent = new NativeWindow();
            win32Parent.AssignHandle(handle);
            //Works as expected (Topmost and Modal):
            MessageBox.Show(win32Parent,"Test");
        });
    }

Related topic

,

Task.Run() 在后台线程中运行工作。通常,您不应该从后台线程显示窗口,但您可以。要解决您的问题,您需要使用 UI 线程 Dispatcher。

Application.Current.Dispatcher.Invoke(() => MessageBox.Show("Test"));

Application.Current.Dispatcher.Invoke(() => new Form().ShowDialog());

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...