无效的跨线程操作C#

时间:2010-12-29 20:13:38

标签: c#

我有一个带有一些控件的窗体。其中一个控件是文本框,另一个是listView。我还有一个按钮(上传),它根据所选项目ListView对象上传文件。

为了报告上传进度%,我添加了一个进度条,通过联系服务器创建了一个可以上传文件的后台工作线程。如果没有创建后台工作程序的方法,进度条不会正确更新并且看起来没有响应。

现在,在上传文件时,我需要从ListView中获取选择并根据该选择获取文件。但是当我尝试从后台工作线程访问“ListView”时,我得到一个异常:System.InvalidOperationException:跨线程操作无效:

我应该怎么做才能纠正这个例外?

7 个答案:

答案 0 :(得分:6)

在这种情况下,您的处理线程想要访问您的UI线程。

示例:

private delegate void UpdateTextDelegate(object value);

private void UpdateText(object value)
{
    if (this.textbox.InvokeRequired)
    {
        // This is a worker thread so delegate the task.
        this.textbox.Invoke(new UpdateTextDelegate(this.UpdateText), value);
    }
    else
    {
        // This is the UI thread so perform the task.
        this.textbox.Text = value.ToString();
    }
}

答案 1 :(得分:0)

对Windows窗体控件的访问本质上不是线程安全的。如果有两个或多个线程操纵控件的状态,则可以强制控件进入不一致状态。其他与线程相关的错误也是可能的,包括竞争条件和死锁。确保以线程安全的方式访问您的控件非常重要。

.NET Framework可帮助您以非线程安全的方式检测何时访问控件。当您在调试器中运行应用程序时,除了创建控件的线程之外的线程尝试调用该控件时,调试器会引发一个InvalidOperationException,并显示消息“从该线程以外的线程访问控制控件名称”创建于。”

在调试期间以及在某些情况下在运行时可靠地发生此异常。强烈建议您在看到此问题时解决此问题。在调试使用.NET Framework 2.0之前的.NET Framework编写的应用程序时,您可能会看到此异常

BackgroundWorker也使用线程来完成它的工作。

Look at this

答案 2 :(得分:0)

除非它在UI线程上运行,否则任何代码都不应触及任何控件。这意味着调用方法(Control.Invoke()除外)和设置/检索属性。实现这一目标的最佳方法是自由使用Control.InvokeRequiredControl.Invoke()。对于您的特定情况,您可能希望使用BackgroundWorker来上传文件。

答案 3 :(得分:0)

您无法访问从另一个线程在一个线程上创建的控件。这是件好事,相信我。 BackgroundWorker类公开了一些可以帮助您完成所需操作的事件,即ProgressChanged和RunWorkerCompleted。

答案 4 :(得分:0)

我在一个频繁的论坛上写了一些detailed guide来解决这个问题。查看“Classic Marshalling”标题下的解释,了解实现的内容。

答案 5 :(得分:0)

通常,我使用BackgroundWorker组件的ReportProgress方法将后台线程中的元素编组到UI线程。

您可以简单地传递进度(整数)值,您也可以将复杂对象(仅限非GUI,因此 no ListViewItems等)传递给GUI线程这个事件。

答案 6 :(得分:0)

好的解决方案是使用Control.Invoke/Control.InvokeRequired - 它有助于在GUI线程中执行代码(因此不会抛出异常)。

糟糕/丑陋的解决方案是Control.CheckForIllegalCrossThreadCalls = false。