如何实现非ui线程更新ui线程?

1. 实现非ui线程更新ui线程的代码

2. 编码中出现的一个错误及探究

<1>. 实现非ui线程更新ui线程

之前的基本做法是使用Invoke实现,这里采用的是 .net 4.0中的Task来实现,代码如下:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading.Tasks;
using System.Threading;
namespace WindowsFormsApplication1 {
public partial class Form1 : Form {
private readonly TaskScheduler m_syncContextScheduler = null;
public Form1() {
InitializeComponent();
base.Text = "Synchronization context task scheduler demo";
base.Visible = true;
base.Height = 100;
base.Width = 400;
// 属性m_syncContextScheduler需要在这里初始化
m_syncContextScheduler =
TaskScheduler.FromCurrentSynchronizationContext();
}
private CancellationTokenSource cts;
private TaskScheduler context = TaskScheduler.Current;
// 计算
private Int32 Sum(CancellationToken token, Int32 n) {
Int32 sum = 0;
for (Int32 i = 1; i <= n; ++i) {
// 出于演示目的,这里休眠一段时间
Thread.Sleep(1000);
sum += i;
}
return sum;
}
protected override void OnMouseClick(MouseEventArgs e) {
if (this.cts != null) {
// 开始取消操作
cts.Cancel();
this.cts = null;
}
else {
// 操作还没有开始,启动任务
this.Text = "Operation running";
this.cts = new CancellationTokenSource();
var t = new Task<Int32>
(
() => Sum(cts.Token, 10),
cts.Token
);
t.Start();
// 如果该任务结束的话,启动新任务,更新ui线程
t.ContinueWith(task => Text = "Result :" + t.Result,
CancellationToken.None,
TaskContinuationOptions.OnlyOnRanToCompletion,
this.m_syncContextScheduler);
// 如果是取消的话
t.ContinueWith(task => Text = "Operation cancel",
CancellationToken.None,
TaskContinuationOptions.OnlyOnCanceled,
this.m_syncContextScheduler);
// 如果出现错误
t.ContinueWith(task => this.Text = "Operation cancel",
CancellationToken.None,
TaskContinuationOptions.OnlyOnFaulted,
this.m_syncContextScheduler);
}
base.OnMouseClick(e);
}
}
}

<2>. 编码中出现的错误及探究

最初的代码将m_syncContextScheduler对象是通过下面的语句产生的:

private readonly TaskScheduler m_syncContextScheduler =

TaskScheduler.FromCurrentSynchronizationContext();

debug时,产生如下错误:

通过异常信息可以看出这可能是当前初始化还为完成,那么这就引出c#中构造函数初始化和属性的初始化顺序的问题,通过调试或者是查看生成的il代码发现了问题所在,c#中首先执行

private TaskScheduler m_syncContextScheduler =
TaskScheduler.FromCurrentSynchronizationContext();

此时环境还没有初始话完成。il中更加明显:

.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// Code size 87 (0x57)
.maxstack 2
IL_0000: ldarg.0
IL_0001: ldnull
IL_0002: stfld class [System]System.ComponentModel.IContainer WindowsFormsApplication1.Form1::components
IL_0007: ldarg.0
IL_0008: call class [mscorlib]System.Threading.Tasks.TaskScheduler [mscorlib]System.Threading.Tasks.TaskScheduler::FromCurrentSynchronizationContext()
IL_000d: stfld class [mscorlib]System.Threading.Tasks.TaskScheduler WindowsFormsApplication1.Form1::m_syncContextScheduler
IL_0012: ldarg.0
IL_0013: call class [mscorlib]System.Threading.Tasks.TaskScheduler [mscorlib]System.Threading.Tasks.TaskScheduler::get_Current()
IL_0018: stfld class [mscorlib]System.Threading.Tasks.TaskScheduler WindowsFormsApplication1.Form1::context
IL_001d: ldarg.0
// 初始化,调用form构造函数
IL_001e: call instance void [System.Windows.Forms]System.Windows.Forms.Form::.ctor()