这些代码会产生这个错误:
跨线程操作无效:控制'progressBar2'从其创建的线程以外的线程访问。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;
namespace ThreadingTest1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
ThreadStart ts1;
ThreadStart ts2;
Thread t1;
Thread t2;
private void btnStart_Click(object sender, EventArgs e)
{
ts1 = new ThreadStart(z1);
ts2 = new ThreadStart(z2);
t1 = new Thread(ts1);
t2 = new Thread(ts2);
t1.Start();
t2.Start();
btnStart.Enabled = false;
}
public void z1()
{
for (int i = 1; i < 60; ++i)
{
progressBar1.Value += 1;
for (int j = 1; j < 10000000; ++j)
{
j += 1;
}
}
}
public void z2()
{
for (int k = 1; k < 100; ++k)
{
progressBar2.Value += 1;
for (int j = 1; j < 25000000; ++j)
{
j += 1;
}
}
}
private void btnstop_Click(object sender, EventArgs e)
{
t1.Suspend();
t2.Suspend();
}
private void btnContinue_Click(object sender, EventArgs e)
{
t1.Resume();
t2.Resume();
}
private void btnClose_Click(object sender, EventArgs e)
{
if (t1.IsAlive)
{
MessageBox.Show("Çalışan threadler var program sonlanamaz.");
}
else
{
this.Close();
}
}
}
}
答案 0 :(得分:7)
您无法访问负责该控件的UI线程以外的线程中的UI控件。
请参阅我的线程教程中的WinForms页面,并在BackgroundWorker
上搜索教程,这是.NET 2.0中引入的一个组件,它使生活更加轻松(特别是对于进度条)。
此外,我会尽量避免使用Thread.Suspend
/ Resume
,而是采用更合作的方式(例如Monitor.Wait
/ Pulse
)。这样可以避免在持有锁等时挂起线程
答案 1 :(得分:1)
对于z1和z2这样做: 添加zSafe() 在InvokeRequired检查之后,在z()内调用zSafe()。
public void z1Safe()
{
for (int i = 1; i < 60; ++i)
{
progressBar1.Value += 1;
for (int j = 1; j < 10000000; ++j)
{
j += 1;
}
}
}
public void z1()
{
if (this.InvokeRequired)
{
this.Invoke((MethodInvoker)delegate { z1Safe(); });
}
else
z1Safe();
}
我刚刚在我的Windows窗体中为asyn del call实现了一个类似的解决方案,它运行正常。
答案 2 :(得分:0)
当您处理多线程应用程序时,交叉线程异常非常常见,当您尝试在除其自己的线程之外的线程中调用控件的成员时,它会发生。为了避免这种情况,您可以检查该控件的InvokeRequired属性并在其自己的线程中调用委托或使用BackgroundWorker在后台运行进程(另一个线程)并处理其事件,当您处理BackgroundWorker事件时,事件处理程序方法将在主线程上运行,因此不需要调用委托
Here您可以找到有关BackgroundWorker的一些信息