uwp C#取消异步任务并重新运行

时间:2017-11-10 10:16:30

标签: c# uwp async-await

提前致谢。 我想使用foreach将项添加到`GridView。这是在 async 方法中完成的。 我想从其他 async 方法中检索项目并在GridView中显示它们:

public async Task SetGridItems(CancellationToken ct, /* and some items */)
{

    GridItems.clear();
    //get two list of item I want
    var ListA = await getBmethodAsync().AsTask(ct);
    var ListB = await getAmethodAsync().AsTask(ct);

    foreach (itemA A in ListA)
    {     
        GridItem i = new GridItem();

        //set name
        i.name = A.Name;

        //get icon
        i.image = img;

        GridItems.Add(i);
    }

    foreach (ItemB b in ListB)
    {
         GridItem i = new GridItem();
         i.name = b.Name;
         i.image.SetSource(icon);

         GridItems.Add(i);
    }
}

为方便起见,内容已经过简化。

当我在按钮单击处理程序中运行此方法时:

private async void check_btn2_Click(object sender, RoutedEventArgs e)
{    
    if (cts != null) { 
        cts.Cancel();
        debug.Text = "cancel a job 4";
    }

    cts = new CancellationTokenSource();
    try
    {
       await SetGridItems(ct.Token, /* and some items */).AsAsyncAction().AsTask(cts.Token);
    }
    catch (OperationCanceledException) { debug.Text = "cancel a job"; }
}

问题在于:

如果我点击此按钮两次(快速点击): - 第一次单击时,将调用事件回调,我的任务将开始运行 - 某些内容会在GridView中显示但不会完成(结束时为80%) - 第二次点击时,GridView按预期清除,并加载了一些新内容,但GriView仅显示第一次点击任务的最后20%

那么,为什么第二次点击取消第一个任务?

我在网上搜了很久,坚果没找到任何东西。请帮助并尝试提供一些如何实现这一目标的想法。

我不擅长英语,谢谢

1 个答案:

答案 0 :(得分:1)

我在这里看到两个问题:

首先,正如文森特在评论中所说,您通过按钮点击处理程序中的AsAsyncAction().AsTask(cts.Token);和方法本身中的.AsTask(ct);以一种多余的方式传递取消令牌。 / p>

其次,更重要的是,您将取消令牌传递给任务,但您从未在该方法中使用它。将取消令牌传递给任务主要是并行使用,而不是异步工作。它是您协调和查询一次运行的多个任务的执行状态的一种方式。无论如何,它始终依赖于令牌本身在执行代码中的使用。可以这样想,你告诉任务对象本身你取消了操作,但你的代码并不知道如何处理它。

在异步开发中,你真的不需要将取消传递给任务对象,因为你不必协调其中许多的状态,你只是执行一个。您应该将令牌传递给您的方法,并让您的代码处理它 因此,在SetGridItems方法中,尝试执行以下操作:

public async Task SetGridItems(CancellationToken ct, /* and some items */)
{

    GridItems.clear();
    //get two list of item I want
    var ListA = await getBmethodAsync().AsTask(ct);
    var ListB = await getAmethodAsync().AsTask(ct);

    foreach (itemA A in ListA)
    {
        ct.ThrowIfCancellationRequested();

        GridItem i = new GridItem();

        //set name
        i.name = A.Name;

        //get icon
        i.image = img;

        GridItems.Add(i);
    }

    foreach (ItemB b in ListB)
    {
        ct.ThrowIfCancellationRequested();

        GridItem i = new GridItem();
        i.name = b.Name;
        i.image.SetSource(icon);

        GridItems.Add(i);
    }
}

确保在GetXMethodAsync方法中执行相同的操作。这样您的代码就知道如何处理取消。因为现在,任务对象可能会被取消,但它仍然会继续执行代码,因为它不知道在哪里停止。

有关任务取消的更多信息,您可以看到以下链接:
1. https://docs.microsoft.com/en-us/dotnet/standard/parallel-programming/task-cancellation
2. https://docs.microsoft.com/en-us/dotnet/standard/parallel-programming/how-to-cancel-a-task-and-its-children

希望这有帮助