我有两个看起来像这样的线程
pbDB_running = true; // start progress bar
Thread connectDb = new Thread(new ThreadStart(ConnectToDb));
Thread runProgress = new Thread(new ThreadStart(RunpbDB));
connectDb.Start();
runProgress.Start();
connectDb.Join(); //wait untill the connection is done
pbDB_running = false; //stop the progress bar
正如您可能已经猜到的那样,ConnectToDb用于建立与数据库的连接,而runpbDB正在接口上运行进度条。进度条(pbDB)是在设计视图上通过拖放创建的Windows.Forms控件。 runProgress线程正在运行RunpbDB(),如下所示:
private void RunpbDB()
{
while (pbDB_running)
{
if (pbDB.Value == 100) pbDB.Value = 0;
else pbDB.Value += 1;
}
pbDB.Value = 0;
}
当两个线程启动时,我在RunpbDB()中得到以下异常:
Cross-thread operation not valid: Control 'pbDB' accessed from a thread other than the thread it was created on.
我可以做些什么来克服这种情况?
答案 0 :(得分:2)
您是否考虑过使用BackgroundWorker
?这可能会让您的生活更轻松。您可以设置两个,一个用于数据库调用,另一个用于进度条。只需听取后台工作人员ProgressChanged
和RunWorkerCompleted
事件。
有关MSDN
的更多信息答案 1 :(得分:1)
使用Control.Invoke方法解决此问题。整个解决方案将成为
private void RunpbDB()
{
while (pbDB_running)
{
Invoke((Action)(()=>{
if (pbDB.Value == 100) pbDB.Value = 0;
else pbDB.Value += 1;}));
}
Invoke((Action)(()=>{pbDB.Value = 0;});
}
答案 2 :(得分:1)
您可以使用pbDB.InvokeRequired
的内容,如果是这样,请调用pbDB.Invoke
在UI线程上执行操作。
如果您知道它将始终在与UI线程不同的线程上完成,则不需要检查。
Here is a link to some code on this and other ways to accomplish this.
您还可以使用BackgroundWorker
答案 3 :(得分:1)
这是微软为其.NET技术强加的安全性。它主要发生在从单独的线程访问winforms元素时,即不在GUI winforms正在运行的主线程中。解决方案是为您的RunpbDB
方法创建委托。请参阅此处的解决方案Best Way to Invoke Any Cross-Threaded Code?。在这里:How to update the GUI from another thread in C#?
答案 4 :(得分:1)
如果您无法访问.NET 4.0,只需让您的生活更轻松,并使用BackgroundWorker
。如果您可以使用4.0+,请使用TPL。如果可以使用4.5,则可以使用新的async / await功能。 Stack Overflow上有很多例子。 Here是Stephen Cleary的一个链接,用来比较它们。
答案 5 :(得分:0)
VS团队在2.0中不鼓励涉及UI线程时的跨线程操作调用(之前可能出于安全原因。有两种方法可以解决这个问题。简单的方法是设置静态属性
System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls
为false,然后从您的应用程序全局禁用此检查。但是这个解决方案并没有被任何人建议,甚至我也没有建议,因为它再次打开了安全漏洞。 另一种方法是,在方法中首先检查UI控件是否需要Invoke,如果是,则使用control的invoke方法再次调用当前方法然后返回。代码可以更好地清除我想说的内容
private void RunpbDB()
{
if (pbDB.InvokeRequired)
{
pbDB.Invoke(new Action(RunpbDB));
return;
}
while (pbDB_running)
{
if (pbDB.Value == 100) pbDB.Value = 0;
else pbDB.Value += 1;
}
pbDB.Value = 0;
}