订阅LoadFileCommand 不会调用该命令。直到您调用命令的执行方法之一,才会调用该命令。在您的情况下,您想致电LoadFileCommand.ExecuteAsync。我相信,这将在您的情况下返回IObservable<File>。处理对该 observable 的订阅或以其他方式终止 observable 将导致 observable 请求取消在您的委托中传递给 LoadFile 的取消令牌。
我试图创建一个 .NET Fiddle here 来演示,但它一直说没有引用程序集,即使它显然是。无论如何,如果您想尝试一下,可以将相同的代码复制到 LinqPad 或控制台应用程序中:
var testCommand = ReactiveCommand.CreateAsyncTask(async (name, ct) =>
{
// Do some long running work and periodically check if the
// token has been cancelled.
for (int i = 0; i < 5; i++)
{
Console.WriteLine(
"{0} cancellation requested: {1}",
name,
ct.IsCancellationRequested);
if (ct.IsCancellationRequested)
{
ct.ThrowIfCancellationRequested();
}
await Task.Delay(1000);
}
});
var whenButtonClick =
Observable
.Timer(TimeSpan.FromSeconds(2));
// Execute a command that is cancelled when a button click happens.
// Note the TakeUntil(whenButtonClick)
testCommand
.ExecuteAsync("first")
.TakeUntil(whenButtonClick)
.Subscribe(
onNext: _ => Console.WriteLine("first next"),
onCompleted: () => Console.WriteLine("first completed"));
// Execute a command that runs to completion.
testCommand
.ExecuteAsync("second")
.Subscribe(
onNext: _ => Console.WriteLine("second next"),
onCompleted: () => Console.WriteLine("second completed"));
这是上述代码的输出。您可以看到取消令牌确实请求取消:
第一次取消请求:错误
第二次取消请求:错误
第二次取消请求:错误
第一次取消请求:错误
首次完成
第一次取消请求:真
第二次取消请求:错误
第二次取消请求:错误
第二次取消请求:错误
第二个下一个
第二次完成
编辑 - 可能的解决方案
所以我认为我有一些东西可以在您的场景中工作,同时仍然允许您使用 Xaml 绑定。我将取消逻辑推送到命令工厂方法中,而不是尝试获取单个调用并取消它们。
CancelOpenFileCommand = ReactiveCommand.Create();
LoadFileCommand =
ReactiveCommand
.CreateAsyncObservable(_ =>
Observable
.FromAsync(cancellationToken => LoadFile(cancellationToken))
.TakeUntil(CancelOpenFileCommand));
现在,如果您将用于打开文件的按钮绑定到LoadFileCommand,并将用于取消命令的按钮绑定到CancelOpenFileCommand,一切都应该正常工作。
这是一个使用我上面描述的相同模式的示例。我用一个虚拟任务替换了LoadFile,它只包含一个循环五次的循环,在循环内我将取消令牌的状态写入控制台,然后延迟一秒钟。所以这个任务应该需要五秒钟才能完成。但是我没有让它完成,而是在一秒钟后调用CancelOpenFileCommand。这表明在调用 CancelOpenFileCommand 时取消令牌正在被取消,并且命令提前终止。
var CancelOpenFileCommand = ReactiveCommand.Create();
CancelOpenFileCommand
.Subscribe(x =>
Console
.WriteLine(
"{0} CancelOpenFileCommand Invoked",
DateTime.Now.TimeOfDay));
var LoadFile = new Func<CancellationToken, Task>(async cancellationToken =>
{
for (int i = 0; i < 5; i++)
{
Console
.WriteLine(
"{0} Cancellation requested: {1}",
DateTime.Now.TimeOfDay,
cancellationToken.IsCancellationRequested);
if (cancellationToken.IsCancellationRequested)
{
cancellationToken.ThrowIfCancellationRequested();
}
await Task.Delay(1000);
}
});
var LoadFileCommand =
ReactiveCommand
.CreateAsyncObservable(
name =>
Observable
.FromAsync(ct => LoadFile(ct))
.TakeUntil(CancelOpenFileCommand));
LoadFileCommand.Execute(null);
Observable
.Timer(TimeSpan.FromSeconds(1))
.Subscribe(_ => CancelOpenFileCommand.Execute(null));
这是控制台输出:
19:04:57.6087252 请求取消:错误
19:04:58.6157828 请求取消:错误
19:04:58.6197830 已调用 CancelOpenFileCommand
19:04:59.6268406 请求取消:真