I am trying to make a window that pops up, to show that my application
is busy. I want it to be able to be called from anywhere, any thread,
so I put it as a static method in a class.

Code listed below.

The problem is, no matter what I can think of doing, I get the
following exception:

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

Trace:
at System.Windows.Forms.Control.MarshaledInvoke(Control caller,
Delegate method, Object[] args, Boolean synchronous)
at System.Windows.Forms.Control.Invoke(Delegate method, Object[]
args)
at UI.Waiter.Busy(Object waitOn)

or i used to get this with a slightly different configuration (same
exception):
Trace:
at System.Windows.Forms.ControlCollection.Add(Control value)
at System.Windows.Forms.ControlCollection.Add(Control value)
at UI.Controls.WaitForm.InitializeComponent()
at UI.Controls.WaitForm..ctor()
at UI.Waiter..cctor()


Anyone got any ideas... or am i going about it the wrong way all
together!?

Cheers
Greg



----- CODE -----

using System;
using System.Collections;
using System.Threading;
using System.Windows.Forms;

namespace UI
{
/// <summary>
/// Summary description for Waiter.
/// </summary>
public sealed class Waiter
{
private static ArrayList _list = new ArrayList();
private static Mutex _lock = new Mutex();
private static Controls.WaitForm _form = null;

private static Form _parent = null;
public static Form Parent { get { return _parent; } set { _parent =
value; } }

private Waiter()
{
}

private delegate void BusyDelegate( object obj );
public static void Busy( object waitOn )
{
if( _parent != null )
_parent.Invoke( new BusyDelegate( InternalBusy ), new object[] {
waitOn } );
}

private static void InternalBusy( object waitOn )
{
// this has to be done here for threading reasons
if( _form == null )
_form = new Controls.WaitForm();

// show the waiting form
_lock.WaitOne();
try
{
_list.Add( waitOn );
if( _list.Count == 1 )
{
_form.Restart();
_form.Show();
System.Windows.Forms.Application.DoEvents();
}
}
finally
{
_lock.ReleaseMutex();
}
}

public static void Ready( object waitOn )
{
_lock.WaitOne();
try
{
_list.Remove( waitOn );
if( _list.Count == 0 )
{
_form.Hide();
}
}
finally
{
_lock.ReleaseMutex();
}
}
}
}

RE: Controls created on one thread cannot be parented to a control on by jch

jch
Mon Oct 18 02:41:03 CDT 2004

A form/control may only be accessed by the thread owning the control. All
calls to a form on another thread must be serialized by calling
Control.Invoke
(http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemcomponentmodelisynchronizeinvokeclasstopic.asp).
As a result, the parent of a form must live on the same thread as the form
itself. So you will have to change your design a bit. Do you need to set
the parent of your popup form?

Regards, Jakob.


"gregbacchus@hotmail.com" wrote:

> I am trying to make a window that pops up, to show that my application
> is busy. I want it to be able to be called from anywhere, any thread,
> so I put it as a static method in a class.
>
> Code listed below.
>
> The problem is, no matter what I can think of doing, I get the
> following exception:
>
> "Controls created on one thread cannot be parented to a control on a
> different thread"
>
> Trace:
> at System.Windows.Forms.Control.MarshaledInvoke(Control caller,
> Delegate method, Object[] args, Boolean synchronous)
> at System.Windows.Forms.Control.Invoke(Delegate method, Object[]
> args)
> at UI.Waiter.Busy(Object waitOn)
>
> or i used to get this with a slightly different configuration (same
> exception):
> Trace:
> at System.Windows.Forms.ControlCollection.Add(Control value)
> at System.Windows.Forms.ControlCollection.Add(Control value)
> at UI.Controls.WaitForm.InitializeComponent()
> at UI.Controls.WaitForm..ctor()
> at UI.Waiter..cctor()
>
>
> Anyone got any ideas... or am i going about it the wrong way all
> together!?
>
> Cheers
> Greg
>
>
>
> ----- CODE -----
>
> using System;
> using System.Collections;
> using System.Threading;
> using System.Windows.Forms;
>
> namespace UI
> {
> /// <summary>
> /// Summary description for Waiter.
> /// </summary>
> public sealed class Waiter
> {
> private static ArrayList _list = new ArrayList();
> private static Mutex _lock = new Mutex();
> private static Controls.WaitForm _form = null;
>
> private static Form _parent = null;
> public static Form Parent { get { return _parent; } set { _parent =
> value; } }
>
> private Waiter()
> {
> }
>
> private delegate void BusyDelegate( object obj );
> public static void Busy( object waitOn )
> {
> if( _parent != null )
> _parent.Invoke( new BusyDelegate( InternalBusy ), new object[] {
> waitOn } );
> }
>
> private static void InternalBusy( object waitOn )
> {
> // this has to be done here for threading reasons
> if( _form == null )
> _form = new Controls.WaitForm();
>
> // show the waiting form
> _lock.WaitOne();
> try
> {
> _list.Add( waitOn );
> if( _list.Count == 1 )
> {
> _form.Restart();
> _form.Show();
> System.Windows.Forms.Application.DoEvents();
> }
> }
> finally
> {
> _lock.ReleaseMutex();
> }
> }
>
> public static void Ready( object waitOn )
> {
> _lock.WaitOne();
> try
> {
> _list.Remove( waitOn );
> if( _list.Count == 0 )
> {
> _form.Hide();
> }
> }
> finally
> {
> _lock.ReleaseMutex();
> }
> }
> }
> }
>
>

