C#线程和窗体:NotSupportedException-使用Control.Invoke?

C#线程和窗体:NotSupportedException-使用Control.Invoke?,c#,winforms,multithreading,windows-mobile,backgroundworker,C#,Winforms,Multithreading,Windows Mobile,Backgroundworker,我正在尝试运行至少有两个线程的应用程序:一个用于用户界面的表单和一个或多个工作线程。他们从一个静态类到许多其他类进行联合读/写 这就是我将worker类的实例传递给显示窗体的原因。我想这就是为什么我会出错的原因: public class CoCoon { private Screen displayForm; private Worker worker; public ThreadedApp() { worker = new Worker

我正在尝试运行至少有两个线程的应用程序:一个用于用户界面的表单和一个或多个工作线程。他们从一个静态类到许多其他类进行联合读/写

这就是我将worker类的实例传递给显示窗体的原因。我想这就是为什么我会出错的原因:

 public class CoCoon
 {
    private Screen displayForm;
    private Worker worker; 

    public ThreadedApp()
    {
        worker = new Worker (1024);
        displayForm = new Screen(worker);
    }

    public void Run()
    {
        //thread 1: display form
        Thread screenThread = new Thread(() => Application.Run(displayForm));

        //thread 2: background worker
        Thread workerThread = new Thread(worker.Run) {IsBackground = true};

        screenThread.Start();

        Thread.Sleep(1000); //if I don't wait a while, I get an ObjectDisposedException!

        workerThread.Start();

    }
线程和对象启动得很好,但是在处理完Form_Load方法之后,就会在上面的Application.Run(displayForm)行上抛出一个错误。这是一个NotSupportedException,带有一条注释,我应该使用Control.Invoke。但我不确定我是否理解,因为我不允许显示窗体以外的线程使用其上的控件

我不熟悉穿线。路上有人能帮我吗?谢谢

PS:一个细节-我正在为Windows Mobile平台开发这个

在堆栈跟踪后编辑

 at Microsoft.AGL.Common.MISC.HandleAr(PAL_ERROR ar)\r\n   at    
 System.Windows.Forms.Control.get_Visible()\r\n   at 
 System.Windows.Forms.Form._SetVisibleNotify(Boolean fVis)\r\n   at  
 System.Windows.Forms.Control.set_Visible(Boolean value)\r\n   at 
 System.Windows.Forms.Application.Run(Form fm)\r\n   at
 CoCoonWM6.CoCoon.<Run>b__1()\r\n
位于Microsoft.AGL.Common.MISC.HandleAr(PAL\u错误ar)\r\n位于
System.Windows.Forms.Control.get\u Visible()\r\n位于
System.Windows.Forms.Form.\u SetVisibleNotify(布尔fVis)\r\n位于
System.Windows.Forms.Control.set\u Visible(布尔值)\r\n位于
System.Windows.Forms.Application.Run(Form fm)\r\n位于
CoCoonWM6.CoCoon.b_u1()\r\n

检查异常的堆栈跟踪(并发布)。几乎可以肯定,您正在从工作线程访问一些
控件

这就是在找到从非UI线程访问控件的位置后,如何修改对控件(在本例中为标签)的访问:

if (label13.InvokeRequired)
{
  ChangeTextDelegate changeText = new ChangeTextDelegate(anyChangeTextMethod);
  label13.Invoke(changeText, new object[] { newText });
}
else
{
  label13.Text = newText;
}

看起来您正在尝试在后台线程中使用GUI元素。这就解释了为什么您必须调用
Sleep
(否则表单及其控件在您尝试使用它们之前不会完成加载)以及
控件。调用
异常(您不能从非UI线程使用GUI元素)。有关如何使用它,请参阅文档


由于CF中没有
BackgroundWorker
Px
,因此您确实被迫直接使用线程——尽管在大多数情况下,使用线程可能比实例化新线程要好。

我建议您只有一个UI线程,即主线程。您可以使用其他线程进行后台操作,但将所有UI内容保留在主线程上

UI线程应该是唯一调用
应用程序的线程。运行
。WinForms对UI线程有其他要求(如STA),这些要求由主线程满足。理论上,WinForms可能支持两个UI线程,但这肯定不容易


当您需要从后台线程更新UI控件时,我通常推荐其他形式的同步-
TaskScheduler
SynchronizationContext
。不幸的是,在移动平台上,您唯一的选择是
控制。调用

了解工作线程正在做什么可能会有所帮助。WAG(不是win mobile dev),但为什么要为应用程序运行一个线程呢?另外,
screenThread
应该是STA,但您没有设置它。还有,还有…检查堆栈跟踪以查找异常(并发布它)。几乎可以肯定,您正在从工作线程访问一些控件。谢谢大家。如前所述,我是线程新手,尤其是在表单方面,因此欢迎对我忘记的内容提出任何建议和评论。我无法从堆栈跟踪中判断另一个线程是如何访问UI线程的。谢谢。这听起来是个有趣的选择。我会朝那个方向尝试。这实际上让我走上了正确的道路。在以前版本的代码中,我一直都是这样做的。我只是觉得表单正在等待另一个线程完成,这就是为什么我认为我必须把它也放到另一个线程上。在恢复到以前的版本并进行一些测试之后,结果证明我错了。所以,现在它的工作,因为我想毕竟-汉克斯。但是,我无法从堆栈跟踪中判断另一个线程是如何访问UI线程的。我猜您正在另一个线程上实例化
displayForm
,而不是
screenThread
,对吗?您必须在访问它的同一线程上实例化
displayForm
,除非您想通过
Invoke
包装所有内容!最好的选择是使用主线程。你可以先启动工作线程,让它等待
displayForm
的命令“真正启动”。啊,我想,问题是我都运行了表单,并尝试在一个新线程中启动它,而我只要实例化工作线程就够了,让表单继续运行,因为它已经在主线程中自动运行。