【问题标题】:C# : Show dialog on UI thread from another threadC#:在另一个线程的 UI 线程上显示对话框
【发布时间】:2011-11-05 02:33:23
【问题描述】:

我是 C# 新手,但我已经完成了很多 java 工作。这是我的问题:我正在尝试从不是 UI 线程的线程打开“SaveFileDialog”。

这正是我尝试做的:

public partial class Form1: Form
{
    public string AskSaveFile()
    {
        var sfd = new SaveFileDialog();
        sfd.Filter = "Fichiers txt (*.txt)|*.txt|Tous les fichiers (*.*)|*.*";
        sfd.FilterIndex = 1;
        sfd.RestoreDirectory = true;
        DialogResult result = (DialogResult) Invoke(new Action(() => sfd.ShowDialog(this)));
        if(result == DialogResult.OK)
        {
            return sfd.FileName;
        }

        return null;
    }
}

此方法将始终从与拥有表单的线程不同的线程中调用。问题是当我执行这段代码时,“Form1”冻结并且“SaveFileDialog”没有出现。

你有什么线索可以帮助我显示来自独立线程的对话框吗?

【问题讨论】:

    标签: c# winforms multithreading dialog


    【解决方案1】:

    试试这个:

    public partial class Form1: Form
    {
        public string AskSaveFile()
        {
            if (this.InvokeRequired)
            {
                Invoke( new MethodInvoker( delegate() { AskSaveFile(); } ) );
            }
            else
            {
                var sfd = new SaveFileDialog();
                sfd.Filter = "Fichiers txt (*.txt)|*.txt|Tous les fichiers (*.*)|*.*";
                sfd.FilterIndex = 1;
                sfd.RestoreDirectory = true;
                if(sfd.ShowDialog() == DialogResult.OK) return sfd.FileName; 
            }               
            return null;
        }
    }
    

    【讨论】:

    • 不工作:“AskSaveFile”需要返回一个字符串。如果我用“EndInvoke”等待结果,我会遇到同样的问题(“Form1”冻结)。
    • 新代码的第一部分使 Dialog 在主线程中执行......所以这可以工作......哦,是的,主线程将执行这个......但是你的意思是你的主线程正在做不同的东西不能使用?相信我,我在我的应用程序的不同线程中使用此代码并且它可以工作......所以我现在一定有一些不明白的东西......
    • @Hans:你的评论是对我还是对 Mathieu?
    • 你是对的,第一部分正在工作,它显示了对话框。但我找到了解决方案。我已经将调用该方法的线程设置为“STA”,现在是这个执行方法“sfd.ShowDialog()”的线程。
    • 为您服务。 C# 编译器不允许您编写不能保证始终设置返回值的代码。
    【解决方案2】:

    让它看起来像这样:

        public string AskSaveFile() {
            if (this.InvokeRequired) {
                return (string)Invoke(new Func<string>(() => AskSaveFile()));
            }
            else {
                var sfd = new SaveFileDialog();
                sfd.Filter = "Fichiers txt (*.txt)|*.txt|Tous les fichiers (*.*)|*.*";
                sfd.FilterIndex = 1;
                sfd.RestoreDirectory = true;
                return sfd.ShowDialog() == DialogResult.OK ? sfd.FileName : null;
            }
        }
    

    如果您仍然遇到死锁,请务必使用调试器的 Debug + Windows + Threads 窗口并查看 UI 线程在做什么。 Control.Invoke() 无法完成,除非 UI 线程处于空闲状态并泵送消息循环。等待工作线程完成总是会导致死锁。

    还要考虑到这种代码是有风险的,用户可能不会期望这个对话框突然出现并在 UI 线程拥有的窗口中使用鼠标或键盘时意外关闭它。

    【讨论】:

    • 感谢这对我有用。我在 FolderBrowserDialog 中使用它
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多