在winfrom开发过程中有时候会遇到在子线程中操作UI线程的操作,这个时候如果在子线程中直接操作控件的话会有下面的错误发生。如下图所示:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Thread myThread = new Thread(new ThreadStart(SetText));
myThread.Start();
}
private void SetText()
{
textBox1.Text = "this is MyText!";
}
}
这段代码运行之后会直接报错:
那也就是说在winfrom中我们是不能直接操作UI线程的。那该怎么操作呢?
在微软官方文档中推荐使用两种方式:
1、使用委托
public partial class delegateFrom : Form
{
private delegate void SafeCallMoteod();
public delegateFrom()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
if (textBox1.InvokeRequired)
{
var d = new SafeCallMoteod(SetText);
textBox1.Invoke(d, null);
}
else
{
SetText();
}
Thread myThread = new Thread(new ThreadStart(SetText));
myThread.Start();
}
private void SetText()
{
textBox1.Text = "this is MyText!";
}
/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
private static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new delegateFrom());
}
该段代码可以正常显示:
2、另外一种可以采用BackgroundWorker来操作,示例如下:
注:使用BackgroundWorker可以直接从工具箱中拖一个。
BackGroundWork有这三个事件,我们可以通过监听这三个事件来达到我们的目的:
详细代码如下:
public partial class frmBackgroundWorker : Form
{
public frmBackgroundWorker()
{
InitializeComponent();
this.backgroundWorker1.WorkerReportsProgress = true;
this.backgroundWorker1.WorkerSupportsCancellation = true;
}
private void btnStart_Click(object sender, EventArgs e)
{
btnStart.Enabled = false;
backgroundWorker1.RunWorkerAsync();
btnCancle.Enabled = true;
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
for (int i = 0; i <= 20; i++)
{
if ((sender as BackgroundWorker).CancellationPending)
{
e.Cancel = true;
break;
}
else
{
Thread.Sleep(1000);
(sender as BackgroundWorker).ReportProgress(i * 5);
e.Result = txtValue.Text + i.ToString();
}
}
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
{
MessageBox.Show(e.Error.Message);
}
else if (e.Cancelled)
{
txtValue.Text = "Canceled";
}
else
{
// Finally, handle the case where the operation
// succeeded.
txtValue.Text = e.Result.ToString();
}
}
private void btnCancle_Click(object sender, EventArgs e)
{
btnCancle.Enabled = false;
backgroundWorker1.CancelAsync();
btnStart.Enabled = true;
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
//获取异步任务执行的百分比
progressBar1.Value = e.ProgressPercentage;
}
/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
private static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new frmBackgroundWorker());
}
}
}
个人感觉BackGroundWork这种事件回调的处理方式更优雅一些。