Click here to Skip to main content
15,885,278 members
Please Sign up or sign in to vote.
1.00/5 (1 vote)
System.InvalidOperationException' in System.Windows.Forms.dll not handled in user code
Additional information: 
Invalid cross-thread operation: the 'pnlCatalogo' control was accessed from a different thread than the one from which it was created.


What I have tried:

public Label[] numeroDia = new Label[600];

//for (int z= 0; z < 500; z++)
Parallel.For (0, 500, z =>
{
  gesGrafica.TestCornici(z, pnlCatalogo);
  //Thread.Sleep(10);
});

public void TestCornici(int i, Panel pnlImmagini)
{
  nDia[i] = new Label();
  pnlCatalogo.Controls.Add(nDia[i]);
  nDia[i].BorderStyle = BorderStyle.None;
  nDia[i].Name = "";
  nDia[i].Text = (i + 1).ToString();
  nDia[i].Width = 150;
  nDia[i].Height = 150;
  nDia[i].BackColor = Color.Gray;
  nDia[i].ForeColor = Color.White;
  nDia[i].Visible = true;

  nDia[i].BringToFront();
  nDia[i].Refresh();
}
Posted
Updated 28-Jan-21 4:20am

Using Parallel.For creates threads.
Please refer to: Parallel For in C# with Examples - Dot Net Tutorials[^]
You cannot access directly Windows Forms controls from other threads.
Here is how to do it: Make thread-safe calls to controls - Windows Forms .NET Framework | Microsoft Docs[^]
 
Share this answer
 
Comments
Member 13174280 28-Jan-21 11:04am    
I limited the number of threads to 2

var options = new ParallelOptions()
{
MaxDegreeOfParallelism = 2
};

the cycle is executed correctly if I exclude: pnlCatalogo.Controls.Add(nDia[i])

nDia[i] = new Label();
//pnlCatalogo.Controls.Add(nDia[i]); --> exclude
nDia[i].BorderStyle = BorderStyle.None;
........

why the exception occurs associating a control (Label) to an other (Panel)?
Dave Kreskowiak 28-Jan-21 15:46pm    
You can NOT create controls, in your case Labels, on threads other than the startup (UI) thread. Period. You're getting that exception because you're trying to violate that rule.

Any Windows UI is single-threaded only. All controls MUST be created on the startup (UI) thread for your UI to work.

You can try to do it, and may even get it to work, but you'll also run into issues you cannot duplicate and may not even happen every time you run the app.

The concept is pretty easy to understand. All UI work should happen on the UI thread and all other work, if required, should happen on other threads. If these other threads have to update the UI, those interactions should be marshalled back to the UI thread so the UI thread can handle it.
TheRealSteveJudge 29-Jan-21 3:02am    
Excellent explanation!
TheRealSteveJudge 29-Jan-21 3:03am    
Limiting the number of threads does not help.
Please read Dave's comment and also read the proposed links.
What did you expect a parallel operation to do? You use it when you want a number of tasks to proceed at the same time (or as close to the same time as the system and it's load will allow) - which means splitting the code up so that it runs on different cores at the same time. To do that, you need N + 1 cores: N for the number of task you are trying to execute simultaneously, plus one to set them all going.

To do that, each task must ruin in it's own Thread: this is the basic "unit of processing", and a thread is assigned to a core my the system (though which core may change while it's running - we'll ignore that and quite a lot of other complications for the sake of brevity here). Without a Thread, code can't execute!

When you app starts, it is given a Thread - called the UI Thread - and when that terminates, so does your application. But the UI Thread is special: it's the only Thread which is allowed to touch display controls (including Forms, they are Controls as well) - if any other Thread tries to access a control in any way you get a "Cross-threading exception" - which is what you are seeing. To access any control from a thread other than the UI thread, you have to do something complicated called Invoking the control, which "moves the code" back to the UI thread temporarily, and then return to your "normal thread" when it's done.
T
That's not difficult to do: Control.Invoke Method (System.Windows.Forms) | Microsoft Docs[^] shows you how - but you need to think very, very carefully about exactly what you are doing as once you exceed the number of cores available in your system you can start to slow things down dramatically, and it's very, very easy to make your code slower, more memory hungry, and les reliable by generating too many threads. Remember, each Thread needs it's own stack, so that's at least 2MB of memory overhead per thread you create, plus the overhead in memory allocation, Thread switching, and so on involved.

And your code tries to create 500 threads - in a system which is likely to have 2, 4, or 8 cores - but probably nowhere near 500!

As a general rule of thumb: give the Thread count as low as possible, and certai9nly never exceed twice the number of cores!
 
Share this answer
 
Comments
Member 13174280 28-Jan-21 11:11am    
thanks I'm at my first experiments with Parallel, applying the suggestions the loop is completed as long as I don't associate a control to another one.

limited the number of threads to 2

var options = new ParallelOptions()
{
MaxDegreeOfParallelism = 2
};

with association pnlCatalogo.Controls.Add(nDia[i]) , Cross-threading exception is guaranteed.

public void TestCornici(int i, Panel pnlImmagini)
{
numeroDia[i] = new Label();
pnlCatalogo.Controls.Add(numeroDia[i]); --> Cross-threading exception

.... without association
//pnlCatalogo.Controls.Add(numeroDia[i]); --> correct cycle
numeroDia[i].BorderStyle = BorderStyle.None;
.....
}

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900