Windows Forms 应用程序中的后台任务与UI响应性

在开发Windows Forms应用程序时,经常会遇到需要在后台执行长时间运行的任务。这些任务可能会阻塞UI线程,导致用户界面变得无响应。为了通知用户后台任务正在进行,需要显示一个加载指示器。这个指示器可以是一个简单的动画图像(GIF图像)。本文将介绍如何在Windows Forms中实现这一功能。

设计表单

首先,在Visual Studio中创建一个新的Windows Forms项目。然后,通过拖放Label、Button、ComboBox和DataGridView控件到Windows表单上,创建一个类似于下图的表单。

在表单的中心添加一个PictureBox控件,并将"Image"和"InitialImage"属性设置为加载图像。可以通过Visual Studio属性窗口导入图像。具体操作是,点击"Initial Image"值旁边的"..."按钮,打开"Select Resource"窗口。选择"Project resource file"选项,然后点击"Import..."按钮。选择加载图像,然后点击"Open"和"Ok"按钮。重复相同的过程来设置PictureBox控件的"Image"属性。

核心功能

当用户点击"Find"按钮时,希望显示一个加载指示器,以便用户知道后台操作正在进行。加载指示器的显示如下:

后台操作完成后,加载图像被隐藏,数据被加载到网格中。以下是数据加载到网格的表单截图。

使用代码

当用户点击"Browse..."按钮时,希望显示一个对话框,从中可以选择文本文件。以下是用于显示文件打开对话框的代码,并进行了自定义。注意添加到文件打开对话框的"Title"和"Filter"。

var dialog = new OpenFileDialog(); dialog.Title = "Browse Text Files"; dialog.DefaultExt = "txt"; dialog.CheckFileExists = true; dialog.Filter = "Text files (*.txt)|*.txt|All files (*.*)|*.*"; dialog.Multiselect = false; dialog.ShowDialog(); var fileName = dialog.FileName; txtFilePath.Text = fileName;

以下是用于显示加载图像的代码,该图像位于PictureBox控件内。注意代码被放在this.Invoke()内。

private void SetLoading(bool displayLoader) { if (displayLoader) { this.Invoke((MethodInvoker)delegate { picLoader.Visible = true; this.Cursor = System.Windows.Forms.Cursors.WaitCursor; }); } else { this.Invoke((MethodInvoker)delegate { picLoader.Visible = false; this.Cursor = System.Windows.Forms.Cursors.Default; }); } }

上述代码用于显示加载图像,当显示加载图像时,光标会更改为"wait"光标。

为了保持UI的响应性,整个操作在新线程中进行。

private void btnFind_Click(object sender, EventArgs e) { try { Thread threadInput = new Thread(DisplayData); threadInput.Start(); } catch (Exception ex) { DisplayError(ex); } }

DisplayData()方法执行所有操作,如调用显示/隐藏加载图像的方法,从文件中读取数据,查找字符并绑定到网格。

private void DisplayData() { SetLoading(true); // Do other operations... SetLoading(false); }

第一行显示加载指示器。接下来的操作紧随其后,最后隐藏加载指示器。

不能直接从控件中读取数据,因为整个操作在单独的线程中进行。如果尝试直接在DisplayData()方法中读取ComboBox的值,它将抛出无效的跨线程操作错误。

var charType = cmbCharacterType.Text; InvalidOperationException: Cross-thread operation not valid: Control 'cmbCharacterType' accessed from a thread other than the thread it was created on. this.Invoke((MethodInvoker)delegate { charType = cmbCharacterType.Text; path = txtFilePath.Text.Trim(); });
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485