Main thread calling event from child thread without using Ctrl.Inv

G

Guest

Hi ,

I build an object with a method and an event.
In the method, I start a thread(child thread) and after a long process, the
event is raised (from the child thread unfortunately).

When I use this object in my form (main UI thread), I get an error which
tells me to use Textbox.Invoke (which I understand and I know how to solve
the error from my form). No problem.

The problem is I want the event to be raised in main thread, so no
Textbox.Invoke error will be thrown in my form.
I mean when the child thread wants to raise the event, I want to tell to use
the main thread of my object instead of the child thread.
So no Textbox.Invoke required in my main UI thread.

Thanks in advance for your help.
 
D

Dan Manges

Noulouk said:
Hi ,

I build an object with a method and an event.
In the method, I start a thread(child thread) and after a long process, the
event is raised (from the child thread unfortunately).

When I use this object in my form (main UI thread), I get an error which
tells me to use Textbox.Invoke (which I understand and I know how to solve
the error from my form). No problem.

The problem is I want the event to be raised in main thread, so no
Textbox.Invoke error will be thrown in my form.
I mean when the child thread wants to raise the event, I want to tell to use
the main thread of my object instead of the child thread.
So no Textbox.Invoke required in my main UI thread.

Thanks in advance for your help.

If I understand your problem correctly, you should be able to have a
method in your class which will raise the event, and then invoke that
method from the other thread.

A not-guaranteed-to-compile example:

public class Program
{
public delegate void SomeHandler();
public event SomeHandler OnEvent;

private delegate void NoArgCallback();

public void RaiseEvent()
{
if (OnEvent != null)
OnEvent();
}

public void StartThread()
{
Thread thread = new Thread(new ThreadStart(ThreadMethod));
thread.Start();
}

private void ThreadMethod()
{
NoArgCallback callback = new NoArgCallback(RaiseEvent);
this.Invoke(callback);
}
}

This will raise the event from the UI thread.

Hope this helps.

Dan Manges
 
T

Techno_Dex

In your EventHandler which is catching the Event Raised from the Child
Thread, call another method which will call itself if not currently
processing on the UI Thread, then handle your code or raise a new event from
there.

private void ChildThread_EventHandler(object sender, EventArgs e)
{
DoWork(e);
}

private void DoWork(EventArgs e)
{
//Check To see if you are currently running on the UI Thread or not, If
not, use the Generic MethodInvoker
//to create a Delegate to call a method on the UI Thread (In this case,
the same Method only on the UI Thread)
if (this.InvokeRequired == true)
{
MethodInvoker miMethodInvoker = new MethodInvoker(DoWork);
//If the DoWork Method did not take in the EventArgs or any params
from the ChildThread, this you would use this.
//miMethodInvoker.BeginInvoke(null, null);
miMethodInvoker.BeginInvoke(null, new object[] (e});
return;
}

//If you get to this point you are now on your UI Thread and you can
update your TextBox as needed or raise a new event.
tbTextBox.Text = e.Value;
}
 
G

Guest

When I use this object in my form (main UI thread), I get an error whichAs you can read I know how to solve this problem and that's your answer.

I'm sorry if I have also problems to expose this problem. lol

In fact, don't mind about the main UI thread.
Let's focus on my object: this object when it is instanciated runs inside a
thread. I start a child thread with an object method. An event is raised
inside the child thread, but I want this event to be raised inside its parent
thread (object thread).

internal class TestClass
{
public event EventHandler MyEvent;

public void MyMethod()
{
Thread.CurrentThread.Name = "Main";
Thread child = new Thread(new ThreadStart(ChildMethod));
child.Start();
}

void RaiseEvent( object sender, EventArgs e )
{
Console.WriteLine("On thread: " + Thread.CurrentThread.Name);
if ( MyEvent != null )
MyEvent( sender, e );
}

private void ChildMethod()
{
// some job
RaiseEvent(this, null); //on child thread. I want to raise this
event on parent Main thread
// some job
}
}

Hope you see what I need.

Techno_Dex said:
In your EventHandler which is catching the Event Raised from the Child
Thread, call another method which will call itself if not currently
processing on the UI Thread, then handle your code or raise a new event from
there.

private void ChildThread_EventHandler(object sender, EventArgs e)
{
DoWork(e);
}

private void DoWork(EventArgs e)
{
//Check To see if you are currently running on the UI Thread or not, If
not, use the Generic MethodInvoker
//to create a Delegate to call a method on the UI Thread (In this case,
the same Method only on the UI Thread)
if (this.InvokeRequired == true)
{
MethodInvoker miMethodInvoker = new MethodInvoker(DoWork);
//If the DoWork Method did not take in the EventArgs or any params
from the ChildThread, this you would use this.
//miMethodInvoker.BeginInvoke(null, null);
miMethodInvoker.BeginInvoke(null, new object[] (e});
return;
}

//If you get to this point you are now on your UI Thread and you can
update your TextBox as needed or raise a new event.
tbTextBox.Text = e.Value;
}


Noulouk said:
Hi ,

I build an object with a method and an event.
In the method, I start a thread(child thread) and after a long process,
the
event is raised (from the child thread unfortunately).

When I use this object in my form (main UI thread), I get an error which
tells me to use Textbox.Invoke (which I understand and I know how to solve
the error from my form). No problem.

