表单加载后取消异步操作?

时间:2015-05-11 12:14:05

标签: c# winforms asynchronous task-parallel-library

我有不同的类(实现接口),其中一种方法是执行异步数据库搜索:

public async void SearchAsync(CancellationToken ct)
{
    await Task.Run(() => {Find(); }, ct);
}

private void Find()
{
    //do db search here...
}

当打开表单时,会执行后台异步搜索以加快用户输入,所以我所做的是:

protected override void OnShown(EventArgs e)
{
    base.OnShown(e);

    try
    {
        //Get list of items that will perform async search...
        //var results = ...

        //Do an async search
        Task task = Task.Factory.StartNew(() =>
            {
                foreach (var item in results)
                {
                    item.SearchAsync(cts.Token);
                }
            }, cts.Token);
    }
    catch (OperationCanceledException)
    { }
}

如果用户关闭表单而任务仍在执行,我会这样做:

protected override void OnFormClosing(FormClosingEventArgs e)
{
    base.OnFormClosing(e);

    if (cts != null)
    {
        cts.Cancel();
    }
}

首先,上面是执行异步操作的正确方法吗?

其次,当我在任务仍未完成时关闭表单时,代码永远不会到达OperationCancelException。可能是上述实施不正确吗?

1 个答案:

答案 0 :(得分:3)

有几点要注意。首先,您正在使用"async over sync"反模式,应该强烈避免。你也传递了一个CancellationToken但实际上从未监视过它。如果您的方法是同步的,那么在执行时您无法真正监视它,您可以做的最好是在执行CancellationToken的每次迭代之前监视Search

public void Search()
{
    Find();
}

protected override async void OnShown(EventArgs e)
{
   base.OnShown(e);

   try
   {
       await Task.Run(() =>
       {
           foreach (var item in results)
           {
               cts.Token.ThrowIfCancellationRequested();
               item.Search();
           }
       }, cts.Token);
   }
   catch (OperationCanceledException)
   { }
}

然后你取消:

protected override void OnFormClosing(FormClosingEventArgs e)
{
    base.OnFormClosing(e);

    if (cts != null)
    {
        cts.Cancel();
    }
}