现在的位置: 首页 > 综合 > 正文

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

2012年09月25日 ⁄ 综合 ⁄ 共 3444字 ⁄ 字号 评论关闭

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()

 

【上篇】
【下篇】

抱歉!评论已关闭.