背景:我曾经在Form Load期间调用存储过程。但是,由于这会导致UI体验不理想,我将我的SP调用放在Shown
事件中的自己的任务中。由于这通常是表单显示过程中的最后一个事件,因此它比将表单加载事件中的内容更好。我有:
private void MainForm_Shown(object sender, EventArgs e)
{
dbCheckTask = Task<bool>.Factory.StartNew(RunSPAndCheckStuff());
// both of below run on the GUI thread.
// if I print the thread ID in mycallback it is the GUI thread id
dbCheckTask.ContinueWith(mycallback());
// I also tried below. But obviously, that too runs on the GUI thread
mycallback(dbCheckTask.Result)
}
因为它们在GUI线程上触发,我的启动表单绘制仍然既不是即时的也不是平滑的。如何在不诉诸事件的情况下在非GUI线程上完成任务完成回调?每当任务完成并且出现问题并且只有在出现问题时(bool结果返回false),用户才会弹出一个消息框。在那之前,他可以继续在表格上做其他非数据库相关的事情。请告诉我如何在非gui线程中获取任务结果回调和任务结果。谢谢
答案 0 :(得分:3)
所有这些内容都可以在您可以下载here的Async语言扩展程序中得到最佳解决,并且主页为here。
它将async
和await
关键字引入C#和VB,使您可以编写在UI和后台线程之间来回切换的代码,即使在单个方法中也是如此。编译器会将其转换为任务,延续,错误捕获等,而不必担心任何问题。你会感兴趣的例子是:
public async void AsyncSwitchToCPU() {
Console.WriteLine("On the UI thread.");
// Switch to a thread pool thread:
await new SynchronizationContext().SwitchTo();
Console.WriteLine("Starting CPU-intensive work on background thread...");
int result = DoCpuIntensiveWork();
Console.WriteLine("Done with CPU-intensive work!");
// Switch back to UI thread
await Application.Current.Dispatcher.SwitchTo();
Console.WriteLine("Back on the UI thread. Result is {0}.", result);
}
public int DoCpuIntensiveWork()
{
// Simulate some CPU-bound work on the background thread:
Thread.Sleep(5000);
return 123;
}
这甚至还有一个上线许可证(MS的一些保留)。从F#借来的非常优雅的东西。
Rgds Gert-Jan
答案 1 :(得分:1)
您应该考虑使用异步API,而不是在后台线程中调用同步版本:
http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlcommand.beginexecutenonquery.aspx
这样做的好处是不会阻塞任何线程,我相信将在ThreadPool线程上调用回调,例如不在GUI线程上。从那里,您可以使用Invoke / BeginInvoke将任何GUI调用封送回GUI线程。
答案 2 :(得分:1)
我个人使用BackgroundWorker
。让回调在任务线程上运行的一种方法是修改方法调用和任务创建,如下所示:
private void MainForm_Shown(object sender, EventArgs e)
{
dbCheckTask = Task<bool>.Factory.StartNew(() => RunSPAndCheckStuff(mycallback));
...
}
private bool RunSPAndCheckStuff(Action<bool> callback)
{
bool result = false;
// Do stuff
callback(result);
return result;
}
答案 3 :(得分:0)
为什么不这样做:
Task.Factory.StartNew(()=>WorkerMethod());
将WorkerMethod()定义为:
void WorkerMethod()
{
RunSPAndCheckStuff(); // this blocks until finished
DoSomeMoreStuff(); // then this continuous
}
否则请提供更多有关您想要完成的内容的详细信息。