Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsFree MagazinesWhite PapersSubmit Content
Discussion GroupsASP.NETWindows FormsLanguages.NET FrameworkVisual Studio.NET
Articles.NET FrameworkASP.NETToolsWindows Forms
.NET DirectoryOpen Source ProjectsUser GroupsWeb Resources
Related Topics
Visual Basic 6SQL ServerMS AccessOther DB ProductsMS Server ProductsMore Topics ...

.NET Forum / Windows Forms / WinForm General / December 2005

Tip: Looking for answers? Try searching our database.

Problem creating controls from other thread w/ invoke

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
Michael Groeger - 08 Dec 2005 10:14 GMT
Hi,

I have a form which acts as monitor for a service. The form and the monitor
communicate via remoting. Because it takes some time for the service to
startup some controls are added to the form when a certain event is raised
by the service.

However, when handling this event I do the following:

--------- snip ---------

private void EventProxy_Initialized(object sender, EventArgs e)
{
   MethodInvoker invoker = new
MethodInvoker(this.CreateCommunicatorControls);
   this.Invoke(invoker);
}

private void CreateCommunicatorControls()
{
   // create controls and add them to a panel on the form
   this.panelCommunicator.Controls.Add(newCommCtrl);
   [...]
}

--------- snip ---------

The panel on the form is created from the main UI thread of the form., but I
still get the exception "Controls created on one thread cannot be parented
to controls on a different thread" when adding the new control to the panel.

Does anybody know what the problem is?

Regards,
Michael
Stoitcho Goutsev (100) [C# MVP] - 08 Dec 2005 14:45 GMT
Michael,

You cannot parent control created in different threads. This Windows OS
restriction. Further mode you cannot call methods and set properties of a
control from a different thread than the one created the control.

In remoting scenarious this could be kind of tricky because all
notifications that comes form the remote objects are executed in worker
threads from the thread pool. Use Control.Invoke to marshal them to the UI
thread.

Why do you need to start this new thread in order to create the controls?

I hope you know that the following code executes
this.CreateCommunicatorControls in a thread from the thread pool

> MethodInvoker invoker = new
> MethodInvoker(this.CreateCommunicatorControls);
>    this.Invoke(invoker);

Signature

HTH
Stoitcho Goutsev (100) [C# MVP]

> Hi,
>
[quoted text clipped - 34 lines]
> Regards,
> Michael
Michael Groeger - 08 Dec 2005 15:16 GMT
Hi Stoitcho,

I know that I cannot parent control created in different threads. That's why
I am already invoking the main UI thread (see the EventHandler
EventProxy_Initialized). It's very strange what's going on there which I saw
after modifying the code a little:

--------- snip ---------

private void EventProxy_Initialized(object sender, EventArgs e)
{
   CreateCommunicatorControls();
}

private void CreateCommunicatorControls()
{
   System.Diagnostics.Trace.WriteLine("CreateCommunicatorControls called");

   // check for invokation
   if (this.InvokeRequired)
   {
       System.Diagnostics.Trace.WriteLine("Invoke was required");
       MethodInvoker invoker = new
MethodInvoker(this.CreateCommunicatorControls);
       this.Invoke(invoker);
   }
   else
               System.Diagnostics.Trace.WriteLine("Invoke was not
required");
   try
   {
       [...]
       // create controls and add them to a panel on the form
       this.panelCommunicator.Controls.Add(newCommCtrl);
       [...]
   }
   catch (Exception e)
   {
       System.Diagnostics.Trace.WriteLine(e.Message);
   }
}

--------- snip ---------

After executing the code the output was the following:
CreateCommunicatorControls called
Invoke was required
CreateCommunicatorControls called
Invoke was not required
Controls created on one thread cannot be parented to controls on a different
thread

I was somehow wondered and diagnosted that the panelCommunicator was running
on a different UI thread, because this.panelCommunicator.InvokeRequired
returned true. I still do not understand why because the panel gets created
in the forms constructor's InitializeComponent() method.

To answer your question Stoitcho:
I am getting a remote event via remoting. Since this event is not raised
from the UI thread I am required to create the controls from a different and
invoke the main UI thread from that one. Each event registers a control,
prior to the event I do not know how many controls I need, that's why the
controls get created dynamically.

Regards,
Michael

> Michael,
>
[quoted text clipped - 58 lines]
> > Regards,
> > Michael
Stoitcho Goutsev (100) [C# MVP] - 08 Dec 2005 16:00 GMT
Michael,

Sorry, I saw wrong. I though (saw) that you call Invoke on the invoker
object.
The problem is here:
After you check that the call requires Invoke you correctly invoke the
method in the UI thread. And the UI thread calls the methods recursively.
This time InvokeRequired is false and you continue with control creation
that by all rules succeeds.

The methods executed by the UI thread finishes and the worker thread
continues after the call *this.Invoke()*. At this point you should do
*return* to cancel execution for the rest of the code. You fail to do that
(no *return* statement) so the execution continues and goes through the code
of creating the control again this time in the worker thread. And here is
the moment where you get the exception.

You should change the code to look like

if (this.InvokeRequired)
{
       System.Diagnostics.Trace.WriteLine("Invoke was required");
       MethodInvoker invoker = new
MethodInvoker(this.CreateCommunicatorControls);
       this.Invoke(invoker);
}

private void CreateCommunicatorControls()
{
   System.Diagnostics.Trace.WriteLine("CreateCommunicatorControls called");

   // check for invokation
   if (this.InvokeRequired)
   {
       System.Diagnostics.Trace.WriteLine("Invoke was required");
       MethodInvoker invoker = new
            MethodInvoker(this.CreateCommunicatorControls);
       this.Invoke(invoker);
           return; //NOTE: PAY ATTENTION ON THIS *RETURN*
   }

   // YOU DON'T NEED THE ELSE CLAUSE SINCE THE EXECUTION WON'T COME HERE IF
INVOKE IS REQUIRED

   System.Diagnostics.Trace.WriteLine("Invoke was not required");

   try
   {
       [...]
       // create controls and add them to a panel on the form
       this.panelCommunicator.Controls.Add(newCommCtrl);
       [...]
   }
   catch (Exception e)
   {
       System.Diagnostics.Trace.WriteLine(e.Message);
   }
}

Signature

HTH
Stoitcho Goutsev (100) [C# MVP]

> Hi Stoitcho,
>
[quoted text clipped - 136 lines]
>> > Regards,
>> > Michael
Michael Groeger - 09 Dec 2005 09:31 GMT
Stoitcho,

oh sorry, I forgot this one. This of course could have been the reason why
...thanks!

Regards,
Michael

> Michael,
>
[quoted text clipped - 199 lines]
> >> > Regards,
> >> > Michael

Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.