在我的应用程序中,我启动了一个隐藏的dummyForm
,它仅仅是为了跟踪主UI线程而创建的。所以如果将要创建一个新窗体InvokeRequired
在虚拟窗体上使用,以确保我们在创建新窗体时位于主UI线程上。线程与WinForms?
直接在实例化我的frmStart
表单后,我检查了frmStart.InvokeRequired
,它被设置为false,因此不需要在这里调用(dummyForm.InvokeRequired
也是如此)。
后来我有一个frmMyDialog
将使用frmStart
父/所有者是这样的:
using(Create frmMyDialog on main UI thread)
{
frmMyDialog.Show(frmStart);
}
,这将抛出一个跨线程异常,这里的奇怪的是:
frmMyDialog.InvokeRequired = false
dummyForm.InvokeRequired = false
frmStart.InvokeRequired = true
甚至当我在创建frmStart
时检查dummyForm.InvokeRequired
为假?
frmMyDialog.InvokeRequired
应该始终与dummyForm.InvokeRequired
的值相同?这里发生了什么?
我检查了frmStart
和dummyForm
完全没有在第一个实例创建后重新创建。
EDIT1:
这是应用程序如何启动:
public static void Main(string[] args)
{
_instance = new MyClientMain(parameters);
Application.Run(_instance);
}
MyClientMain类的构造函数将在一个名为MainControl静态类运行安装程序。 MainControler将在设置方法实例化一个像这样的dummyform:
if (_dummyForm == null)
_dummyForm = new Form();
此步骤完成后登录表单将处理登录和这种形式是多线程的。当登录完成时,MainController将再次被调用以instanciate并打开包含frmStart的主MDI窗口。为了确保我们在同一线程上完成以下工作:
public static StartApplication()
{
if (_dummyForm.InvokeRequired)
_dummyForm.Invoke(new MethodInvoker(delegate { OpenMainOrbitWindow(); }));
//Instanciate mainform and frmStart then open mainForm with frmStart as a MDI child
}
这里没有多线程。
然后,当服务下线时,一个事件将被触发,我需要弹出一个frmMyDialog,但使用时。的ShowDialog(),它的对话框将被放在后面表格,以便家长/所有者最多可以发现这样设置:
public static Form GetActiveForm()
{
Form activeForm = Form.ActiveForm;
if (activeForm != null)
return activeForm;
if (MainOrbitForm.TopMost)
return MainOrbitForm;
else
{
FormCollection openForms = Application.OpenForms;
for (int i = 0; i < openForms.Count && activeForm == null; ++i)
{
Form openForm = openForms[i];
if (openForm.IsMdiContainer)
return openForm.ActiveMdiChild;
}
}
if (_patientForm != null)
{
if (_patientForm.TopMost)
return _patientForm;
}
return null;
}
public static string ShowOrbitDialogReName()
{
frmMyDialog myDialog;
Form testForm;
//Makes sures that the frmOrbitDialog is created with the same thread as the dummyForm
//InvokeRequired is used for this
using (myDialog = MainController.CreateForm<frmOrbitDialog>())
{
//Settings...
testForm = GetActiveForm();
myDialog.ShowDialog(GetActiveForm(testForm));
}
}
的问题是,
myDialog.InvokeRequired = false
testForm.InvokeRequired = true;
MainController.DummyForm.InvokeRequired = false;
EDIT2: 启动和创建dummyform:
dummyForm.InvokeRequired = false
Thread.CurrentThread.ManagedThreadId = 9
登录成功后,我们创建的MainForm
_mainForm.InvokeRequired = false
MainControl.DummyForm.InvokeRequired = false
Thread.CurrentThread.ManagedThreadId = 9
目前为止一切都很好。然后回调接收(WCF)和事件创建相同的线程上frmMyDialog(调用是在dummyForm使用),然后使用ShowDialog的:
frmMyCustomDialog.ShowDialog(_mainForm)
这将引发CrossThreadException,这是它的外观像这样:
_mainForm.InvokeRequired = true
frmMyCustomDialog.InvokeRequired = false
MainControl.DummyForm.InvokeRequired = false
Thread.CurrentThread.ManagedThreadId = 12
为什么MainControl.DummyForm不正确? ManageThreadId不是9但是12?
显示更多*真实*代码,了解如何创建涉及您获得的例外的表单。 InvokeRequired未绑定到主UI线程,而是绑定到创建控件/窗体的线程! – Jan
你是否多次调用Application.Run? – Jodrell
@Jodrell请参阅Edit1 – Banshee