Отменить и запустить новую асинхронную задачу на основе навигации

У меня есть форма WPF, экран которой разделен на 2 части в качестве основной формы детализации. Приведенная выше часть является основной, и она показывает кучу записей в сетке данных, которая привязана к источнику collectionviewsource. Всякий раз, когда пользователь щелкает строку, нижняя часть формы создается путем реакции на событие collectionviewsource.current_changed. Там я отменяю все незавершенные асинхронные операции и начинаю новую. Код выглядит так:

if (_tokenSource != null) //_tokenSource is an instance variable of the class that implements current_changed
{
    try
    {
        _tokenSource.Cancel(); //needed because _tokenSource might be disposed already. Ugly.
    }
    catch (Exception Ex)
    {
    }
}

using (_tokenSource = new CancellationTokenSource())
{
    try
    {
        _unitOfWork = await loadRelatieAsync(relatieId, _tokenSource.Token); // this is just currently an await Task.Delay(5000,token).ConfigureAwait(true); return null;
    }
    catch (Exception Ex)
    {
    }
}
//_tokenSource = null; can’t do this, it would lead to several operations not being cancelled

То, что у меня есть, похоже, работает, но код уродлив, приложение все еще немного вяло. Есть ли правильный / лучший способ сделать это?

1 ответ

Решение

Я обычно не пытаюсь избавиться от CancellationTokenSource, Если вы просто перезаписываете, не утилизируя, код будет чище:

if (_tokenSource != null)
  _tokenSource.Cancel();

_tokenSource = new CancellationTokenSource();
try
{
  _unitOfWork = await loadRelatieAsync(relatieId, _tokenSource.Token);
  return null;
}
catch (OperationCanceledException ex)
{
}

Что касается "медлительности", я полагаю, что это может быть связано с тем, что пользователь быстро меняет выбранный элемент в главном представлении? Если это так, вы можете ввести небольшую (скажем, 100 мс) задержку перед началом новой операции. Это может быть сделано с async код как таковой:

if (_tokenSource != null)
{
  _tokenSource.Cancel();
  _tokenSource = null;
}

var currentItem = _whateverView.CurrentItem;
await Task.Delay(TimeSpan.FromMilliseconds(100));
if (currentItem != _whateverView.CurrentItem)
  return null;

_tokenSource = new CancellationTokenSource();
try
{
  _unitOfWork = await loadRelatieAsync(relatieId, _tokenSource.Token);
  return null;
}
catch (OperationCanceledException ex)
{
}

Хотя я должен сказать, что если вы выполняете много "основанных на времени" операций (например, "задерживаете это действие на некоторый период времени" или "ограничиваете эти события на основе этого временного окна"), то более естественный подход будет Реактивные расширения.

Другие вопросы по тегам