PC Review


Reply
Thread Tools Rate Thread

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

 
 
gregbacchus@hotmail.com
Guest
Posts: n/a
 
      18th Oct 2004
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();
}
}
}
}

 
Reply With Quote
 
 
 
 
=?Utf-8?B?SmFrb2IgQ2hyaXN0ZW5zZW4=?=
Guest
Posts: n/a
 
      18th Oct 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/de...classtopic.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.


"(E-Mail Removed)" 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();
> }
> }
> }
> }
>
>

 
Reply With Quote
 
Herfried K. Wagner [MVP]
Guest
Posts: n/a
 
      18th Oct 2004
<(E-Mail Removed)> 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/>

 
Reply With Quote
 
Stoitcho Goutsev \(100\) [C# MVP]
Guest
Posts: n/a
 
      18th Oct 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]


<(E-Mail Removed)> wrote in message
news:(E-Mail Removed)...
>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();
> }
> }
> }
> }
>



 
Reply With Quote
 
gregbacchus@hotmail.com
Guest
Posts: n/a
 
      18th Oct 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.

 
Reply With Quote
 
gregbacchus@hotmail.com
Guest
Posts: n/a
 
      18th Oct 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??

 
Reply With Quote
 
Stoitcho Goutsev \(100\) [C# MVP]
Guest
Posts: n/a
 
      18th Oct 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]


<(E-Mail Removed)> wrote in message
news:(E-Mail Removed)...
> 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.
>



 
Reply With Quote
 
gregbacchus@hotmail.com
Guest
Posts: n/a
 
      18th Oct 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

 
Reply With Quote
 
Stoitcho Goutsev \(100\) [C# MVP]
Guest
Posts: n/a
 
      19th Oct 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]


<(E-Mail Removed)> wrote in message
news:(E-Mail Removed)...
> 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
>



 
Reply With Quote
 
 
 
Reply

Thread Tools
Rate This Thread
Rate This Thread:

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Threading question "Controls created on one thread cannot be parented to a control on a different thread." VMI Microsoft C# .NET 1 17th Jan 2005 09:53 PM
controls create on one thread cannot be parented to a control on different threa Mamatha Microsoft VB .NET 1 6th Oct 2004 11:05 AM
propertygrid throwing error "Controls created on one thread cannot be parented to a control on a diffrent thread." jaire Microsoft C# .NET 10 21st Aug 2004 04:17 PM
Controls Created on One Thread Cannot Be Parented to a Control on a Different Thread William Ryan Microsoft ADO .NET 0 8th Sep 2003 10:14 PM
Re: propertygrid throwing error "Controls created on one thread cannot be parented to a control on a diffrent thread." Greg Bacchus Microsoft C# .NET 1 18th Jul 2003 08:38 AM


Features
 

Advertising
 

Newsgroups
 


All times are GMT +1. The time now is 11:06 AM.