在非UI线程上运行模式对话框

时间:2009-11-08 19:42:25

标签: c# .net winforms multithreading modal-dialog

我正在编写一个简单的数据UI,使用标准的.Net数据绑定到SQL Server中的类型化DataSet。

我有一个重新加载按钮,在所有DataAdapter上调用Fill以从数据库中获取新数据(如果其他用户更改了数据)。

这需要一些时间,在此期间UI被冻结。它必须在UI线程上运行,或者数据绑定事件处理程序抛出跨线程异常。

当UI线程连接到数据库时,我想在后台线程上显示模式“Please Wait”对话框(以便可以设置动画)。

如何在非UI线程上显示模式对话框?


编辑:我知道最佳做法是在后台运行该操作,但由于数据绑定事件,我不能这样做。

5 个答案:

答案 0 :(得分:8)

你应该做相反的事情。在后台线程上运行长时间运行的进程,让UI线程自由响应用户操作。

如果要在处理过程中阻止任何用户操作,您有许多选项,包括模态对话框。后台线程完成处理后,您可以通知主线程有关结果

答案 1 :(得分:2)

数据绑定事件中运行的代码需要与UI分离,可能使用某种数据传输对象。

然后,您可以在单独的线程或BackgroundWorker中运行查询操作,并保持UI线程不变。

编辑:真正快速解决此问题的方法是使用InvokeRequired.Invoke让事件在他们自己的代理中运行。这将给出方法UI上下文。我的同事这样做就像它已经过时了,它让我感到厌烦,因为以这种方式做这件事并不是一个好主意......但如果你想要一个快速的解决方案,这将是有效的。 (我不上班,所以我没有样品给我;我会试着想出办法。)

编辑2:我不确定你所要求的是可能的。我做了一个示例应用程序,在另一个线程中创建了一个模态对话框,最终变为无模式。您可以使用其他一些控件或一组控件来指示进度更改,而不是使用模态对话框,很可能直接在同一表单上吗?

答案 2 :(得分:0)

using( var frmDialog = new MyPleasWaitDialog() ) {
    // data loading is started after the form is shown
    frmDialog.Load += (_sender, _e) {
        // load data in separate thread
        ThreadPool.QueueWorkItem( (_state)=> {
            myAdapter.Fill( myDataSet );
            // refresh UI components in correct (UI) thread
            frmDialog.Invoke( (Action)myDataControl.Refresh );
            // close dialog
            frmDialog.Invoke( (Action)frmDialog.Close() );
        }
    }

    // shows dialog
    frmDialog.ShowDialog( this );
}

答案 3 :(得分:0)

以下是使用BackgroundWorker进行数据加载并运行用户友好表单以显示“正在加载记录”或类似内容的示例...

    public void Run()
    {
        bgWorkrFillDS = new BackgroundWorker();
        bgWorkrFillDS.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bgWorkrFillDS_RunWorkerCompleted);
        bgWorkrFillDS.DoWork += new DoWorkEventHandler(bgWorkrFillDS_DoWork);
        bgWorkrFillDS.RunWorkerAsync();
    }

    void bgWorkrFillDS_DoWork(object sender, DoWorkEventArgs e)
    {
        BackgroundWorker bgWrkrFillDS = (BackgroundWorker)sender as BackgroundWorker;
        if (bgWrkrFillDS != null)
        {
            // Load up the form that shows a 'Loading....'
            // Here we fill in the DS
            // someDataSetAdapter.Fill(myDataSet);
        }
    }


    void bgWorkrFillDS_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        // Hide or unload the form when the work is done
    }

希望这会有所帮助...... 照顾自己, 汤姆。

答案 4 :(得分:0)

我通过创建一个新的DataSet,在后台加载,然后在UI线程上调用DataSet.Merge来解决这个问题。感谢大家的建议,这导致了这个解决方案。

作为一个额外的好处,它比以前更快地运行很多(在后台调用Fill,这只能在没有网格打开的情况下工作)。有谁知道为什么?