Search code examples
c#winformswindows-mobile-5.0motorola-emdksmart-device-framework

Cross thread exception when using Invoke()


I'm developing an application running on a Windows Mobile 5 based barcode scanner. Occasionally I'm experiencing a cross thread exception causing the application to fail.

The application is written in C# 3.5 and is build on top of the Motorola EMDK for .NET but also uses parts of the Smart Device Framework.

In my main form I have a Panel where I change the content based on what context the application is in. All Views shares a common interface IContentView.

I also use some background threads to monitor if the device is currently charging (triggers a user logout) and also monitor if the device can connect to the server.

I'm using John Skeets construction from here when invoking changes on the Panel, to ensure changes being invoked on the control being changed:

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

contentPanel being a System.Windows.Forms.Panel.

But I still get the following exception:

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()

What am I missing here? Do I need to do something else to marshal the changes correctly from the thread to the panel?

Any advise is highly appreciated.


Solution

  • For me it seems that the problem occurs while adding content as UserControl to Controls.

    Check in which thread IContentView content was created, I suppose NOT in the main thread, which may be the issue.

    Also look here: Why can you cross thread adding controls in WinForms, but not WPF?

    So it seems that this is also "forbidden" in Windows Forms, but not as strictly checked by the framework code.

    So the solution will be to create ALL GUI controls in the main thread, probably also using Invoke()