C# WinForm中Timer启动后Tick事件仅在方法结束后触发问题求助
问题根因
你使用的是WinForm原生的System.Windows.Forms.Timer,其Tick事件依赖UI线程的消息循环调度。当前recorrido方法同步运行在UI线程上,全程占用UI线程资源,导致Timer的消息无法被及时分发,只能等整个方法执行完成后才会处理积压的Tick事件。同时原有逻辑还存在缺陷:调用segundero启动Timer后没有等待执行完成,直接进入下一次循环,会覆盖SegundoTerminar等共享变量,就算Timer正常触发也会出现数值混乱。
修复方案
采用异步逻辑改造,不阻塞UI线程,同时等待单步Timer执行完成后再处理下一个批处理任务,代码改造示例如下:
Stopwatch oSW = new Stopwatch(); // 新增TaskCompletionSource用于等待Timer执行完成 TaskCompletionSource<bool> timerTcs; void segundero() { oSW.Reset(); oSW.Start(); timer1.Enabled = true; timer1.Start(); } // 改造为异步方法 async Task recorrido(int i) { int num1; int num2; int res = 0; for(int k =i; k<= i+3; k++) { if (k < NuProcesos) { num1 = ListOp1[k]; num2 = ListOp2[k]; if (Oper[k] == "+") { res = num1 + num2; } else if (Oper[k] == "-") { res = num1 - num2; } else if (Oper[k] == "*") { res = num1 * num2; } else if (Oper[k] == "/") { res = num1 / num2; } else if (Oper[k] == "%") { res = num1 % num2; } operacionactual = ListOp1[k].ToString() + Oper[k].ToString() + ListOp2[k] + " = " + res.ToString(); SegundoMenos = 0; SegundoTerminar = LisTime[k]; SegundoTerminar1 = LisTime[k]; loteproceso.Rows[0].Cells[0].Value = NombreP[k]; loteproceso.Rows[0].Cells[1].Value = operacionactual; loteproceso.Rows[0].Cells[2].Value = LisTime[k]; loteproceso.Rows[0].Cells[3].Value = IDNumero[k]; // 初始化等待源 timerTcs = new TaskCompletionSource<bool>(); segundero(); // 等待当前Timer执行完成再进入下一个任务 await timerTcs.Task; procesoterminado.Rows.Add(IDNumero[k], operacionactual, nlote); } } } private void timer1_Tick(object sender, EventArgs e) { TimeSpan ts = new TimeSpan(0, 0, 0, 0, (int)oSW.ElapsedMilliseconds); SegundoMenos = SegundoMenos + 1; SegundoTerminar = SegundoTerminar - 1; loteproceso.Rows[0].Cells[4].Value = SegundoTerminar; loteproceso.Rows[0].Cells[5].Value = SegundoMenos; if (SegundoTerminar==0) { oSW.Reset(); timer1.Enabled = false; // 通知等待的任务已完成 timerTcs.SetResult(true); } }
改造完成后,原来调用recorrido的地方需要改成await recorrido(参数),且调用方法需要标记为async。
内容的提问来源于stack exchange,提问作者CLAUDIO SEBASTIAN ORTEGA RAMIR
相关产品推荐
相关产品推荐

