Cannot get the Application Thread to Handle Event

G

Guest

Environment:
Visual Studio 2005, Beta 2
..Net 2.0
Windows XP, SP2
C#
Generics
-------------------------------

Hi,
I have a Windows Form whose contents I would like to dynamically change. I
also plan to put this form in a class library, along with a facade class.

This facade class will start the form, along with a Windows Message Loop
using Application.Run(new MyForm(ref MyQueue))

Moreover, the facade class has a method by which the user can add new
controls (of the same type) at runtime. The strategy used is this:
The Client class creates a Facade member object
The client schedules a function on the CLR threadpool. This function randomly calls Facade.AddNewControl(string name)
Next the Client Calls Facade.Start(string name). This order is chosen, since Application.Run is a blocking call
In Facade.AddNewControl(string name), we add the string 'name' to a Queue<string>. Note that this queue is passed as reference to the form class
The Form class spawns a Worker thread that scans the queue and raises custom events, whenever there is an entry available.
The Form also defines an event handler to handle this event, wherein it creates a new control and adds it.

What I observe is that the event handler gets called on the Worker thread
and not on the main form thread. Hence, the exception "Caanot assign controls
created on one thread to another" is thrown.

How do I get around this problem? Does it help if the event generation is
done in a seperate class?
 
D

Daniel O'Connell [C# MVP]

What I observe is that the event handler gets called on the Worker thread
and not on the main form thread. Hence, the exception "Caanot assign
controls
created on one thread to another" is thrown.

How do I get around this problem? Does it help if the event generation is
done in a seperate class?

You'll need to use the Invoke method of your form. I assume you mean a
custom event here, so change your raise method to send the delegates to
Invoke() which will execute it on the UI thread.
 
G

Guest

Code Sample:
---------------------------------------------------------------------------
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Threading;

namespace WindowsApplication1
{
public delegate void MyEventHandler(object o, MyEventArgs e);

public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.Panel panel1;
private event MyEventHandler MyEvent;
private System.ComponentModel.Container components = null;

public Form1()
{
InitializeComponent();
this.MyEvent +=new MyEventHandler(Form1_MyEvent);
ThreadPool.QueueUserWorkItem(new WaitCallback(Go));
}

private void Go(object o)
{
while(true)
{
MyEventArgs e = new MyEventArgs();
MyEvent(this,e);
Thread.Sleep(1000);
}
}

[STAThread]
static void Main()
{
Application.Run(new Form1());
}

private void Form1_MyEvent(object o, MyEventArgs e)
{
Button b = new Button();
Random r = new Random();
b.Left = (int)(r.NextDouble() * 10.0);
this.panel1.Controls.Add(b);
}
}
}
 
D

Daniel O'Connell [C# MVP]

Rajiv Das said:
Code Sample:
---------------------------------------------------------------------------
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Threading;

namespace WindowsApplication1
{
public delegate void MyEventHandler(object o, MyEventArgs e);

public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.Panel panel1;
private event MyEventHandler MyEvent;
private System.ComponentModel.Container components = null;

public Form1()
{
InitializeComponent();
this.MyEvent +=new MyEventHandler(Form1_MyEvent);
ThreadPool.QueueUserWorkItem(new WaitCallback(Go));
}

private void Go(object o)
{
while(true)
{
MyEventArgs e = new MyEventArgs();
//MyEvent(this,e);
Invoke(MyEvent, this, e); //<-- add this line, it should marshal your
delegate over to the control's thread.
Thread.Sleep(1000);
}
}

[STAThread]
static void Main()
{
Application.Run(new Form1());
}

private void Form1_MyEvent(object o, MyEventArgs e)
{
Button b = new Button();
Random r = new Random();
b.Left = (int)(r.NextDouble() * 10.0);
this.panel1.Controls.Add(b);
}
}
}
 
G

Guest

Daniel,

It works with a slight modification.

MyEventArgs e = new MyEventArgs();
MyEventHandler m = new MyEventHandler(Form1_MyEvent);
object []args = {this,e};
this.Invoke(m,args);

Thanks a zillion.
Rajiv Das


Daniel O'Connell said:
Rajiv Das said:
Code Sample:
---------------------------------------------------------------------------
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Threading;

namespace WindowsApplication1
{
public delegate void MyEventHandler(object o, MyEventArgs e);

public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.Panel panel1;
private event MyEventHandler MyEvent;
private System.ComponentModel.Container components = null;

public Form1()
{
InitializeComponent();
this.MyEvent +=new MyEventHandler(Form1_MyEvent);
ThreadPool.QueueUserWorkItem(new WaitCallback(Go));
}

private void Go(object o)
{
while(true)
{
MyEventArgs e = new MyEventArgs();
//MyEvent(this,e);
Invoke(MyEvent, this, e); //<-- add this line, it should marshal your
delegate over to the control's thread.
Thread.Sleep(1000);
}
}

[STAThread]
static void Main()
{
Application.Run(new Form1());
}

private void Form1_MyEvent(object o, MyEventArgs e)
{
Button b = new Button();
Random r = new Random();
b.Left = (int)(r.NextDouble() * 10.0);
this.panel1.Controls.Add(b);
}
}
}
 

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