Re: Controls created on one thread cannot be parented to a control on a different thread by Herfried

Herfried
Mon Oct 18 05:46:02 CDT 2004

<gregbacchus@hotmail.com> schrieb:
>I am trying to make a window that pops up, to show that
> my application is busy. I want it to be able to be called from
> anywhere, any thread, so I put it as a static method in a class.

Always show your forms in the app's main UI thread and use 'Control.Invoke'
to communicate in the tread -> UI direction:

Multithreading:

<URL:http://msdn.microsoft.com/library/en-us/dnforms/html/winforms06112002.asp>
<URL:http://msdn.microsoft.com/library/en-us/dnforms/html/winforms08162002.asp>
<URL:http://msdn.microsoft.com/library/en-us/dnforms/html/winforms01232003.asp>

<URL:http://www.devx.com/dotnet/Article/11358/>

<URL:http://msdn.microsoft.com/library/en-us/cpref/html/frlrfSystemWindowsFormsControlClassInvokeTopic.asp>

Multithreading in Visual Basic .NET (Visual Basic Language Concepts)
<URL:http://msdn.microsoft.com/library/en-us/vbcn7/html/vaconthreadinginvisualbasic.asp>

Sample:

<URL:http://dotnet.mvps.org/dotnet/samples/filesystem/downloads/FileSystemEnumerator.zip>

--
Herfried K. Wagner [MVP]
<URL:http://dotnet.mvps.org/>


Re: Controls created on one thread cannot be parented to a control on a different thread by Stoitcho

Stoitcho
Mon Oct 18 09:19:32 CDT 2004

Hi Giedriusm,

This is Windows OS requirement rather that Windows Forms. This is done
because winprocs are not re-entrant and threadsafe in almost all of the
cases. To make them so requires I great deal of programing discipline, which
will make windows programming harder, but the benefit would be not so big.
To make programing easier windows streams all calls to the winproc (sending
and posting messages) thru the creator's thread's message pump. For posted
messages it comes naturally, sended messages go thru the messsage only when
they cross threads' boundaries. That is all gread and all progarmmers get
advantages of this feature, but beacuse all the communication between
parents and their children (like request, responses, notifications, etc) are
based on window messages there are big chances of deadlocks if the parent
and the child are created by separated threads. That's why Windows checks
and doesn't allow control created in one thread to parent controls created
in different one.



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


