我有一个C#WinForms应用程序,它包含一个运行时表单设计器/实时数据查看器。用户可以在应用程序运行时添加控件并查看实时数据。它使用了许多第三方图形和仪表类型控件,这些控件在重绘期间非常耗费GUI。设计器表单使用另一个具有属性网格控件的浮动窗体,以允许更改每个用户添加控件的属性。
为了在使用多个设计器时帮助提高应用程序的性能,我使用与此类似的代码将每个表单移动到一个单独的GUI线程:
Thread guiThread = new Thread(CreateScreen);
guiThread.SetApartmentState( ApartmentState.STA);
guiThread.Start();
List<frmDesigner> designers = new List<frmDesigner>();
private void CreateScreen()
{
frmDesigner designer = new frmDesigner(openedFile, comms);
designers.Add(designer);
Application.Run(designer);
}
这适用于第一个创建的frmDesigner。我可以使用第二种形式的属性网格编辑表单上的所有控件。注意:属性网格表单是从创建设计器的线程打开的。每个frmDesigner都有自己的属性编辑器表单。分享一个会很好,但这会产生更多的麻烦。
如果我创建了多个frmDesigner(每个都在自己的线程中),则在尝试修改控件的BackColor时,所有后续属性网格都会抛出一个跨线程异常。如果我双击属性网格中的颜色选择器,颜色将更改,没有任何异常。可以使用相同的属性网格编辑任何其他属性。我使用Thread.CurrentThread.ManagedThreadId属性验证了所使用的所有表单和控件都在同一个线程上。
我正在尝试了解如何识别导致交叉线程异常的原因。据我所知,所有形式和控件都是在同一个帖子中创建的。
有人询问有关List是线程安全的问题。我只使用主GUI线程中的列表来允许在应用程序退出时关闭设计器。它不会在应用程序的任何其他位置使用。
private void CloseScreens()
{
List<frmDesigner> designersToClose = new List<frmDesigner>();
foreach (frmDesigner designer in designers)
{
if (designer != null && designer.IsDisposed == false)
{
designer.Invoke(new Action(() => { designer.Close(); }));
designersToClose.Add(designer);
}
}
foreach (frmDesigner designer in designersToClose)
{
designers.Remove(designer);
}
designers.Clear();
}
我设法通过在调试选项中关闭“Just my Code”来获取代码。我现在有以下堆栈跟踪。
System.Windows.Forms.dll!System.Windows.Forms.Control.Handle.get() + 0xc4 bytes
System.Windows.Forms.dll!System.Windows.Forms.Control.SendMessage(int msg, int wparam, ref System.Windows.Forms.NativeMethods.RECT lparam) + 0x10 bytes
System.Windows.Forms.dll!System.Windows.Forms.TabControl.GetTabRect(int index) + 0x84 bytes
System.Drawing.Design.dll!System.Drawing.Design.ColorEditor.ColorUI.AdjustColorUIHeight() + 0x3b bytes
System.Drawing.Design.dll!System.Drawing.Design.ColorEditor.ColorUI.Start(System.Windows.Forms.Design.IWindowsFormsEditorService edSvc, object value) + 0x2f bytes
System.Drawing.Design.dll!System.Drawing.Design.ColorEditor.EditValue(System.ComponentModel.ITypeDescriptorContext context, System.IServiceProvider provider, object value) + 0x89 bytes
System.Windows.Forms.dll!System.Windows.Forms.PropertyGridInternal.GridEntry.EditPropertyValue(System.Windows.Forms.PropertyGridInternal.PropertyGridView iva) + 0x5a bytes
System.Windows.Forms.dll!System.Windows.Forms.PropertyGridInternal.PropertyDescriptorGridEntry.EditPropertyValue(System.Windows.Forms.PropertyGridInternal.PropertyGridView iva) + 0x17 bytes
System.Windows.Forms.dll!System.Windows.Forms.PropertyGridInternal.PropertyGridView.PopupDialog(int row) + 0x680 bytes
System.Windows.Forms.dll!System.Windows.Forms.PropertyGridInternal.PropertyGridView.OnBtnClick(object sender, System.EventArgs e) + 0x6b bytes
System.Windows.Forms.dll!System.Windows.Forms.Control.OnClick(System.EventArgs e) + 0x70 bytes
System.Windows.Forms.dll!System.Windows.Forms.Button.OnClick(System.EventArgs e) + 0x4a bytes
System.Windows.Forms.dll!System.Windows.Forms.PropertyGridInternal.DropDownButton.OnClick(System.EventArgs e) + 0xe bytes
System.Windows.Forms.dll!System.Windows.Forms.Button.OnMouseUp(System.Windows.Forms.MouseEventArgs mevent) + 0xac bytes
System.Windows.Forms.dll!System.Windows.Forms.PropertyGridInternal.DropDownButton.OnMouseUp(System.Windows.Forms.MouseEventArgs e) + 0xe bytes
System.Windows.Forms.dll!System.Windows.Forms.Control.WmMouseUp(ref System.Windows.Forms.Message m, System.Windows.Forms.MouseButtons button, int clicks) + 0x28f bytes
System.Windows.Forms.dll!System.Windows.Forms.Control.WndProc(ref System.Windows.Forms.Message m) + 0x885 bytes
System.Windows.Forms.dll!System.Windows.Forms.ButtonBase.WndProc(ref System.Windows.Forms.Message m) + 0x127 bytes
System.Windows.Forms.dll!System.Windows.Forms.Button.WndProc(ref System.Windows.Forms.Message m) + 0x20 bytes
System.Windows.Forms.dll!System.Windows.Forms.Control.ControlNativeWindow.OnMessage(ref System.Windows.Forms.Message m) + 0x10 bytes
System.Windows.Forms.dll!System.Windows.Forms.Control.ControlNativeWindow.WndProc(ref System.Windows.Forms.Message m) + 0x31 bytes
System.Windows.Forms.dll!System.Windows.Forms.NativeWindow.DebuggableCallback(System.IntPtr hWnd, int msg, System.IntPtr wparam, System.IntPtr lparam) + 0x57 bytes
[Native to Managed Transition]
[Managed to Native Transition]
System.Windows.Forms.dll!System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(int dwComponentID, int reason, int pvLoopData) + 0x24e bytes
System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(int reason, System.Windows.Forms.ApplicationContext context) + 0x177 bytes
System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.RunMessageLoop(int reason, System.Windows.Forms.ApplicationContext context) + 0x61 bytes
System.Windows.Forms.dll!System.Windows.Forms.Application.Run(System.Windows.Forms.Form mainForm) + 0x31 bytes
MDIMain.CreateScreen() Line 282 + 0x8 bytes C#
mscorlib.dll!System.Threading.ThreadHelper.ThreadStart_Context(object state) + 0x66 bytes
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state) + 0x6f bytes
mscorlib.dll!System.Threading.ThreadHelper.ThreadStart() + 0x44 bytes
有没有人知道为什么会根据堆栈跟踪发生这种情况?