C#线程和窗体:NotSupportedException-使用Control.Invoke?
我正在尝试运行至少有两个线程的应用程序:一个用于用户界面的表单和一个或多个工作线程。他们从一个静态类到许多其他类进行联合读/写 这就是我将worker类的实例传递给显示窗体的原因。我想这就是为什么我会出错的原因: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
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
的命令“真正启动”。啊,我想,问题是我都运行了表单,并尝试在一个新线程中启动它,而我只要实例化工作线程就够了,让表单继续运行,因为它已经在主线程中自动运行。