1

I needed to create an event in another class, so I've used an EventHandler and this works fine, however now in my main class form, when I try to use any controls I get:

Cross-thread operation not valid

So after researching I can Invoke:

tbMessage.Invoke((Action)delegate
{
      tbMessage.Size = new System.Drawing.Size(500, 60);
      this.Controls.Add(tbMessage);
});

However if I do this all over the form, there would be loads of instances, where, I'm moving, resizing, changing text for loads of controls. This doesn't seem right, there must be something to do with using the EventHandle that I don't know about. These errors didn't occur before moving some code out into new class and using task and events.

I am unsubscribing from the event after finished with and before

dvm.VoltageSet -= dvmVoltageSet;

Any ideas please?

EDIT:

I am using a background worker to update UI, whilst receiving serial commands in Form1. In another class I am using Task.Run to set voltage + read voltage whilst I'm not at set voltage. Then I'm using EventHandler to send an event to Form1 so it know's the voltage had been set before proceeding to next step.

RE-EDIT:

I can now see that I have two Windows.Forms threads, which is causing my error. This appears to be happening when I call a method in another class, when it causes an event in form1 and I try to use a control, it then starts a new thread.

Not Flagged >   4432    8   Worker Thread   Worker Thread   System.Windows.Forms.dll!System.Windows.Forms.Control.Handle.get    Normal
                    [External Code]  
                    TestSensor.exe!TestSensor.Form1.TestLvdtNull() Line 3113     
                    TestSensor.exe!TestSensor.Form1.dvmVoltageSet(object sender, VoltageEventArgs e) Line 414    
                    TestSensor.exe!TestSensor.DVMLoopRunner.OnNewVoltageSet(VoltageEventArgs e) Line 71  
                    TestSensor.exe!TestSensor.DVMLoopRunner.NewSet.set(bool value) Line 57   
                    TestSensor.exe!TestSensor.DVMLoopRunner.AdjustVoltage() Line 295     
                    TestSensor.exe!TestSensor.DVMLoopRunner.Form1_DVMReadingAvailable(object sender, TestSensor.DVMLoopRunner.DVMReadingAvailableEventArgs e) Line 147   
                    TestSensor.exe!TestSensor.DVMLoopRunner.ReadDVM() Line 192   
                    TestSensor.exe!TestSensor.DVMLoopRunner.ReadDVMWorker() Line 173     
                    TestSensor.exe!TestSensor.DVMLoopRunner.SetVoltage.AnonymousMethod__49_0() Line 95   
                    [External Code]  

Not Flagged     6768    1   Main Thread Main Thread System.Windows.Forms.dll!System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop   Normal
                    [External Code]  
                    TestSensor.exe!TestSensor.Program.Main() Line 17     

Not Flagged     11048   0   Worker Thread   <No Name>       Normal
Not Flagged     668 4   Worker Thread   <No Name>   System.dll!System.IO.Ports.SerialStream.EventLoopRunner.WaitForCommEvent    Normal
Not Flagged     5888    5   Worker Thread   <No Name>   System.dll!System.IO.Ports.SerialStream.EventLoopRunner.WaitForCommEvent    Normal
Not Flagged     12968   0   Worker Thread   <No Name>       Normal
Not Flagged     11924   6   Worker Thread   Worker Thread       Normal

Is it possible to tell the compiler to carry on using the existing Forms thread and not start a new one?

chasher
  • 149
  • 11
  • You can only use Windows Forms controls on the same thread that created those controls. If you have another worker threads, this gets more complex. From your question it is unclear, why and how are you using worker threads. Please provide us with more context information. – dymanoid Oct 04 '18 at 11:24
  • @dymanoid - you should have only 1 thread that creates controls. – bommelding Oct 04 '18 at 11:25
  • The question is incomplete, you need to study the basics. Presumably you have 1 event that triggers from a device, in another thread. That needs to Invoke. When you have many Invokes you are doing something wrong. – bommelding Oct 04 '18 at 11:27
  • _"using a background worker to update UI"_ is very strange. And impossible (or at least very impractical). – bommelding Oct 04 '18 at 11:40
  • @bommelding In the BW I'm reading values from the serial, putting them into a PointPairList for Zedgraph and Invalidate the graph – chasher Oct 04 '18 at 12:05
  • I'm not sure about reading the Serial port from a Bgw. But the ZedGraph actions shouldn't be in the Bgw. Consider the Progress event, you can pass a data package. – bommelding Oct 04 '18 at 12:18
  • 2
    If you are using a `BackGroudWorker`, use its `ProgressChanged` event to report a modification of some kind. That event is raised in the UI thread. You should never Invoke from the `DoWork` proc. – Jimi Oct 04 '18 at 12:19
  • Thanks all for comments. If there is data to read from the serial port I read the property in the serial class, then use this data to add to an array or list and update the zedgraph UI. I do use the ProgressChanged event to update the UI's textboxes. I will look to move the update graph to the ProgressChanged later on, but this has all been working and stable for quite some time. I'm sure this issue I'm having is to do with adding this new class and the event. – chasher Oct 04 '18 at 12:34
  • I used this example [link]https://www.codeproject.com/tips/55555/pass-value-between-forms-using-events and replaced the returned string to a bool and my "Form2.cs" doesn't have an actual winform as it doesn't require one – chasher Oct 04 '18 at 12:36
  • Is it possible to tell the compiler to carry on using the existing Forms thread and not start a new one? – chasher Oct 04 '18 at 15:00
  • @chasher it has nothing to do with the compiler. It only makes sense to create a new thread for a new form, else it would block your whole application – slow Oct 05 '18 at 09:24

0 Answers0