C#线程和表单:NotSupportedException - 使用Control.Invoke?

时间:2011-02-08 15:01:17

标签: c# winforms multithreading windows-mobile backgroundworker

我正在尝试运行至少包含两个线程的应用程序:一个用于用户界面的表单和一个或多个工作线程。他们通过许多其他课程从静态课程中共同阅读/写作。

这就是我将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

3 个答案:

答案 0 :(得分:2)

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

UI线程应该是唯一一个调用Application.Run的线程。 WinForms对UI线程有其他要求(例如是STA),并且主线程满足这些要求。从理论上讲,WinForms可能支持两个UI线程,但这肯定不容易。

当您需要从后台线程TaskSchedulerSynchronizationContext更新UI控件时,我通常会推荐其他形式的同步。不幸的是,在移动平台上,您唯一的选择是Control.Invoke

答案 1 :(得分:1)

检查异常的堆栈跟踪(并发布)。您几乎肯定会从工作线程中访问一些Control

在找到从非UI线程访问控件的位置后,可以通过以下方式修改对Control的访问(在此示例中为Label):

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

答案 2 :(得分:0)

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

由于你在CF中没有BackgroundWorkerPx,你确实被迫直接使用线程 - 虽然ThreadPool可能比实例化新线程更好,大多数时候。