为什么我会收到此错误:“跨线程操作无效:控制从其创建的线程以外的线程访问的lbFolders。”?

这令我感到困惑,也许有人可以用我的无知来照亮教育之光。 这是在C#windows应用程序中。 我从一个线程访问列表框的内容。 当我尝试像这样访问它时

prgAll.Maximum = lbFolders.SelectedItems.Count; 

我收到了错误。 但是,这是我没有得到的部分。 如果我注释掉那一行,那就是下一行

 foreach (string dir in lbFolders.SelectedItems) 

执行得很好。

编辑:像往常一样,我缺乏沟通技巧。 让我澄清一下。

我知道从除了创建它们之外的线程访问GUI项会导致问题。 我知道访问它们的正确方法是通过委托。

我的问题主要在于:为什么我可以正常访问和迭代SelectedItems对象,但是当我尝试获取(未设置)它的Count属性时,它会爆炸。

 prgAll.Maximum = lbFolders.SelectedItems.Count; 

在该行上,您执行一个赋值( set / add ),默认情况下它不是线程安全的。

在第二行,它只是一个get操作,其中线程安全无关紧要。

编辑:我不是指访问prgAll元素。

访问Count属性会更改 ListBox内部集合的内部状态 ,这就是它抛出exception的原因。

您无法从单独的线程访问GUI元素。 使用委托进行更改。

例如。

 lblStatus.Invoke((Action)(() => lblStatus.Text = counter.ToString())); 

或更旧的skool:

 lblTest.Invoke((MethodInvoker)(delegate() { lblTest.Text = i.ToString(); })); 

我有一篇关于如何在所有.Net版本中执行此操作的博客文章。

SelectedItems的Count属性不是线程安全的,因此您不能跨线程使用它。

您正在尝试从主线程以外的线程写入控件。 使用Invoke或BeginInvoke。

 void SetMax() { if (prgAll.InvokeRequired) { prgAll.BeginInvoke(new MethodInvoker(SetMax)); return; } prgAll.Maximum = lbFolders.SelectedItems.Count; } 

您无法从不是主GUI线程的线程触摸GUI对象。 有关详细信息和解决方案,请参见此处 。

因为您在线程中创建了一个控件,并且您正试图从另一个控件中获取该控件。 调用InvokeRequired属性,如下所示:

 private void RunMe() { if (!InvokeRequired) { myLabel.Text = "You pushed the button!"; } else { Invoke(new ThreadStart(RunMe)); } } 

试试这个:

 private delegate void xThreadCallBack(); private void ThreadCallBack() { if (this.InvokeRequired) { this.BeginInvoke(new xThreadCallBack(ThreadCallBack)); } else { //do what you want } } 

但是,使用lambda表达式的答案就足够了。