C#非控制台场景下如何按ESC键随时退出while循环
C# 非控制台场景下给循环添加ESC退出逻辑实现方案
前置注意
你当前的代码直接在UI线程执行while死循环会阻塞Windows消息队列,导致界面卡死、按键事件无法响应,优先推荐用后台线程执行循环逻辑的方案,避免阻塞UI。
实现步骤
第一步:添加ESC按键监听
首先将窗体的KeyPreview属性设置为true,让窗体优先接收按键消息,然后添加类级别标记字段和按键事件处理:
// 窗体类级别字段,标记ESC是否被按下 private bool _isEscPressed = false; // 窗体KeyDown事件处理方法 private void MainForm_KeyDown(object sender, KeyEventArgs e) { if (e.KeyCode == Keys.Escape) { _isEscPressed = true; e.Handled = true; } }
第二步:改造循环逻辑(推荐后台线程方案)
将循环放到后台线程执行,涉及UI操作的部分通过Invoke封送回UI线程,避免跨线程访问异常:
// 进入循环前重置标记 _isEscPressed = false; wechsel = true; // 后台线程执行循环逻辑 _ = Task.Run(() => { while (wechsel && !_isEscPressed) { ProfDpDrv.MDPReadSlaveData(SlaveAddress, resetdiag, out dpData); newStatus = dpData.m_InputData[i]; if (newStatus == 1) { // 操作UI控件必须封送回UI线程 this.Invoke(new Action(() => { int debug = e.RowIndex; Dgv_Data_List.Rows[e.RowIndex].Cells["Adresse"].Style.BackColor = Color.Green; Dgv_Data_List.Refresh(); })); wechsel = false; } // 可根据业务需求调整延迟,避免CPU占用过高 Thread.Sleep(10); } });
可选方案:同步循环加消息处理(不推荐)
如果不想改动线程逻辑,可以在循环内调用Application.DoEvents()处理消息队列,但是存在UI重入、多次触发逻辑等风险:
// 进入循环前重置标记 _isEscPressed = false; wechsel = true; while (wechsel && !_isEscPressed) { ProfDpDrv.MDPReadSlaveData(SlaveAddress, resetdiag, out dpData); newStatus = dpData.m_InputData[i]; if (newStatus == 1) { int debug = e.RowIndex; Dgv_Data_List.Rows[e.RowIndex].Cells["Adresse"].Style.BackColor = Color.Green; Dgv_Data_List.Refresh(); wechsel = false; } // 处理UI消息,让按键事件能被响应 Application.DoEvents(); // 降低CPU占用 Thread.Sleep(10); }
注意事项
- bool类型的读写本身是原子操作,
_isEscPressed字段不需要额外加锁 - 如果
MDPReadSlaveData是阻塞调用,ESC按下后需要等该方法返回才会退出循环,可根据需要给读取方法添加超时逻辑 - 后台线程方案如果需要在循环结束后执行UI操作,同样需要通过
Invoke封送回UI线程
内容的提问来源于stack exchange,提问作者and95y
相关产品推荐
相关产品推荐