The problem is I want the event to be raised in main thread, so no
Textbox.Invoke error will be thrown in my form.
I mean when the child thread wants to raise the event, I want to tell to
use
the main thread of my object instead of the child thread.
So no Textbox.Invoke required in my main UI thread.

Thanks in advance for your help.
 
D

Dan Manges

Noulouk wrote:
[snip]
private void ChildMethod()
{
// some job
RaiseEvent(this, null); //on child thread. I want to raise this
event on parent Main thread
// some job
}
}

Hope you see what I need.
[snip]

Why can't you use an Invoke method from ChildMethod() to call RaiseEvent() ?

Dan Manges
 
S

Stoitcho Goutsev \(100\)

Dan,

To work your sample the class Program needs to inherit from Control.
Otherwise there is no Invoke method that will marshal the method call.
Delegates has Invoke also, but Control.Invoke and BeginInvoke are the only
methods that marhal the method calls to the UI thread. For some reason the
original poster doesn't want to use Control.Invoke.

BTW .NET 2.0 has BackgroundWorker component that is capable to marshal its
events to the UI thread without the requirements of a control. I've peeked
in the code there, but had no time to get too deep to understand how it
actually does this.
 
S

Stoitcho Goutsev \(100\)

Noulouk,

I don't think you can pull this off without using Control.Invoke.
BackgroundWorker from .NET 2.0. does that and if you have enough time you
can dig into its code to find out how it does it.
My suggestion is to do the same that System.Timers.Timer component does.
This class has a property called SynchronizingObject of type
ISynchronizeInvoke. If an object implements this interface it has to make
sure that the call is marshaled to appropriate thread if necessary. At the
moment only the Control class implement this interface.

When your object needs to fire the event it checks whether the property is
set if it is, it uses objects Invoke method otherwise it fires the event in
the usual way.


--
HTH
Stoitcho Goutsev (100)

Noulouk said:
When I use this object in my form (main UI thread), I get an error which
As you can read I know how to solve this problem and that's your answer.

I'm sorry if I have also problems to expose this problem. lol

In fact, don't mind about the main UI thread.
Let's focus on my object: this object when it is instanciated runs inside
a
thread. I start a child thread with an object method. An event is raised
inside the child thread, but I want this event to be raised inside its
parent
thread (object thread).

internal class TestClass
{
public event EventHandler MyEvent;

public void MyMethod()
{
Thread.CurrentThread.Name = "Main";
Thread child = new Thread(new ThreadStart(ChildMethod));
child.Start();
}

void RaiseEvent( object sender, EventArgs e )
{
Console.WriteLine("On thread: " + Thread.CurrentThread.Name);
if ( MyEvent != null )
MyEvent( sender, e );
}

private void ChildMethod()
{
// some job
RaiseEvent(this, null); //on child thread. I want to raise this
event on parent Main thread
// some job
}
}

Hope you see what I need.

Techno_Dex said:
In your EventHandler which is catching the Event Raised from the Child
Thread, call another method which will call itself if not currently
processing on the UI Thread, then handle your code or raise a new event
from
there.

private void ChildThread_EventHandler(object sender, EventArgs e)
{
DoWork(e);
}

private void DoWork(EventArgs e)
{
//Check To see if you are currently running on the UI Thread or not,
If
not, use the Generic MethodInvoker
//to create a Delegate to call a method on the UI Thread (In this
case,
the same Method only on the UI Thread)
if (this.InvokeRequired == true)
{
MethodInvoker miMethodInvoker = new MethodInvoker(DoWork);
//If the DoWork Method did not take in the EventArgs or any
params
from the ChildThread, this you would use this.
//miMethodInvoker.BeginInvoke(null, null);
miMethodInvoker.BeginInvoke(null, new object[] (e});
return;
}

//If you get to this point you are now on your UI Thread and you can
update your TextBox as needed or raise a new event.
tbTextBox.Text = e.Value;
}


Noulouk said:
Hi ,

I build an object with a method and an event.
In the method, I start a thread(child thread) and after a long process,
the
event is raised (from the child thread unfortunately).

When I use this object in my form (main UI thread), I get an error
which
tells me to use Textbox.Invoke (which I understand and I know how to
solve
the error from my form). No problem.

The problem is I want the event to be raised in main thread, so no
Textbox.Invoke error will be thrown in my form.
I mean when the child thread wants to raise the event, I want to tell
to
use
the main thread of my object instead of the child thread.
So no Textbox.Invoke required in my main UI thread.

Thanks in advance for your help.
 
D

Dan Manges

Stoitcho said:
Dan,

To work your sample the class Program needs to inherit from Control.
Otherwise there is no Invoke method that will marshal the method call.
Delegates has Invoke also, but Control.Invoke and BeginInvoke are the only
methods that marhal the method calls to the UI thread. For some reason the
original poster doesn't want to use Control.Invoke.

BTW .NET 2.0 has BackgroundWorker component that is capable to marshal its
events to the UI thread without the requirements of a control. I've peeked
in the code there, but had no time to get too deep to understand how it
actually does this.
Stoitcho,

Thanks for pointing that out. I wrote that code like it was a
System.Windows.Forms.Form class, but I forgot to write that.

Dan Manges
 

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