我正在尝试运行至少包含两个线程的应用程序:一个用于用户界面的表单和一个或多个工作线程。他们通过许多其他课程从静态课程中共同阅读/写作。
这就是我将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
答案 0 :(得分:2)
我建议您只有一个UI线程,即主线程。您可以将其他线程用于后台操作,但将所有UI内容保留在主线程上。
UI线程应该是唯一一个调用Application.Run
的线程。 WinForms对UI线程有其他要求(例如是STA),并且主线程满足这些要求。从理论上讲,WinForms可能支持两个UI线程,但这肯定不容易。
当您需要从后台线程TaskScheduler
或SynchronizationContext
更新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中没有BackgroundWorker
和Px
,你确实被迫直接使用线程 - 虽然ThreadPool可能比实例化新线程更好,大多数时候。