C# WinForm等待窗体关闭时终止任务的实现方案咨询
解决WinForm Excel处理任务的终止问题
需求说明
开发WinForm应用处理大型Excel文件,执行任务时显示等待窗体。要求:点击等待窗体关闭按钮时弹出确认框,确认后终止当前任务但不退出主程序,后续可重新发起处理。
关键实现步骤
1. 改造等待窗体(PleaseWait)
添加公共属性标记用户是否确认终止任务,保留原有的关闭确认逻辑:
public partial class PleaseWait : Form { public bool IsCancellationConfirmed { get; private set; } = false; private void PleaseWait_FormClosing(object sender, FormClosingEventArgs e) { var result = MessageBox.Show("确定要终止任务吗?", "确认终止", MessageBoxButtons.YesNo, MessageBoxIcon.Question); if (result == DialogResult.No) { e.Cancel = true; IsCancellationConfirmed = false; } else { IsCancellationConfirmed = true; e.Cancel = false; } } }
2. 在主窗体(Home.cs)中集成CancellationToken
使用CancellationTokenSource控制任务取消,监听等待窗体关闭事件,在用户确认终止时触发取消信号:
private CancellationTokenSource _cts; private async void btnClick() { try { _cts = new CancellationTokenSource(); var pleaseWait = new PleaseWait(); // 监听等待窗体关闭事件,确认终止则取消任务 pleaseWait.FormClosed += (s, e) => { if (pleaseWait.IsCancellationConfirmed) { _cts.Cancel(); } }; pleaseWait.Show(); // 传入CancellationToken执行异步任务 await Task.Run(() => ProcessBookstoreExcel(_cts.Token), _cts.Token); pleaseWait.Close(); MessageBox.Show("处理完成!"); } catch (OperationCanceledException) { MessageBox.Show("任务已终止"); } catch (Exception ex) { MessageBox.Show($"处理出错:{ex.Message}"); } finally { _cts?.Dispose(); // 确保等待窗体关闭 foreach (Form form in Application.OpenForms) { if (form is PleaseWait) { form.Close(); } } } }
3. 修改Excel处理方法,加入取消检查
在ProcessBookstoreExcel中接受CancellationToken,在耗时循环步骤中检查取消信号,及时终止任务:
private void ProcessBookstoreExcel(CancellationToken cancellationToken) { string path = TxtBox.Text; ExcelPackage.LicenseContext = LicenseContext.NonCommercial; var records = new List<BookRecord>(); using (var package = new ExcelPackage(new FileInfo(path))) { ExcelWorksheet worksheet = package.Workbook.Worksheets[0]; int rowCount = worksheet.Dimension.Rows; for (int row = 2; row <= rowCount; row++) { // 每次循环检查是否取消,若已取消则抛出异常终止任务 cancellationToken.ThrowIfCancellationRequested(); records.Add(new BookRecord { LineNumber = row, ISBN = worksheet.Cells[row, 1].Text, Title = worksheet.Cells[row, 2].Text, Stock = int.Parse(worksheet.Cells[row, 3].Text), Price = decimal.Parse(worksheet.Cells[row, 4].Text), PublisherID = int.Parse(worksheet.Cells[row, 5].Text), PublisherName = worksheet.Cells[row, 6].Text }); } } var discrepancies = new List<Discrepancy>(); var groupedRecords = new Dictionary<string, Dictionary<string, (decimal Price, int Stock)>>(); foreach (var record in records) { // 处理记录时也检查取消信号 cancellationToken.ThrowIfCancellationRequested(); var publisherKey = record.PublisherID.ToString(); var isbnKey = record.ISBN; if (!groupedRecords.ContainsKey(publisherKey)) { groupedRecords[publisherKey] = new Dictionary<string, (decimal Price, int Stock)>(); } if (!groupedRecords[publisherKey].ContainsKey(isbnKey)) { groupedRecords[publisherKey][isbnKey] = (record.Price, record.Stock); } else { var existing = groupedRecords[publisherKey][isbnKey]; if (existing.Price != record.Price || existing.Stock != record.Stock) { discrepancies.Add(new Discrepancy { LineNumber = record.LineNumber, Publisher = record.PublisherName, Title = record.Title }); } } } // 取消时不执行写入操作 cancellationToken.ThrowIfCancellationRequested(); WriteDiscrepancies(discrepancies); MessageBox.Show("处理完成,请查看输出文件中的差异记录。"); }
4. 核心注意点
- 必须在耗时循环中插入取消检查,确保任务能及时响应终止请求;
cancellationToken.ThrowIfCancellationRequested()会抛出OperationCanceledException,上层捕获后可给出终止提示;- 任务取消后
finally块自动清理资源并关闭等待窗体,避免泄漏; - 取消后不会执行写入操作,避免生成不完整的输出文件。
内容的提问来源于stack exchange,提问作者Anonymous
相关产品推荐
相关产品推荐

