C# WinForm点击按钮强制终止ParseXlM类文件解析处理任务方法
实现方案
核心思路
使用.NET 自带的CancellationTokenSource+CancellationToken实现协作式取消,同时将长时间运行的解析逻辑放到后台线程执行,避免阻塞UI导致取消按钮无法响应。协作式取消是业务逻辑主动判断取消信号的方案,比强制终止线程更安全,不会出现资源泄漏、数据损坏的问题。
第一步:改造文件解析业务类
给解析方法新增取消令牌入参,在循环内主动判断是否收到取消信号:
namespace oarch.classes { public class ParseXlM { // 新增CancellationToken类型入参 public static DataTable ParseXlM2(string dbfFile, System.Text.Encoding readingEncoding,ListBox olistBox1,ListBox elistBox, System.Windows.Forms.Label nlabel, CancellationToken cancellationToken) { // 原有初始化逻辑省略 for (int i =0 ;;) { // 新增取消判断:收到取消信号则抛出异常终止执行 cancellationToken.ThrowIfCancellationRequested(); // 原有循环处理逻辑省略 // 注意:如果有更新UI的操作,需要用控件.Invoke回到主线程执行,避免跨线程异常 } // 原有返回逻辑省略 } } }
第二步:改造窗体代码,新增取消控制逻辑
先在窗体上新增终止按钮(名称设为btnCancel),再修改窗体代码如下:
namespace oarch.xmlSql { public partial class ReadXML : Form { // 全局声明取消令牌源,用于发送取消信号 private CancellationTokenSource _cts; public ReadXML() { InitializeComponent(); // 初始状态下取消按钮不可点击 btnCancel.Enabled = false; } // 原有解析触发按钮的点击事件,改造成异步方法 private async void buttiClick(object sender, EventArgs e) { _cts = new CancellationTokenSource(); // 任务执行中切换按钮状态 btnCancel.Enabled = true; butti.Enabled = false; DataTable parseResult = null; try { // 把解析逻辑放到后台线程执行,不阻塞UI parseResult = await Task.Run(() => { return classes.ParseXlM.ParseXlM2(FileNameStr, System.Text.Encoding.GetEncoding(eCodepage),listBox1,listBox2, label6, _cts.Token); }, _cts.Token); // 解析完成后的后续业务逻辑省略,比如绑定数据到控件 } catch (OperationCanceledException) { MessageBox.Show("文件解析已被手动终止"); } catch (Exception ex) { MessageBox.Show($"解析出错:{ex.Message}"); } finally { // 释放资源,恢复按钮状态 _cts.Dispose(); btnCancel.Enabled = false; butti.Enabled = true; } } // 新增终止按钮的点击事件 private void btnCancel_Click(object sender, EventArgs e) { // 发送取消信号 _cts?.Cancel(); } } }
注意事项
- 解析逻辑里如果有直接操作UI控件的代码,必须改为通过控件
Invoke方法封送到主线程执行,否则会抛出跨线程操作异常 - 循环内的取消判断尽量放在每次迭代的最开头,保证取消请求可以被及时响应
- 禁止使用
Thread.Abort这类强制终止线程的方法,会导致文件句柄未释放、内存泄漏等不可预期的问题
内容的提问来源于stack exchange,提问作者Ahmad101
相关产品推荐
相关产品推荐

