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

    技术2022-05-19  20

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


    最新回复(0)