使用 Invoke() 时出现跨线程异常

Cross thread exception when using Invoke()

我正在 运行 基于 Windows Mobile 5 的条码扫描器开发应用程序。偶尔我会遇到导致应用程序失败的跨线程异常。

该应用程序是用 C# 3.5 编写的,构建在适用于 .NET 的摩托罗拉 EMDK 之上,但也使用了 Smart Device Framework 的部分内容。

在我的主窗体中,我有一个面板,我可以根据应用程序所在的上下文更改内容。所有视图共享一个公共接口 IContentView。

我还使用一些后台线程来监控设备当前是否正在充电(触发用户注销)以及监控设备是否可以连接到服务器。

我在调用面板上的更改时使用 here 中的 John Skeets 构造,以确保在正在更改的控件上调用更改:

    public void ShowContent(IContentView content)
    {
        contentPanel.Invoke(() =>
            {
                contentPanel.Controls.Clear();
                contentPanel.Controls.Add(content as UserControl);
                contentPanel.Focus();
            });
    }

contentPanel 是 System.Windows.Forms.Panel.

但我仍然得到以下异常:

Control.Invoke must be used to interact with controls created on a separate thread.
   at Microsoft.AGL.Common.MISC.HandleAr(PAL_ERROR ar)
   at System.Windows.Forms.Control.get_Parent()
   at System.Windows.Forms.Control.ControlCollection.Add(Control value)
   at BarcodeScanner.MainView.MainForm.<>c__DisplayClass1e.<ShowContent>b__1d()
   at System.Reflection.RuntimeMethodInfo.InternalInvoke(RuntimeMethodInfo rtmi, Object obj, BindingFlags invokeAttr, Binder binder, Object parameters, CultureInfo culture, Boolean isBinderDefault, Assembly caller, Boolean verifyAccess, StackCrawlMark& stackMark)
   at System.Reflection.RuntimeMethodInfo.InternalInvoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean verifyAccess, StackCrawlMark& stackMark)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)
   at System.Windows.Forms.Control.TASK.Invoke()
   at System.Windows.Forms.Control._InvokeAll()
   at System.Windows.Forms.Control.WnProc(WM wm, Int32 wParam, Int32 lParam)
   at System.Windows.Forms.Control._InternalWnProc(WM wm, Int32 wParam, Int32 lParam)
   at Microsoft.AGL.Forms.EVL.EnterMainLoop(IntPtr hwnMain)
   at System.Windows.Forms.Application.Run(Form fm)
   at BarcodeScanner.Program.Main()

我在这里错过了什么?我是否需要执行其他操作才能将更改从线程正确编组到面板?

非常感谢任何建议。

对我来说,问题似乎是在将 content as UserControl 添加到 Controls 时出现的。

检查在哪个线程中创建了 IContentView content,我想不在主线程中,这可能是问题所在。

另请看这里:Why can you cross thread adding controls in WinForms, but not WPF?

所以看起来这也是"forbidden"在Windows的形式,但是没有被框架代码严格检查。

所以解决方案是在主线程中创建所有 GUI 控件,可能还使用 Invoke()