<gregbacchus@hotmail.com> wrote in message
news:1098076912.818448.164800@c13g2000cwb.googlegroups.com...
>I am trying to make a window that pops up, to show that my application
> is busy. I want it to be able to be called from anywhere, any thread,
> so I put it as a static method in a class.
>
> Code listed below.
>
> The problem is, no matter what I can think of doing, I get the
> following exception:
>
> "Controls created on one thread cannot be parented to a control on a
> different thread"
>
> Trace:
> at System.Windows.Forms.Control.MarshaledInvoke(Control caller,
> Delegate method, Object[] args, Boolean synchronous)
> at System.Windows.Forms.Control.Invoke(Delegate method, Object[]
> args)
> at UI.Waiter.Busy(Object waitOn)
>
> or i used to get this with a slightly different configuration (same
> exception):
> Trace:
> at System.Windows.Forms.ControlCollection.Add(Control value)
> at System.Windows.Forms.ControlCollection.Add(Control value)
> at UI.Controls.WaitForm.InitializeComponent()
> at UI.Controls.WaitForm..ctor()
> at UI.Waiter..cctor()
>
>
> Anyone got any ideas... or am i going about it the wrong way all
> together!?
>
> Cheers
> Greg
>
>
>
> ----- CODE -----
>
> using System;
> using System.Collections;
> using System.Threading;
> using System.Windows.Forms;
>
> namespace UI
> {
> /// <summary>
> /// Summary description for Waiter.
> /// </summary>
> public sealed class Waiter
> {
> private static ArrayList _list = new ArrayList();
> private static Mutex _lock = new Mutex();
> private static Controls.WaitForm _form = null;
>
> private static Form _parent = null;
> public static Form Parent { get { return _parent; } set { _parent =
> value; } }
>
> private Waiter()
> {
> }
>
> private delegate void BusyDelegate( object obj );
> public static void Busy( object waitOn )
> {
> if( _parent != null )
> _parent.Invoke( new BusyDelegate( InternalBusy ), new object[] {
> waitOn } );
> }
>
> private static void InternalBusy( object waitOn )
> {
> // this has to be done here for threading reasons
> if( _form == null )
> _form = new Controls.WaitForm();
>
> // show the waiting form
> _lock.WaitOne();
> try
> {
> _list.Add( waitOn );
> if( _list.Count == 1 )
> {
> _form.Restart();
> _form.Show();
> System.Windows.Forms.Application.DoEvents();
> }
> }
> finally
> {
> _lock.ReleaseMutex();
> }
> }
>
> public static void Ready( object waitOn )
> {
> _lock.WaitOne();
> try
> {
> _list.Remove( waitOn );
> if( _list.Count == 0 )
> {
> _form.Hide();
> }
> }
> finally
> {
> _lock.ReleaseMutex();
> }
> }
> }
> }
>



Re: Controls created on one thread cannot be parented to a control on a different thread by gregbacchus

gregbacchus
Mon Oct 18 15:35:17 CDT 2004

That's what I thought I am doing in public static void Busy( object
waitOn ) with the parent.Invoke... where parent is the main UI form.


Re: Controls created on one thread cannot be parented to a control on by gregbacchus

gregbacchus
Mon Oct 18 15:37:31 CDT 2004

That's what I am doing in public static void Busy( object waitOn ). The
parent is the Main Window of the application for that reason. So that
with the invoke, the whole thing should be happening in the thread of
the Main form. Or am I wrong??


Re: Controls created on one thread cannot be parented to a control on a different thread by Stoitcho

Stoitcho
Mon Oct 18 16:00:02 CDT 2004

Windows, doesn't allow parenting controls created in different thread in the
first place. Win32 API fails when you try to do that so, you won't get to
the point where you call the parent's Invoke mehod

--

Stoitcho Goutsev (100) [C# MVP]


<gregbacchus@hotmail.com> wrote in message
news:1098131716.974825.128840@z14g2000cwz.googlegroups.com...
> That's what I thought I am doing in public static void Busy( object
> waitOn ) with the parent.Invoke... where parent is the main UI form.
>



Re: Controls created on one thread cannot be parented to a control on a different thread by gregbacchus

gregbacchus
Mon Oct 18 16:24:43 CDT 2004

The class "Waiter" is not a Control. The only point of the Parent
property is so that I can use invoke on the Main UI Thread.

So I set the Parent Property and the call Busy(). This should, by my
understanding call InternalBusy in the thread of Parent. It is here
that is the Popup form is created and all its controls are added....
all in the thread of the Parent Form (main UI form)... Then as its all
happening in this thread, why then is it coming up with the error??
Cheers

Greg


Re: Controls created on one thread cannot be parented to a control on a different thread by Stoitcho

Stoitcho
Tue Oct 19 09:23:47 CDT 2004

Yes that part of your code is correct.
However, from what I can see in the stack trace the Waiter class has a
static constructor which actually creates the WaitForm control. The type is
loaded and static constructor is executed by the thread where the first time
the instance of the object is created or method is accessed (depending on
what type of initialization is set). So if you create the form in the static
constructor it is possible that it is created not in the UI thread.
IMHO the code snippet you posted doesn't match the stack trace. At least it
doesn' show the point where you add the WaitForm control to the parent's
Control collection. This is actually the place where the exception is
thrown.

If you can post some working example that demonstrates the problem. That
would help to isolate the problem faster.

--
HTH

Stoitcho Goutsev (100) [C# MVP]


<gregbacchus@hotmail.com> wrote in message
news:1098134683.315128.197320@z14g2000cwz.googlegroups.com...
> The class "Waiter" is not a Control. The only point of the Parent
> property is so that I can use invoke on the Main UI Thread.
>
> So I set the Parent Property and the call Busy(). This should, by my
> understanding call InternalBusy in the thread of Parent. It is here
> that is the Popup form is created and all its controls are added....
> all in the thread of the Parent Form (main UI form)... Then as its all
> happening in this thread, why then is it coming up with the error??
> Cheers
>
> Greg
>