2014-12-03 5 views
1

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

ObservableCollection<Dictionary<string, string>> gridData; 
ObservableCollection<Dictionary<string, string>> GridData; 
{ 
    get 
    { 
     return gridData; 
    } 
    set 
    { 
     this.gridData = value; 
     NotifyPropertyChanged(); 
    } 
} 

Вышеуказанное свойство привязано к GridControl (Devexpress WPF).

Ниже представлен асинхронный метод, который отвечает за визуализацию данных из задней службы.

public async void RefresRecords() 
{ 
    await GetRecords(); 
} 

private async Task GetRecords() 
{ 
    int offset = 0; 
    int limit = 50; 

    do 
    { 
     var dummyData = await GetRangeRecord(offset, limit); 
     GridData.Add(dummyData); 

     offset += limit; 

    } while (GridData.Count() < 1000); 
} 

private Task<Dictionary<string, string>> GetRangeRecord(int offset, int limit) 
{ 
    // This method does processing and returns records from offset to limit 
    return new Task<Dictionary<string, string>>(); 
} 

От задней службы может быть огромное количество данных, но я хочу показать только 1000 записей.

Записи будут отобраны в куске по 50 записей за звонок. Когда свойство привязано, пользовательский интерфейс будет обновляться одновременно.

Теперь рассмотрим случай использования, как показано ниже: -

Шаг 1: - Вызов приходит метод ASYN "RefresRecords". Предположим, что из бэкэнд-сервиса выдается 1000 записей. Таким образом, этот метод будет зацикливаться 20 раз и отобразит 50 записей на вызов службы.

Этап 2: - Пока шажок 1 находится в процессе, так как он является асинхронным, другой вызов приходит для одного и того же метода асинхронизации «RefreshRecords».

Результат: - После шага 2 сетка будет загружена данными из извлеченных данных этапа 2, а также некоторой частью шага 1, поскольку одно и то же свойство изменяется в двух последующих вызовах метода asyn.

Вопрос: - Каков наилучший способ полностью остановить Step1, когда есть новый вызов для того же метода.

+1

Либо использовать 'CancellationToken', чтобы позволить первый вызов будет отменен или отключить дубликат операции, чтобы предотвратить его от вмешательства (например, отключить любую часть пользовательского интерфейса вызывает это произойдет, просто игнорировать его, если требуется, поставите его так, чтобы он начинался только после первого окончания и т. д.).К сожалению, я не могу сказать, что вопрос включает достаточно контекста, чтобы знать, какой из этих вариантов может быть предпочтительным в вашем случае. Здесь много вариантов. –

ответ

0

Вы можете использовать токены отмены для своих методов асинхронного использования. И когда вызывается метод GetRecords(), выполните команду GridData.Clear().

Это очень простая демонстрация, но надеюсь, что это поможет.

public static List<int> List = new List<int>(); 

    public static async Task AddToList(CancellationToken cancellation) 
    { 
     List.Clear(); 

     for (var i = 0; i < 100 && !cancellation.IsCancellationRequested; i++) 
     { 
      await Task.Delay(100, cancellation); 
      List.Add(i); 
     } 
    } 

    public static async Task MainAsync(CancellationToken cancellation) 
    { 
     await AddToList(cancellation); 
    } 

    private static void Main(string[] args) 
    { 
     var cts = new CancellationTokenSource(); 
     Task.Run(() => MainAsync(cts.Token), cts.Token); 

     Thread.Sleep(1000); 
     cts.Cancel(); 

     cts = new CancellationTokenSource(); 
     Task.Run(() => MainAsync(cts.Token), cts.Token).Wait(cts.Token); 

     Console.WriteLine(List.Count); 
     Console.Read(); 
    } 

Надеется, что это помогает
взгляда здесь более http://msdn.microsoft.com/en-us/library/dd997396(v=vs.110).aspx

+0

Мы используем dot net framework 4.0, это было по ошибке, помечено как 4.5 – Nilesh

+0

. Вы все равно можете передать объект отмены (с отмененным свойством) и выполнить проверку, если каждый раз, когда вы собираетесь добавить в grid – sQuir3l

+0

Спасибо, сработало – Nilesh

0

Один из способов сделать это, чтобы сохранить Task для RefreshRecords, а затем отменить его, если новый запрос поступает. Вам нужно будет изменить свой метод GetRecords, чтобы взять CancellationToken, и вам необходимо периодически проверять этот токен на отмену либо token.ThrowIfCancellationRequested (который выдает OperationCancelledException), либо путем проверки свойства token.IsCancellationRequested. Лучше позвонить token.ThrowIfCancellationRequested, так как это правильно переводит задачу в состояние «Отменено».

Вам также потребуется синхронизировать доступ к методу RefreshRecords и создать для каждого задания новый CancellationTokenSource. Вы можете использовать SemaphoreSlim для асинхронного ожидания завершения предыдущего запроса.

private Task refreshRecordsTask; 
private CancellationTokenSource cts = new CancellationTokenSource(); 
private SemaphoreSlim sempahore = new SemaphoreSlim(1,1); 

public async void RefreshRecords() 
{ 
    try 
    { 
     await sempahore.WaitAsync(); 

     if(refreshRecordsTask != null && !refreshRecordsTask.IsCompleted) 
     { 
      cts.Cancel(); 
      cts = new CancellationTokenSource();    
     } 

     refreshRecordsTask = GetRecords(cts.Token); 
    } 
    finally 
    { 
     sempahore.Release(); 
    } 

    await refreshRecordsTask; 
} 

private async Task GetRecords(CancellationToken token) 
{ 
    int offset = 0; 
    int limit = 50; 

    do 
    { 
     token.ThrowIfCancellationRequested(); 
     var dummyData = await GetRangeRecord(offset, limit); 
     GridData.Add(dummyData); 

     offset += limit; 

    } while (GridData.Count() < 1000); 
} 
+0

Мы используем dot net framework 4.0, это было по ошибке с тегом 4.5 – Nilesh

+0

Вы можете использовать AsyncCTP с http://www.microsoft.com/en-au/download/details.aspx?id= 9983 –

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