如何实现非ui线程更新ui线程?
时间:2011-04-19 来源:qiang.xu
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()
相关阅读 更多 +