Подписывание LoadFileCommand
не вызывает команду. Команда не вызывается, пока вы не вызовете один из методов выполнения команды. В вашем случае вы хотите позвонить LoadFileCommand.ExecuteAsync
. Я верю, что в вашем случае это вернет IObservable<File>
. Устранение подписки на это наблюдаемое или иным образом прекращение наблюдаемого приведет к тому, что наблюдаемый попросит аннулировать токен отмены, который был передан 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"));
Это выход из кода выше. Вы можете видеть, что маркер отмены действительно требовать отмен:
первой отмена просьбы: Ложная
второй отмена просила: Ложная
второй отмена просила: Ложные
первая отмена просьбы: Ложные
первую завершила
первая аннулирование: True
Требуется вторая просьба об аннулировании: False
Требуется вторая просьба об аннулировании: False
второй запрос отмены d: Ложные
второй следующий
второй завершил
Edit - Возможное решение
Так что я думаю, что у меня есть что-то, что будет работать в вашем сценарии, все еще позволяя вам использовать 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 Аннулирование заказа: True
Можете ли вы показать мне, где вы связываете свой бу tton в 'OpenFileCommand'? –
Я привязываюсь к команде, используя привязку в XAML, например – SuperJMN
Я не думаю, что вы собираетесь куда-нибудь с привязкой XAML. Это будет полагаться на интерфейс 'ICommand' для вызова' Execute', который возвращает void. Вам нужно вызывать 'ExecuteAsync' и висеть на наблюдаемом, который он возвращает, чтобы вы могли его отменить. Я попытаюсь бросить что-то вместе, что может сработать для вас. –