[C#.NET][TPL] 利用 TaskScheduler 跨執行緒更新 UI

[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);
}


錯誤資訊如下圖:

image

 

加上 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

Image result for microsoft+mvp+logo