我正在编写一个简单的数据UI,使用标准的.Net数据绑定到SQL Server中的类型化DataSet。
我有一个重新加载按钮,在所有DataAdapter上调用Fill
以从数据库中获取新数据(如果其他用户更改了数据)。
这需要一些时间,在此期间UI被冻结。它必须在UI线程上运行,或者数据绑定事件处理程序抛出跨线程异常。
当UI线程连接到数据库时,我想在后台线程上显示模式“Please Wait”对话框(以便可以设置动画)。
如何在非UI线程上显示模式对话框?
编辑:我知道最佳做法是在后台运行该操作,但由于数据绑定事件,我不能这样做。
答案 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
,这只能在没有网格打开的情况下工作)。有谁知道为什么?