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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/244591/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 19:37:50  来源:igfitidea点击:

Why am I getting this error:"Cross-thread operation not valid: Control lbFolders accessed from a thread other than the thread it was created on."?

c#.netmultithreading

提问by Kevin

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;
我得到了错误。但是,这是我没有得到的部分。如果我注释掉那行,下一行
foreach (string dir in lbFolders.SelectedItems)
执行得很好。

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 属性时,它会崩溃。

采纳答案by arul

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 getoperation, 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 stateof the ListBox inner collection, that is why it throws the exception.

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

回答by Martin Marconcini

The Count property of SelectedItems is not thread-safe, so you can't use it cross-thread.

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

回答by Matt Warren

You can't touch a GUI object from a thread that isn't the main GUI thread. See herefor more details and the solution.

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

回答by Jon B

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;
}

回答by Echostorm

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:

或更旧的学校:

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.

我有关于如何做到这一点在所有博客中的净释放这里

回答by sebagomez

Because you created a control in a thread and you're trying to reach it from another one. Call the InvokeRequiredproperty as shown here:

因为您在一个线程中创建了一个控件,而您正试图从另一个线程访问它。调用InvokeRequired属性,如下所示:

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

回答by Gatherer

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 表达式的答案就足够了。