【问题标题】:Form.Show() intermittently showing the form in a threadForm.Show() 在线程中间歇性地显示表单
【发布时间】:2010-12-23 21:57:45
【问题描述】:

我需要在打开文件时显示进度对话框,这是一个耗时的操作。为此,我在我的打开文件函数中使用以下内容:

           //some code
           ...
           ...
           ...
           bool done = false;

            //Show progress in a separate thread. 
            System.Threading.ThreadPool.QueueUserWorkItem((x) =>
            {
                using (var progressDialog = new ProgressDialog())
                {
                    progressDialog.TopMost = true;
                    progressDialog.Show();

                    while (!done)
                    {
                        if(progressDialog.Message != this.strProgressMsg)
                            progressDialog.Message = this.strProgressMsg;

                        Application.DoEvents();
                    }

                    progressDialog.Close();
                }
            });

           ....
           ....
           done = true;
           ....
           ....

问题: 进度条对话框有时会显示,有时不会。我的文件打开函数在主线程中运行。有人可以指出我正确的检测为什么会发生这种情况吗?

【问题讨论】:

    标签: c# multithreading


    【解决方案1】:

    你有这个倒退。以下是它的工作原理:

    1. 分离一个线程来打开文件,并让它使用progressDialog.Invoke() 回调到主线程以执行 GUI 更新。 (它不应该设置 strProgressMsg 并等待其他东西注意到变化——让它直接将更新发送到对话框。)
    2. 从主线程模态显示进度对话框。

    所以是这样的:

    using (var progressDialog = new ProgressDialog()) {
        progressDialog.TopMost = true;
    
        System.Threading.ThreadPool.QueueUserWorkItem((x) =>
        {
            try {
                // this represents whatever loop you use to load the file
                while (...) {
                    // do some work loading the file
    
                    // update the status
                    progressDialog.Invoke(new MethodInvoker(
                        () => progressDialog.Message = "Hello, World!"));
                }
            } finally {
                // done working
                progressDialog.Invoke(new MethodInvoker(progressDialog.Close));
            }
        });
    
        // this will block until the thread closes the dialog
        progressDialog.ShowDialog();
    }
    

    【讨论】:

      【解决方案2】:

      表单需要一条消息才能正常工作。您可以使用Application.RunForm.ShowDialog 启动消息循环,这两个都是阻塞调用,因此显然这种策略在工作线程中效果不佳。这里有两种方法可以让它正常工作。

      • 在 UI 线程上创建 progressDialog 并通过 Control.Invoke 向其发送消息以使用新的进度信息对其进行更新。
      • 在 UI 线程上创建 progressDialog 并让它使用 System.Windows.Forms.Timer 轮询变量以获取工作线程发布的新进度信息。

      在这种情况下,轮询方法优于Control.Invoke 方法,因为:

      • 它打破了Control.Invoke 强加的 UI 和工作线程之间的紧密耦合。
      • 它将更新 UI 线程的责任放在它本来应该属于的 UI 线程上。
      • UI 线程可以决定更新的时间和频率。
      • 不存在 UI 消息泵溢出的风险,就像工作线程启动的封送技术一样。
      • 工作线程无需等待确认更新已执行,即可继续执行后续步骤(即,您可以在 UI 和工作线程上获得更高的吞吐量)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-10-11
        • 1970-01-01
        • 2015-01-06
        • 1970-01-01
        • 2011-08-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多