为什么我会收到此错误:“跨线程操作无效:控制从其创建的线程以外的线程访问的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表达式的答案就足够了。