如何取消 IMvxAsyncCommand?

How to cancel IMvxAsyncCommand?

我刚开始在 MVVMcross 平台上使用 xamarin android。我需要取消 IMvxAsyncCommand 但我尝试了很多方法,它仍然不起作用。有人对此有任何想法或样本吗?

所以基本上 IMvxAsyncCommand 就像这样调用 Task

MyCommand = new MvxAsyncCommand(MyTask);
...
private async Task MyTask()
{
     // do async stuff
}

为了取消 Task,您需要使用 CancellationToken,您可以从 CancellationTokenSource 获取它并使用另一个命令或任何您想调用 Cancel()CancellationTokenSource 上,所以您可以这样做的一种方法是:

public class MyClass
{
    private CancellationTokenSource cts;

    public MyClass()
    {
        MyAsyncCommand = new MvxAsyncCommand(MyTask);
        CancelMyTaskCommand = new MvxCommand(() => cts.Cancel());
    }

    public ICommand MyAsyncCommand {get; private set; }

    public ICommand CancelMyTaskCommand { get; private set; }

    private async Task MyTask()
    {
        cts = new CancellationTokenSource();

        await MyAsyncStuff(cts.CancellationToken);

        cts.Dispose();
        cts = null;
    }

    private async Task MyAsyncStuff(CancellationToken cancellationToken)
    {
        cancellationToken.ThrowIfCancellationRequested();

        await foo.BlablaAsync();

        cancellationToken.ThrowIfCancellationRequested();

        await bar.WhateverAsync();

        cancellationToken.ThrowIfCancellationRequested();

        await foo2.AnotherAsync();
    }
}

然后您可以改进代码以避免重复调用 Task、处理取消异常、使用 MvxNotifyTask 和许多其他东西,但这是基础。

更多信息在Cancellation in Managed Threads

您实际上可以直接取消 MvxAsyncCommand 而无需创建任何额外的 CancellationTokenSource

只需对对象本身调用 Cancel()

因此,不要让 属性 成为 ICommandIMvxCommand,而是使用 MvxAsyncCommandIMvxAsyncCommand

这样,当您在 Task 中将 CancellationToken 作为参数并在命令中调用 Cancel() 时,它将取消该标记。

private async Task MyAsyncStuff(CancellationToken ct)
{
    await abc.AwesomeAsyncMethod(ct);
    // and/or
    ct.ThrowIfCancellationRequested();
}

所以如果你修改@fmaccaroni 的答案,你会得到这个:

public class MyClass
{    
    public MyClass()
    {
        MyAsyncCommand = new MvxAsyncCommand(MyAsyncStuff);
        CancelMyTaskCommand = new MvxCommand(() => MyAsyncCommand.Cancel());
    }

    public IMvxAsyncCommand MyAsyncCommand {get; private set; }

    public ICommand CancelMyTaskCommand { get; private set; }

    private async Task MyAsyncStuff(CancellationToken cancellationToken)
    {
        cancellationToken.ThrowIfCancellationRequested();

        await foo.BlablaAsync();

        cancellationToken.ThrowIfCancellationRequested();

        await bar.WhateverAsync();

        cancellationToken.ThrowIfCancellationRequested();

        await foo2.AnotherAsync();
    }
}

编辑:如果您的异步方法还允许传递 CancellationToken 直接取消它们,甚至更好,MyAsyncStuff 方法可以这样写:

private async Task MyAsyncStuff(CancellationToken cancellationToken)
{
    await foo.BlablaAsync(cancellationToken);
    await bar.WhateverAsync(cancellationToken);
    await foo2.AnotherAsync(cancellationToken);
}

或者,如果您不关心他们开始和完成的顺序:

private Task MyAsyncStuff(CancellationToken cancellationToken)
{
    return Task.WhenAll(
        foo.BlablaAsync(cancellationToken),
        bar.WhateverAsync(cancellationToken),
        foo2.AnotherAsync(cancellationToken));
}