在Windows Forms中,由于UI控件不是线程安全的,直接跨线程访问和修改UI控件通常会导致不可预测的行为或异常。TextBox
控件同样不能直接从非创建它的线程进行写入。为了安全地在不同线程间更新 TextBox
控件的内容,你可以使用控件的 Invoke
方法或 BeginInvoke
方法来在控件的拥有线程(通常是主UI线程)上执行操作。
以下是一个扩展 TextBox
控件的简单示例,它提供了一个线程安全的方法来更新文本内容:
using System;
using System.Threading;
using System.Windows.Forms;
public class SafeTextBox : TextBox
{
// 委托,用于定义在UI线程上执行的方法签名
public delegate void SafeSetTextCallback(string text);
// 公有方法,用于安全地设置TextBox的Text属性
public void SafeSetText(string text)
{
// 检查调用线程是否是创建控件的线程
if (this.InvokeRequired)
{
// 如果不是,则使用Invoke在正确的线程上执行
//方法1 测试通过1
//SafeSetTextCallback d = new SafeSetTextCallback(SafeSetText);
//this.Invoke(d, new object[] { text });
//方法2 测试通过2
//Action<string> dlg = new Action<string>(SafeSetText);
//this.Invoke(dlg, text);
//方法3 测试通过3
this.Invoke(new Action<string>(SafeSetText), text);
}
else
{
// 如果是,则直接设置Text属性
this.Text = text;
}
}
}
// 使用示例
public partial class MainForm : Form
{
private SafeTextBox safeTextBox;
public MainForm()
{
InitializeComponent();
safeTextBox = new SafeTextBox();
safeTextBox.Dock = DockStyle.Fill;
this.Controls.Add(safeTextBox);
// 在一个后台线程中更新TextBox
Task.Run(() =>
{
// 模拟一些工作
Thread.Sleep(1000);
// 安全地更新TextBox的文本
safeTextBox.SafeSetText("这是从后台线程安全地写入的文本!");
});
}
}
在上面的代码中,SafeTextBox
类继承自 TextBox
类,并添加了一个名为 SafeSetText
的方法。这个方法接受一个字符串参数,并使用一个委托来在UI线程上安全地设置 TextBox
的 Text
属性。如果调用 SafeSetText
的线程不是创建 TextBox
的线程(即主UI线程),则通过 Invoke
方法在正确的线程上执行该操作。如果是主UI线程,则直接设置 Text
属性。
使用 SafeTextBox
控件与使用普通的 TextBox
控件类似,但是你可以通过调用 SafeSetText
方法来安全地在后台线程中更新其文本内容。
注意:虽然上面的代码示例适用于Windows Forms应用程序,但如果你正在使用WPF或其他类型的UI框架,实现方式可能会有所不同。在WPF中,你通常会使用 Dispatcher.Invoke
或 Dispatcher.BeginInvoke
来在UI线程上执行操作。
参考链接
特此记录
anlog
2024年2月23日