Problem creating controls from other thread w/ invoke

  • Thread starter Michael Groeger
  • Start date
M

Michael Groeger

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
 
S

Stoitcho Goutsev \(100\) [C# MVP]

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


--
HTH
Stoitcho Goutsev (100) [C# MVP]

Michael Groeger said:
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
 
M

Michael Groeger

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



Stoitcho Goutsev (100) said:
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);


--
HTH
Stoitcho Goutsev (100) [C# MVP]

Michael Groeger said:
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
 
S

Stoitcho Goutsev \(100\) [C# MVP]

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);
}
}


--
HTH
Stoitcho Goutsev (100) [C# MVP]

Michael Groeger said:
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



Stoitcho Goutsev (100) said:
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);


--
HTH
Stoitcho Goutsev (100) [C# MVP]

Michael Groeger said:
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
 
M

Michael Groeger

Stoitcho,

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

Regards,
Michael

Stoitcho Goutsev (100) said:
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);
}
}


--
HTH
Stoitcho Goutsev (100) [C# MVP]

Michael Groeger said:
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



Stoitcho Goutsev (100) said:
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);


--
HTH
Stoitcho Goutsev (100) [C# MVP]

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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top