WinForm关闭前延迟执行任务并更新RichTextBox问题求助
窗体关闭前的日志更新与延迟关闭问题解决
问题背景
我需要实现:当窗体在处理任务时被关闭,先更新RichTextBox显示日志、删除当前工作目录,再等待3秒后关闭窗体。但当前代码直接关闭窗体,无法实现延迟并显示日志;另外关闭窗体时更新日志会报错,因为RichTextBox已被释放,在Logger类的LogInternal方法的_richTextBox.SelectionStart = _richTextBox.TextLength;行抛出异常。
同时有两个疑问:
- 关闭窗体是否视为取消操作?
- 对话框是否会暂停窗体进程?
现有代码
窗体相关代码
private bool isCancelling = false;
FormClosing事件处理代码:
private async void Form1_FormClosing(object sender, FormClosingEventArgs e) { if (isCancelling) { // Already cancelling, let it continue return; } if (processingFrames) { // Set the flag to indicate that we are cancelling isCancelling = true; // Trigger the cancellation if (cancellationTokenSource != null) { cancellationTokenSource.Cancel(); } // Wait for a few seconds before closing the form int waitTimeInSeconds = 3; // You can adjust this as needed for (int i = waitTimeInSeconds; i > 0; i--) { logger.Log($"Cancelling in {i} seconds...", Color.Yellow); await Task.Delay(1000); } // Log the cancellation and close the form logger.Log("Session Cancelled at " + DateTime.Now.ToString("dd/MM/yyyy HH:mm"), Color.Red); logger.Log("", Color.Black); DeleteCurrentSession(); // Delete the current session folder e.Cancel = false; // Allow the form to close } else { // If not processing frames, allow the form to close immediately DeleteCurrentSession(); // Delete the current session folder e.Cancel = false; } }
Logger类代码
using System; using System.Collections.Generic; using System.Drawing; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace Test { public class Logger { private readonly RichTextBox _richTextBox; private bool saveToFile; // Added a flag to indicate whether to save to a file private string logFilePath = ""; public Logger(RichTextBox richTextBox, bool saveToFile = false) { _richTextBox = richTextBox; this.saveToFile = saveToFile; // Initialize the log file path in the constructor InitializeLogFilePath(); } private void InitializeLogFilePath() { string folderName = "Logs"; // Replace with the desired folder name string fileName = "log.txt"; // Replace with the desired file name // Set the log file path without creating the directory or file logFilePath = Path.Combine(Application.LocalUserAppDataPath, folderName, fileName); } public void Log(string message, Color textColor) { if (_richTextBox.InvokeRequired) { _richTextBox.Invoke((MethodInvoker)delegate { LogInternal(message, textColor); }); } else { LogInternal(message, textColor); } } private void LogInternal(string message, Color textColor) { _richTextBox.SelectionStart = _richTextBox.TextLength; _richTextBox.SelectionLength = 0; _richTextBox.SelectionColor = textColor; _richTextBox.AppendText(message + Environment.NewLine); _richTextBox.SelectionColor = _richTextBox.ForeColor; // Scroll to the caret (the end) _richTextBox.ScrollToCaret(); if (saveToFile) { SaveToFile(message); // Save to a file if the flag is set } } private void SaveToFile(string message) { try { // Ensure the directory exists, and create it if it doesn't string folderName = "Logs"; // Replace with the desired folder name string fileName = "log.txt"; // Replace with the desired file name // Application.LocalUserAppDataPath logFilePath = Path.Combine(Application.LocalUserAppDataPath, folderName, fileName); Directory.CreateDirectory(Path.Combine(Application.LocalUserAppDataPath, folderName)); // Append the message to the log file File.AppendAllText(logFilePath, message + Environment.NewLine); } catch (Exception ex) { // Handle any exceptions related to file I/O here Console.WriteLine("Error saving to log file: " + ex.Message); } } public string LogFilePath() { return logFilePath; } } }
解决方案
1. 修复延迟关闭不生效问题
问题核心是未先阻止窗体立即关闭。修改后的FormClosing事件代码:
private async void Form1_FormClosing(object sender, FormClosingEventArgs e) { if (isCancelling) { return; } if (processingFrames) { e.Cancel = true; // 先阻止窗体关闭 isCancelling = true; cancellationTokenSource?.Cancel(); int waitTimeInSeconds = 3; for (int i = waitTimeInSeconds; i > 0; i--) { logger.Log($"Cancelling in {i} seconds...", Color.Yellow); await Task.Delay(1000); } logger.Log($"Session Cancelled at {DateTime.Now:dd/MM/yyyy HH:mm}", Color.Red); logger.Log("", Color.Black); DeleteCurrentSession(); // 所有操作完成后手动关闭窗体 this.Close(); } else { DeleteCurrentSession(); e.Cancel = false; } }
2. 修复RichTextBox已释放的异常问题
在Logger类中增加控件状态检查,避免操作已释放的控件:
public void Log(string message, Color textColor) { if (_richTextBox.IsDisposed || !_richTextBox.IsHandleCreated) { if (saveToFile) { SaveToFile(message); } return; } if (_richTextBox.InvokeRequired) { _richTextBox.Invoke((MethodInvoker)delegate { LogInternal(message, textColor); }); } else { LogInternal(message, textColor); } } private void LogInternal(string message, Color textColor) { if (_richTextBox.IsDisposed || !_richTextBox.IsHandleCreated) { if (saveToFile) { SaveToFile(message); } return; } _richTextBox.SelectionStart = _richTextBox.TextLength; _richTextBox.SelectionLength = 0; _richTextBox.SelectionColor = textColor; _richTextBox.AppendText(message + Environment.NewLine); _richTextBox.SelectionColor = _richTextBox.ForeColor; _richTextBox.ScrollToCaret(); if (saveToFile) { SaveToFile(message); } }
疑问解答
- 关闭窗体是否视为取消操作:是的,用户关闭正在处理任务的窗体属于主动取消任务的场景,现有逻辑将其作为取消操作处理是合理的。
- 对话框是否会暂停窗体进程:模态对话框(如
MessageBox.Show())会阻塞当前UI线程,直到用户关闭对话框,但后台非UI线程的任务不受影响;非模态对话框则不会暂停UI线程。你的场景中,用延迟+日志更新的方式无需用户额外操作,体验更友好。
内容的提问来源于stack exchange,提问作者Daniel Lip
相关产品推荐
相关产品推荐

