Firing event from thread in a component

G

Guest

Does anyone have example code that demonstrates how to fire an event on the
main thread of a GUI app from a thread within a component (not control)?

I'm sure that Control.Invoke is required, but do not know how to obtain the
control reference from the component.

In the full framework, this can be obtained from Delegate.Target. VS2005
documentation indicates that Delegate.Target is supported by Compact
Framework, but compiler reports "error CS0117: 'System.Delegate' does not
contain a definition for 'Target'"

This code works for full framework but not compact framwork.

void InvokeDelegate(Delegate del, params object[] args)
{
if (del == null)
return;
ISynchronizeInvoke synchronizer = del.Target as ISynchronizeInvoke;

// Test for GUI application
if ((synchronizer == null) || (!synchronizer.InvokeRequired))
{
// Not a GUI application
try
{
del.DynamicInvoke(args);
}
catch(Exception e)
{
Debug.Assert(false, "del.DynamicInvoke failed: " + e.Message);
}
return;
}

try
{
// GUI application
synchronizer.Invoke(del, args);
}
catch(Exception e)
{
Debug.Assert(false, "synchronizer.Invoke failed: " + e.Message);
}
}
 
G

Guest

Without a reference to a Control created on the primary thread you can't.
Why do you need to? Genrally, you can raise the event and let the UI
determine if it needs to Invoke.

Another option is to create a Control in the constructor of your Component
and then use Invoke through it. It will marshal the event to the thread
that created your component that way. If the Component was created by the
UI thread then you'll be fine.
 
G

Guest

Without a reference to a Control created on the primary thread you can't.

So this is a limitation of the Compact Framework? It can be done on the full
framework.
Why do you need to?

The GUI thread can configure the component to perform some background
(thread) operations and to notify the GUI via events when data has changed or
there is an error.
Genrally, you can raise the event and let the UI determine if it needs to Invoke.

I don't understand, please elaborate. Raising an event from another thread
causes internittent crashes on VS2003 and cross-threaded exception on VS2005.
Another option is to create a Control in the constructor of your Component
and then use Invoke through it.

Have you actually done this? If so, do you have any example code or can you
point me to a tech note?
 
G

Guest

Without a reference to a Control created on the primary thread you can't.
So this is a limitation of the Compact Framework? It can be done on the
full
framework.

Good for the full framework. However it's not necessary, so the CF team
omitted it.
I don't understand, please elaborate. Raising an event from another thread
causes internittent crashes on VS2003 and cross-threaded exception on
VS2005.

Of course, like any worker thread trying to affect UI controls. Does your
COmponent contain actual controls? If so, use them to Invoke. If not, then
the app that created your component should be checking to see if Invoke is
necessary in it's handler and taking care of the work there.
and then use Invoke through it.

Have you actually done this? If so, do you have any example code or can
you
point me to a tech note?

Yes, I have.

Something like this (this is all off the top of my head, so beware syntax,
etc)

class MyComponent
{
public event EventHandler MyEvent;
private Control m_control = new Control();

void RaiseMyEvent(object o, EventArgs e)
{
if(m_control.InvokeRequired)
{
m_control.Invoke(new EventHandler(RaiseMyEvent, new object[] {o, e}));
return;
}

if(MyEvent != null)
{
foreach(EventHandler eh in MyEvent.GetInvocationList())
{
eh(o, e);
}
}
}

void Foo()
{
DoSomeStuff();
RaiseMyEvent();
}
}
 
G

Guest

Of course, like any worker thread trying to affect UI controls. Does your
COmponent contain actual controls?

My component is not visible at runtime and contains no actual controls.
If so, use them to Invoke. If not, then the app that created your component should be checking to see if Invoke is necessary in it's handler and taking care of the work there.

I don't think it is reasonable for my component users to set up delegates,
check for InvokeRequired and call invoke, especially since the same users
that develop under full framework do not need to do any of that.
 
G

Guest

I don't think it is reasonable for my component users to set up delegates,
check for InvokeRequired and call invoke, especially since the same users
that develop under full framework do not need to do any of that.

You're not developing with the full framework, and Control.Invoke is
standard fare for CF developers. By your logic there are a *lot* of things
that developers shouldn't have to do since it's in the full framework and
you'd end up writing the full framework to support that.

If you don't want your users to have to marshal the events, you'll have to
do it yourself, but someone has to do it and there is absolutely no way in
the CF to guarantee that the user isn't going to have to do it. As I said
you can create a Control when your object is created and Invoke with that
which would provide reasonable protection, but if the user creates your
Component on a Thread, then they're still going to have Invoke themselves.
There's no way to make anything idiot-proof, as there will always be a
better idiot.
 

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