2016-02-25 2 views
2

У меня есть эта ReactiveCommand;Задача ReactiveCommand.CreateAsync. Как отменить задачу с помощью кнопки?

LoadFileCommand = ReactiveCommand.CreateAsyncTask((_, cancellationToken) => LoadFile(cancellationToken)); 

Я также подписаться на команду

subscription = LoadFileCommand.Subscribe(file => OnFileLoaded(file); 

Теперь я хочу сделать еще одну команду, которая используется из пользовательского интерфейса (в кнопке), чтобы отменить задание.

Но КАК?

У меня нет возможности «ввести» мое аннулирование. Заключить команду LoadFileCommand. Я действительно потерян!

EDIT:

В настоящее время под моим MainViewModel.cs (в конструкторе) У меня есть это:

OpenFileCommand = ReactiveCommand.CreateAsyncTask(async (o, ct) => await LoadFile(ct)); 

var whenButtonClick = 
    Observable 
     .Timer(TimeSpan.FromSeconds(10)); 
whenButtonClick.Subscribe(_ => Console.WriteLine()); 

OpenFileCommand 
    .ExecuteAsync() 
    .TakeUntil(whenButtonClick) 
    .Subscribe(OnDocumentLoaded); 

У меня есть "Загрузить" кнопку на мой взгляд, который связан с LoadFileCommand, но с кодом выполняет задачу, как только создается viewmodel, а не когда пользователь нажимает кнопку.

Кстати, я хочу иметь еще одну кнопку «Отмена», которая позволяет пользователю отменить загрузку.

+0

Можете ли вы показать мне, где вы связываете свой бу tton в 'OpenFileCommand'? –

+0

Я привязываюсь к команде, используя привязку в XAML, например

+0

Я не думаю, что вы собираетесь куда-нибудь с привязкой XAML. Это будет полагаться на интерфейс 'ICommand' для вызова' Execute', который возвращает void. Вам нужно вызывать 'ExecuteAsync' и висеть на наблюдаемом, который он возвращает, чтобы вы могли его отменить. Я попытаюсь бросить что-то вместе, что может сработать для вас. –

ответ

2

Подписывание 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

+0

Итак, подписка = LoadFileCommand.Subscribe (file => OnFileLoaded (файл) не так? Я думал, что подписка на эту команду была способом получения результатов Задачи после ее завершения. Я что-то упустил? – SuperJMN

+1

@Super Нет, это не так. Вы получаете результаты вызова команды в наблюдаемом файле LoadFileCommand. Если вы хотите отменить команду, единственным способом, который я знаю, является захват наблюдаемого, возвращаемого при вызове команды и завершении наблюдаемого. Я не знаю, как это сделать с помощью команды observable. Какой смысл имеет смысл, если это длинная работа, команда могла быть вызвана любым количеством дополнительных времен, единственный способ отменить индивидуальный вызов команды будет иметь некоторый объект, который представляет этот вызов команды. –

+0

Я немного смущен :(Я делаю это, чтобы связать Button с LoadCommand. В MainViewModel (в c тор). Если я поместил строку 'testCommand .ExecuteAsync (" first ")' он поднимает задачу, даже если кнопка не нажата. Я хотел бы, чтобы пользователь поднял его, нажав кнопку и разрешив отменить использование другой кнопки. Пожалуйста, взгляните на редактирование, которое я опубликовал в исходном сообщении. – SuperJMN

Смежные вопросы