如何在非GUI线程中获得任务完成通知

本文关键字:任务 通知 GUI 线程 | 更新日期: 2023-09-27 18:03:42

Background:我过去常常在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线程中获得任务完成回调与任务结果。谢谢你

如何在非GUI线程中获得任务完成通知

所有这些东西都在Async语言扩展中得到了最好的解决,你可以在这里下载并在这里有主页。

它向c#和VB引入了asyncawait关键字,这将使您编写的代码可以在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

我个人使用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;
}

你应该考虑使用异步API,而不是在后台线程中调用同步版本:

http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlcommand.beginexecutenonquery.aspx

这样做的好处是没有线程会被阻塞,并且我相信回调将在ThreadPool线程上调用,例如不在GUI线程上调用。从那里,您可以使用Invoke/BeginInvoke将任何GUI调用封送回GUI线程。

为什么不这样做呢:

Task.Factory.StartNew(()=>WorkerMethod());

并定义WorkerMethod()为:

void WorkerMethod()
{
     RunSPAndCheckStuff(); // this blocks until finished
     DoSomeMoreStuff(); // then this continuous
}