2014-03-15 7 views
2

Я видел аналогичный вопрос, заданный here, но это не кажется правильным для моего сценария.Отменить выполнение и выполнить повторную запись при повторном вводе метода

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

На данный момент у меня есть:

private readonly IDataService _dataService; 
private readonly MainViewModel _mainViewModel; 

private CancellationTokenSource _cancellationTokenSource; 

//Constructor omitted for brevity 

public async void Execute() 
{ 
    if (_cancellationTokenSource != null) 
    { 
     _cancellationTokenSource.Cancel(); 
    } 

    _cancellationTokenSource = new CancellationTokenSource(); 

    try 
    { 
     string dataItem = await _dataService.GetDataAsync(_mainViewModel.Request, _cancellationTokenSource.Token); 
     _mainViewModel.Data.Add(dataItem); 
    } 
    catch (TaskCanceledException) 
    { 
     //Tidy up ** area of concern ** 
    } 
} 

Это, кажется, хорошо функционировать и у меня есть хороший и отзывчивый интерфейс, но у меня есть сценарий, который касается меня:

  1. Запрос производится пользователь
  2. Пользователь делает новый запрос, который отменяет исходный запрос
  3. Новый запрос возвращается до того, как первоначальный аннулированный запрос вызывает его исключение populati нг пользовательского интерфейса с необходимыми в настоящее время данных
  4. Исключение отбрасывается и очистка происходит перезапись новых запросов выхода

Это может быть очень редким, но я могу видеть это как возможность, если мое понимание этого не случилось ,

Есть ли способ гарантировать, что если задача отменена с помощью запроса маркера отмены и запускается новая задача, то аннулирование происходит до того, как будет запущена или запущена новая задача, не блокируя поток пользовательского интерфейса?

Любое чтение, чтобы расширить мое понимание об этом, было бы очень признательно.

+0

Почему приведение в порядок перезаписывает результаты? Очистить результаты до вызова. – Paparazzi

ответ

2

Есть ли способ, чтобы убедиться, что если задача будет отменена с помощью маркеров запроса отмены и новое задание запускается отмена происходит до того, как новая задача запускается/выполнение возвращается без блокирует поток пользовательского интерфейса?

Любое чтение, чтобы развернуть мое понимание об этом, было бы самым оценено.

Во-первых, некоторые из которых связаны чтение и вопросы, в соответствии с просьбой:

Если я правильно понял ваш вопрос, ваша основная проблема является то, что предыдущим экземпляра той же задачи может обновить пользовательский интерфейс (или ViewModel) с устаревшими результатами, как только он закончил.

Чтобы убедиться, что это не произойдет, используйте ThrowIfCancellationRequested с соответствующим лексема перед вы как раз собирается обновить UI/модель, везде вам сделать это. Тогда не имеет значения, завершится ли последний экземпляр задачи до предыдущего более старого. Чем старше задача достигнет ThrowIfCancellationRequested точки перед тем он может иметь шанс сделать что-нибудь вредное, так что вам не придется await старую задачу:

public async void Execute() 
{ 
    if (_cancellationTokenSource != null) 
    { 
     _cancellationTokenSource.Cancel(); 
    } 

    _cancellationTokenSource = new CancellationTokenSource(); 
    var token = _cancellationTokenSource.Token. 

    try 
    { 
     string dataItem = await _dataService.GetDataAsync(
      _mainViewModel.Request, 
      token); 

     token.ThrowIfCancellationRequested(); 

     _mainViewModel.Data.Add(dataItem); 
    } 
    catch (OperationCanceledException) 
    { 
     //Tidy up ** area of concern ** 
    } 
} 

Другой проблемой является то, что делать в ситуации, когда предыдущая задача выходит из строя с чем-либо еще, кроме TaskCanceledException. Это может случиться и после завершения новой задачи. Вам решать, игнорировать это исключение, повторно бросить его или сделать что-нибудь еще:

try 
{ 
    string dataItem = await _dataService.GetDataAsync(
     _mainViewModel.Request, 
     token); 

    token.ThrowIfCancellationRequested(); 

    _mainViewModel.Data.Add(dataItem); 
} 
catch (Exception ex) 
{ 
    if (ex is OperationCanceledException) 
     return 

    if (!token.IsCancellationRequested) 
    { 
     // thrown before the cancellation has been requested, 
     // report and re-throw 
     MessageBox.Show(ex.Message); 
     throw; 
    } 

    // otherwise, log and ignore 
} 
+1

Не хотите ли вы также обрабатывать OperationCanceledException? – Paparazzi

+0

@Blam, конечно, вы правы, я изначально неправильно вас понял. Да, 'OperationCanceledException' следует использовать везде, а не' TaskCancelledException'. Я забыл, что при копировании кода OP. – Noseratio

+0

ОК, так что это nitpicking put У меня есть catch (OperationCanceledException Ex) – Paparazzi

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