This is baffling me, maybe somebody can shine the light of education on my ignorance. This is in a C# windows app. I am accessing the contents of a listbox from a thread. When I try to access it like this
这让我感到困惑,也许有人可以用我的无知来照亮教育之光。这是在C#windows应用程序中。我从一个线程访问列表框的内容。当我尝试像这样访问它时
prgAll.Maximum = lbFolders.SelectedItems.Count;
I get the error. However, here is the part I don't get. If I comment out that line, the very next line
foreach (string dir in lbFolders.SelectedItems)
executes just fine.
Edit: As usual, my communication skills are lacking. Let me clarify.
编辑:像往常一样,我缺乏沟通技巧。让我澄清一下。
I know that accessing GUI items from threads other than the ones they were created on causes problems. I know the right way to access them is via delegate.
我知道从除了创建它们之外的线程访问GUI项会导致问题。我知道访问它们的正确方法是通过委托。
My question was mainly this: Why can I access and iterate through the SelectedItems object just fine, but when I try to get (not set) the Count property of it, it blows up.
我的问题主要在于:为什么我可以正常访问和迭代SelectedItems对象,但是当我尝试获取(未设置)它的Count属性时,它会爆炸。
7 个解决方案
#1
6
prgAll.Maximum = lbFolders.SelectedItems.Count;
On that line you perform an assignment (set/add), which by default is not thread-safe.
在该行上,您执行一个赋值(set / add),默认情况下它不是线程安全的。
On the second line it's just a get operation, where thread-safety merely doesn't matter.
在第二行,它只是一个get操作,其中线程安全无关紧要。
EDIT: I don't mean access to the prgAll element.
编辑:我不是指访问prgAll元素。
Accessing the Count property changes the internal state of the ListBox inner collection, that is why it throws the exception.
访问Count属性会更改ListBox内部集合的内部状态,这就是它抛出异常的原因。
#2
17
You can't access GUI elements from a separate thread. Use a delegate to make the change.
您无法从单独的线程访问GUI元素。使用委托进行更改。
eg.
lblStatus.Invoke((Action)(() => lblStatus.Text = counter.ToString()));
or older skool:
或更旧的skool:
lblTest.Invoke((MethodInvoker)(delegate()
{
lblTest.Text = i.ToString();
}));
I've got a blog post on how to do this in all the .Net releases here.
我有一篇关于如何在所有.Net版本中执行此操作的博客文章。
#3
3
The Count property of SelectedItems is not thread-safe, so you can't use it cross-thread.
SelectedItems的Count属性不是线程安全的,因此您不能跨线程使用它。
#4
2
You're trying to write to a control from a thread other than the main thread. Use Invoke or BeginInvoke.
您正在尝试从主线程以外的线程写入控件。使用Invoke或BeginInvoke。
void SetMax()
{
if (prgAll.InvokeRequired)
{
prgAll.BeginInvoke(new MethodInvoker(SetMax));
return;
}
prgAll.Maximum = lbFolders.SelectedItems.Count;
}
#5
1
You can't touch a GUI object from a thread that isn't the main GUI thread. See here for more details and the solution.
您无法从不是主GUI线程的线程触摸GUI对象。有关详细信息和解决方案,请参见此处。
#6
1
Because you created a control in a thread and you're trying to reach it from another one. Call the InvokeRequired property as shown here:
因为您在线程中创建了一个控件,并且您正试图从另一个控件中获取该控件。调用InvokeRequired属性,如下所示:
private void RunMe()
{
if (!InvokeRequired)
{
myLabel.Text = "You pushed the button!";
}
else
{
Invoke(new ThreadStart(RunMe));
}
}
#7
0
Try this:
private delegate void xThreadCallBack();
private void ThreadCallBack()
{
if (this.InvokeRequired)
{
this.BeginInvoke(new xThreadCallBack(ThreadCallBack));
}
else
{
//do what you want
}
}
Though, the answer with the lambda expression would suffice.
但是,使用lambda表达式的答案就足够了。
#1
6
prgAll.Maximum = lbFolders.SelectedItems.Count;
On that line you perform an assignment (set/add), which by default is not thread-safe.
在该行上,您执行一个赋值(set / add),默认情况下它不是线程安全的。
On the second line it's just a get operation, where thread-safety merely doesn't matter.
在第二行,它只是一个get操作,其中线程安全无关紧要。
EDIT: I don't mean access to the prgAll element.
编辑:我不是指访问prgAll元素。
Accessing the Count property changes the internal state of the ListBox inner collection, that is why it throws the exception.
访问Count属性会更改ListBox内部集合的内部状态,这就是它抛出异常的原因。
#2
17
You can't access GUI elements from a separate thread. Use a delegate to make the change.
您无法从单独的线程访问GUI元素。使用委托进行更改。
eg.
lblStatus.Invoke((Action)(() => lblStatus.Text = counter.ToString()));
or older skool:
或更旧的skool:
lblTest.Invoke((MethodInvoker)(delegate()
{
lblTest.Text = i.ToString();
}));
I've got a blog post on how to do this in all the .Net releases here.
我有一篇关于如何在所有.Net版本中执行此操作的博客文章。
#3
3
The Count property of SelectedItems is not thread-safe, so you can't use it cross-thread.
SelectedItems的Count属性不是线程安全的,因此您不能跨线程使用它。
#4
2
You're trying to write to a control from a thread other than the main thread. Use Invoke or BeginInvoke.
您正在尝试从主线程以外的线程写入控件。使用Invoke或BeginInvoke。
void SetMax()
{
if (prgAll.InvokeRequired)
{
prgAll.BeginInvoke(new MethodInvoker(SetMax));
return;
}
prgAll.Maximum = lbFolders.SelectedItems.Count;
}
#5
1
You can't touch a GUI object from a thread that isn't the main GUI thread. See here for more details and the solution.
您无法从不是主GUI线程的线程触摸GUI对象。有关详细信息和解决方案,请参见此处。
#6
1
Because you created a control in a thread and you're trying to reach it from another one. Call the InvokeRequired property as shown here:
因为您在线程中创建了一个控件,并且您正试图从另一个控件中获取该控件。调用InvokeRequired属性,如下所示:
private void RunMe()
{
if (!InvokeRequired)
{
myLabel.Text = "You pushed the button!";
}
else
{
Invoke(new ThreadStart(RunMe));
}
}
#7
0
Try this:
private delegate void xThreadCallBack();
private void ThreadCallBack()
{
if (this.InvokeRequired)
{
this.BeginInvoke(new xThreadCallBack(ThreadCallBack));
}
else
{
//do what you want
}
}
Though, the answer with the lambda expression would suffice.
但是,使用lambda表达式的答案就足够了。