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

本文介绍了一种使用.NET 4.0中的Task而非传统Invoke方法实现非UI线程更新UI线程的技术方案,并探讨了初始化阶段可能出现的错误及其原因。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值