[C#.NET][TPL] 利用 TaskScheduler 跨執行緒更新 UI
TPL 中的 TaskScheduler.FromCurrentSynchronizationContext 可與目前的 UI 傳遞上下文,可用來處理跨執行緒更新,跟 SynchronizationContext 是一樣的意思,如果沒用過它的話,試著在我的Blog搜尋"SynchronizationContext"關鍵字,應該會找到一些訊息。
SumAsync 方法寫法如下:
private Task<long> SumAsync(CancellationToken cancellationToken)
{
long sum = 0;
return Task.Factory.StartNew(() =>
{
for (int i = 0; i < 100; i++)
{
if (cancellationToken.IsCancellationRequested)
{
break;
}
sum++;
SpinWait.SpinUntil(() => cancellationToken.IsCancellationRequested, 100);
}
return sum;
}, cancellationToken);
}
當我們接續任務時會跳出例外錯誤
private void button_SumAsync_Click(object sender, EventArgs e)
{
this._cts = new CancellationTokenSource();
var mainTask = SumAsync(this._cts.Token);
mainTask.ContinueWith(task =>
{
this.label2.Text = task.Result.ToString();
}, _cts.Token);
}
錯誤資訊如下圖:
加上 TaskScheduler ,便可以處理跨執行緒的問題
private void button_SumAsync_Click(object sender, EventArgs e)
{
TaskScheduler scheduler = TaskScheduler.FromCurrentSynchronizationContext();
this._cts = new CancellationTokenSource();
var mainTask = SumAsync(this._cts.Token);
mainTask.ContinueWith(task =>
{
this.label2.Text = task.Result.ToString();
}, _cts.Token, TaskContinuationOptions.OnlyOnRanToCompletion, scheduler);
}
這其實不難,若還是看不懂,再看以下例子
private Task<string> DownloadStringAsync(string address, CancellationToken cancellationToken)
{
var tcs = new TaskCompletionSource<string>();
WebClient wc = new WebClient();
wc.DownloadStringCompleted += (sender, e) =>
{
if (cancellationToken.IsCancellationRequested)
{
tcs.TrySetCanceled();
}
if (e.Cancelled)
tcs.TrySetCanceled();
else if (e.Error != null)
tcs.TrySetException(e.Error);
else
tcs.TrySetResult(e.Result);
};
wc.DownloadStringAsync(new Uri(address));
return tcs.Task;
}
private void button_DownloadStringAsync_Click(object sender, EventArgs e)
{
TaskScheduler scheduler = TaskScheduler.FromCurrentSynchronizationContext();
this._cts = new CancellationTokenSource();
var mainTask = DownloadStringAsync("https://www.google.com.tw/", this._cts.Token);
mainTask.ContinueWith(task =>
{
if (task.IsCanceled)
this.label2.Text = "Cancel";
else if (task.IsFaulted)
this.label2.Text = "Error";
else
this.label2.Text = task.Result.ToString();
}, this._cts.Token, TaskContinuationOptions.None, scheduler);
}
範例下載:https://dotblogsfile.blob.core.windows.net/user/yc421206/1308/201387154327528.zip
本文出自:http://www.dotblogs.com.tw/yc421206/archive/2013/08/07/113652.aspx
若有謬誤,煩請告知,新手發帖請多包涵
Microsoft MVP Award 2010~2017 C# 第四季
Microsoft MVP Award 2018~2022 .NET