.NET (296) administrative (41) Ajax (42) AngularJS (2) ASP.NET (145) bicycle (2) books (180) browser (8) C# (135) cars (1) chess (29) CodePlex (10) Coma (8) database (49) deployment (3) Entity Framework (2) essay (114) flash/shockwave (2) flex (1) food (3) friend (2) game (20) idea (5) IIS (8) javascript (83) LInQ (2) Linux (6) management (4) manga (43) misc (676) mobile (1) movies (92) MsAccess (1) murder (2) music (64) mysql (1) news (100) permanent (1) personal (68) PHP (1) physics (2) picture (309) places (12) politics (14) programming (507) rant (120) religion (3) science (43) Sharepoint (3) software (58) space (1) T4 (2) technology (12) Test Driven Development (4) translation (2) VB (2) video (98) Visual Studio (45) web design (46) Windows API (8) Windows Forms (3) Windows Server (6) WPF/Silverlight (63) XML (11)

Tuesday, May 02, 2006

Controls created on one thread cannot be parented to a control on a different thread error.

Trying to build a reusable object that is independent of the Windows or Web interface I've stumbled upon the issue of multiple threads trying to access and modify the same form. The ugly "Controls created on one thread cannot be parented to a control on a different thread." error occured and, no matter what I tried, it seemed it will never work. But finally I found out the solution.

First the issue:
doing something on the interface was starting a separate process that ran an external program. The interface has a progress bar that was updated during this. At the end of the process, an event was fired, and to that event I added a method that was supposed to clear the progress bar and put another UserControl on the form. The the error occured.

The problem was that the event was fired by the separate process that ran the external program. Trying to change something in the form that was created on another thread resulted in error.
The solution is that inside the method called by the event any references to methods that change the interface must be done through BeginInvoke:

private delegate void MethodDelegate(int i)

private void TestMethod(int i) {
// change interface here
}

private void OnEvent(object sender, EventArgs e) {
<interface_form_object>.BeginInvoke(new MethodDelegate(TestMethod),new
object[] {i});
// this replaces using TestMethod(i) which generates an error
}

Update on this:
Use the BackgroundWorker class in NET 2.0.

1 comment:

~Blog Author~ said...

This was a great post.