如何实现非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构造函数
// 初始化,调用form构造函数
IL_001e: call instance void [System.Windows.Forms]System.Windows.Forms.Form::.ctor()
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?