我有一个负责渲染网格记录的类。
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个记录的大小提取。当属性绑定时,UI将同时刷新。
现在考虑用例如下: -
步骤1: - 呼叫来自asyn方法&#34; RefresRecords&#34;。假设从后端服务获取了1000条记录。因此,此方法将循环20次,每个服务调用将显示50条记录。
步骤2: - 当Step1正在进行同步调用时,另一个调用是针对相同的异步方法&#34; RefreshRecords&#34;。
结果: - 在第2步之后,网格将加载来自Step2的获取数据的数据以及Step1的某些部分,因为在随后的两个asyn方法调用中相同的属性被修改。
问题: - 当有相同方法的新调用时,完全停止Step1的最佳方法是什么。
答案 0 :(得分: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
答案 1 :(得分: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);
}