Event handling and reflection - C# (NetCF)

K

Klaudiusz Bryja

Hi,

This is for NetCF 2.0.

I need to create event handling code which using reflection. I have
some parameters in XML which describe how event should be handled. I
have code to create delegate:

public class DelegateEx
{
private object target;
private MethodInfo method;
private XmlNode node;

// XmlNode describe how to handle event (dll path, class, method and
method parameters).
private DelegateEx(MethodInfo method, object target, XmlNode
node)
{
this.target = target;
this.method = method;
this.node = node;
}

// This is called when event was fired.
// XMLFormsEventArgs inherits from EventsArgs and add XmlNode
property.
private void Invoke(object sender, EventArgs e)
{
method.Invoke(target, new object[] { sender, (new
XMLFormsEventArgs(this.node, e) as EventArgs) });
}

public static EventHandler CreateDelegate(MethodInfo method,
object target, XmlNode node)
{
return new EventHandler((new DelegateEx(method, target,
node)).Invoke);
}
}

Using this I try to subscribe to event (I have static method
HandleEvents which should be called when event is fired):

EventInfo ei = form.GetType().GetEvent("Click",
BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.NonPublic
| BindingFlags.Instance | BindingFlags.Static);
if (ei != null)
{
MethodInfo miHandler = typeof(XMLForms).GetMethod("HandleEvents",
BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.NonPublic
| BindingFlags.Instance | BindingFlags.Static);

MethodInfo addHandler = ei.GetAddMethod();

// formNode - this is xmlNode which describe event

Object[] addHandlerArgs = { DelegateEx.CreateDelegate(miHandler,
typeof(XMLForms), formNode) };
addHandler.Invoke(form, addHandlerArgs);
}

Everything work when I want to handle standard event which is type of
EventHandler. But I get error "ArgumentException" without any message
when I try to handle e.g. KeyDown event (event is type of
KeyEventHandler).

StackTrace for this error:
at System.Reflection.RuntimeMethodInfo.InternalInvoke()
at System.Reflection.RuntimeMethodInfo.InternalInvoke()
at System.Reflection.RuntimeMethodInfo.Invoke()
at System.Reflection.MethodBase.Invoke()
at bcs.XMLForms.BuildXMLForm()
at TestApp.Form1.button2_Click()
at System.Windows.Forms.Control.OnClick()
at System.Windows.Forms.Button.OnClick()
at System.Windows.Forms.ButtonBase.WnProc()
at System.Windows.Forms.Control._InternalWnProc()
at Microsoft.AGL.Forms.EVL.EnterMainLoop()
at System.Windows.Forms.Application.Run()
at TestApp.Program.Main()

I think that I should cast EventHandler type to KeyEventHandler type
but I get error:
Cannot convert type 'System.EventHandler' to
'System.Windows.Forms.KeyEventHandler'.

How to change my code to work with all type of EventHandler?


Best regards,
Klaudiusz
 
P

Pavel Minaev

Hi,

This is for NetCF 2.0.

I need to create event handling code which using reflection. I have
some parameters in XML which describe how event should be handled. I
have code to create delegate:

public class DelegateEx
    {
        private object target;
        private MethodInfo method;
        private XmlNode node;

// XmlNode describe how to handle event (dll path, class, method and
method parameters).
        private DelegateEx(MethodInfo method, object target, XmlNode
node)
        {
            this.target = target;
            this.method = method;
            this.node = node;
        }

// This is called when event was fired.
// XMLFormsEventArgs inherits from EventsArgs and add XmlNode
property.
        private void Invoke(object sender, EventArgs e)
        {
            method.Invoke(target, new object[] { sender, (new
XMLFormsEventArgs(this.node, e) as EventArgs) });
        }

        public static EventHandler CreateDelegate(MethodInfo method,
object target, XmlNode node)
        {
            return new EventHandler((new DelegateEx(method, target,
node)).Invoke);
        }
    }

Using this I try to subscribe to event (I have static method
HandleEvents which should be called when event is fired):

EventInfo ei = form.GetType().GetEvent("Click",
BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.NonPublic
| BindingFlags.Instance | BindingFlags.Static);
if (ei != null)
{
    MethodInfo miHandler = typeof(XMLForms).GetMethod("HandleEvents",
BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.NonPublic
| BindingFlags.Instance | BindingFlags.Static);

    MethodInfo addHandler = ei.GetAddMethod();

// formNode - this is xmlNode which describe event

    Object[] addHandlerArgs = { DelegateEx.CreateDelegate(miHandler,
typeof(XMLForms), formNode) };
    addHandler.Invoke(form, addHandlerArgs);

}

Everything work when I want to handle standard event which is type of
EventHandler. But I get error "ArgumentException" without any message
when I try to handle e.g. KeyDown event (event is type of
KeyEventHandler).

StackTrace for this error:
at System.Reflection.RuntimeMethodInfo.InternalInvoke()
at System.Reflection.RuntimeMethodInfo.InternalInvoke()
at System.Reflection.RuntimeMethodInfo.Invoke()
at System.Reflection.MethodBase.Invoke()
at bcs.XMLForms.BuildXMLForm()
at TestApp.Form1.button2_Click()
at System.Windows.Forms.Control.OnClick()
at System.Windows.Forms.Button.OnClick()
at System.Windows.Forms.ButtonBase.WnProc()
at System.Windows.Forms.Control._InternalWnProc()
at Microsoft.AGL.Forms.EVL.EnterMainLoop()
at System.Windows.Forms.Application.Run()
at TestApp.Program.Main()

I think that I should cast EventHandler type to KeyEventHandler type
but I get error:
Cannot convert type 'System.EventHandler' to
'System.Windows.Forms.KeyEventHandler'.

How to change my code to work with all type of EventHandler?

Your code passes your own class XMLFormsEventArgs to a method which
expects KeyEventArgs. These types are obviously not compatible. Can
you explain more about what that class is and why is it needed?
 
K

Klaudiusz Bryja

This is for NetCF 2.0.
I need to create event handling code which using reflection. I have
some parameters in XML which describe how event should be handled. I
have code to create delegate:
public class DelegateEx
{
private object target;
private MethodInfo method;
private XmlNode node;
// XmlNode describe how to handle event (dll path, class, method and
method parameters).
private DelegateEx(MethodInfo method, object target, XmlNode
node)
{
this.target = target;
this.method = method;
this.node = node;
}
// This is called when event was fired.
// XMLFormsEventArgs inherits from EventsArgs and add XmlNode
property.
private void Invoke(object sender, EventArgs e)
{
method.Invoke(target, new object[] { sender, (new
XMLFormsEventArgs(this.node, e) as EventArgs) });
}
public static EventHandler CreateDelegate(MethodInfo method,
object target, XmlNode node)
{
return new EventHandler((new DelegateEx(method, target,
node)).Invoke);
}
}
Using this I try to subscribe to event (I have static method
HandleEvents which should be called when event is fired):
EventInfo ei = form.GetType().GetEvent("Click",
BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.NonPublic
| BindingFlags.Instance | BindingFlags.Static);
if (ei != null)
{
MethodInfo miHandler = typeof(XMLForms).GetMethod("HandleEvents",
BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.NonPublic
| BindingFlags.Instance | BindingFlags.Static);
MethodInfo addHandler = ei.GetAddMethod();
// formNode - this is xmlNode which describe event
Object[] addHandlerArgs = { DelegateEx.CreateDelegate(miHandler,
typeof(XMLForms), formNode) };
addHandler.Invoke(form, addHandlerArgs);

Everything work when I want to handle standard event which is type of
EventHandler. But I get error "ArgumentException" without any message
when I try to handle e.g. KeyDown event (event is type of
KeyEventHandler).
StackTrace for this error:
at System.Reflection.RuntimeMethodInfo.InternalInvoke()
at System.Reflection.RuntimeMethodInfo.InternalInvoke()
at System.Reflection.RuntimeMethodInfo.Invoke()
at System.Reflection.MethodBase.Invoke()
at bcs.XMLForms.BuildXMLForm()
at TestApp.Form1.button2_Click()
at System.Windows.Forms.Control.OnClick()
at System.Windows.Forms.Button.OnClick()
at System.Windows.Forms.ButtonBase.WnProc()
at System.Windows.Forms.Control._InternalWnProc()
at Microsoft.AGL.Forms.EVL.EnterMainLoop()
at System.Windows.Forms.Application.Run()
at TestApp.Program.Main()
I think that I should cast EventHandler type to KeyEventHandler type
but I get error:
Cannot convert type 'System.EventHandler' to
'System.Windows.Forms.KeyEventHandler'.
How to change my code to work with all type of EventHandler?

Your code passes your own class XMLFormsEventArgs to a method which
expects KeyEventArgs. These types are obviously not compatible. Can
you explain more about what that class is and why is it needed?

XMLFormsEventArgs inherits from EventArgs and has property:
XmlNode - this node describie target method which shoudl be called
after event occured (e.g. in xml I define that when Click occured in
e.g. button system should call method named "A" from \program files
\dlls\methoddll.dll from class dllsMethod),

OK. I try to explain what I want to do. I have XML file which describe
control leyout and how events should be handled.

<System.Windows.Forms.Button Name="btnEnter" Text="Button text" >
<Click Assembly="\Program Files\testapp\MessageTest.dll"
Class="Message" Method="SampleMethod" />
</System.Windows.Forms.Button>

So when I click in button application shoul call method SampleMethod
in class Message in assembly \Program Files\testapp\MessageTest.dll.
As you see the xmlnode describe what kind of event I handle.
When I test HandleEvent method I set:

button.Click += delegate(object sender1, EventArgs e1)
{ HandleEvents(sender1, e1, node); };

where node parameter is is <Click Assembly="\Program Files\testapp
\MessageTest.dll" Class="Message" Method="SampleMethod" />.

In that case everything works fine. But problem is that buttn is
creating using reflection in run-time. So I couldn't subscribe to
Click event as above.

This is whay I try to use XMLFormsEventArgs. I have generic delegate
subscribed to event and when is called I get XmlNode in
XMLFormsEventArgs. So I can fire method which I want to fire.
 
B

Ben Voigt [C++ MVP]

Klaudiusz said:
Hi,

This is for NetCF 2.0.

I need to create event handling code which using reflection. I have
some parameters in XML which describe how event should be handled. I
have code to create delegate:

public class DelegateEx
{
private object target;
private MethodInfo method;
private XmlNode node;

// XmlNode describe how to handle event (dll path, class, method and
method parameters).
private DelegateEx(MethodInfo method, object target, XmlNode
node)
{
this.target = target;
this.method = method;
this.node = node;
}

// This is called when event was fired.
// XMLFormsEventArgs inherits from EventsArgs and add XmlNode
property.
private void Invoke(object sender, EventArgs e)
{
method.Invoke(target, new object[] { sender, (new
XMLFormsEventArgs(this.node, e) as EventArgs) });
}

public static EventHandler CreateDelegate(MethodInfo method,
object target, XmlNode node)
{
return new EventHandler((new DelegateEx(method, target,
node)).Invoke);
}
}

Using this I try to subscribe to event (I have static method
HandleEvents which should be called when event is fired):

EventInfo ei = form.GetType().GetEvent("Click",
BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.NonPublic
BindingFlags.Instance | BindingFlags.Static);
if (ei != null)
{
MethodInfo miHandler = typeof(XMLForms).GetMethod("HandleEvents",
BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.NonPublic
BindingFlags.Instance | BindingFlags.Static);

There's no need to use reflection for HandleEvents, only for the method
identified in your xml.
MethodInfo addHandler = ei.GetAddMethod();

// formNode - this is xmlNode which describe event

Object[] addHandlerArgs = { DelegateEx.CreateDelegate(miHandler,
typeof(XMLForms), formNode) };
addHandler.Invoke(form, addHandlerArgs);
}

Everything work when I want to handle standard event which is type of
EventHandler. But I get error "ArgumentException" without any message
when I try to handle e.g. KeyDown event (event is type of
KeyEventHandler).

StackTrace for this error:
at System.Reflection.RuntimeMethodInfo.InternalInvoke()
at System.Reflection.RuntimeMethodInfo.InternalInvoke()
at System.Reflection.RuntimeMethodInfo.Invoke()
at System.Reflection.MethodBase.Invoke()
at bcs.XMLForms.BuildXMLForm()
at TestApp.Form1.button2_Click()
at System.Windows.Forms.Control.OnClick()
at System.Windows.Forms.Button.OnClick()
at System.Windows.Forms.ButtonBase.WnProc()
at System.Windows.Forms.Control._InternalWnProc()
at Microsoft.AGL.Forms.EVL.EnterMainLoop()
at System.Windows.Forms.Application.Run()
at TestApp.Program.Main()

I think that I should cast EventHandler type to KeyEventHandler type
but I get error:
Cannot convert type 'System.EventHandler' to
'System.Windows.Forms.KeyEventHandler'.

How to change my code to work with all type of EventHandler?

Try:

class XmlEventForwarder
{
public readonly XmlNode node;
public XmlEventForwarder(XmlNode node) { this.node = node; }
public void ForwardIncoming(object sender, EventArgs e) {
XMLForms.HandleEvent(sender, e, node); }

public static readonly MethodInfo forwarder;
static XmlEventForwarder()
{
forwarder = typeof(XmlEventForwarder).GetMethod("ForwardIncoming",|
BindingFlags.Public | BindingFlags.Instance);
}
}

EventInfo ei = form.GetType().GetEvent("Click", BindingFlags.IgnoreCase |
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance |
BindingFlags.Static);
if (ei != null)
{

MethodInfo addHandler = ei.GetAddMethod();
// formNode - this is xmlNode which describe event
object[] addHandlerArgs = new object[] {
Delegate.CreateDelegate(ei.EventHandlerType, new
XmlEventForwarder(formNode), XmlEventForwarder.forwarder) };
addHandler.Invoke(form, addHandlerArgs);
}


When XMLForms.HandleEvent calls the method identified in your xml snippet,
the runtime will ensure that the eventargs actually passed in the event is
the right type for the handler. Since you're using reflection there, it
should just happen with no casting required.
 
K

Klaudiusz Bryja

Klaudiusz said:
This is for NetCF 2.0.
I need to create event handling code which using reflection. I have
some parameters in XML which describe how event should be handled. I
have code to create delegate:
public class DelegateEx
{
private object target;
private MethodInfo method;
private XmlNode node;
// XmlNode describe how to handle event (dll path, class, method and
method parameters).
private DelegateEx(MethodInfo method, object target, XmlNode
node)
{
this.target = target;
this.method = method;
this.node = node;
}
// This is called when event was fired.
// XMLFormsEventArgs inherits from EventsArgs and add XmlNode
property.
private void Invoke(object sender, EventArgs e)
{
method.Invoke(target, new object[] { sender, (new
XMLFormsEventArgs(this.node, e) as EventArgs) });
}
public static EventHandler CreateDelegate(MethodInfo method,
object target, XmlNode node)
{
return new EventHandler((new DelegateEx(method, target,
node)).Invoke);
}
}
Using this I try to subscribe to event (I have static method
HandleEvents which should be called when event is fired):
EventInfo ei = form.GetType().GetEvent("Click",
BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.NonPublic
if (ei != null)
{
MethodInfo miHandler = typeof(XMLForms).GetMethod("HandleEvents",
BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.NonPublic

There's no need to use reflection for HandleEvents, only for the method
identified in your xml.




MethodInfo addHandler = ei.GetAddMethod();
// formNode - this is xmlNode which describe event
Object[] addHandlerArgs = { DelegateEx.CreateDelegate(miHandler,
typeof(XMLForms), formNode) };
addHandler.Invoke(form, addHandlerArgs);
}
Everything work when I want to handle standard event which is type of
EventHandler. But I get error "ArgumentException" without any message
when I try to handle e.g. KeyDown event (event is type of
KeyEventHandler).
StackTrace for this error:
at System.Reflection.RuntimeMethodInfo.InternalInvoke()
at System.Reflection.RuntimeMethodInfo.InternalInvoke()
at System.Reflection.RuntimeMethodInfo.Invoke()
at System.Reflection.MethodBase.Invoke()
at bcs.XMLForms.BuildXMLForm()
at TestApp.Form1.button2_Click()
at System.Windows.Forms.Control.OnClick()
at System.Windows.Forms.Button.OnClick()
at System.Windows.Forms.ButtonBase.WnProc()
at System.Windows.Forms.Control._InternalWnProc()
at Microsoft.AGL.Forms.EVL.EnterMainLoop()
at System.Windows.Forms.Application.Run()
at TestApp.Program.Main()
I think that I should cast EventHandler type to KeyEventHandler type
but I get error:
Cannot convert type 'System.EventHandler' to
'System.Windows.Forms.KeyEventHandler'.
How to change my code to work with all type of EventHandler?

Try:

class XmlEventForwarder
{
public readonly XmlNode node;
public XmlEventForwarder(XmlNode node) { this.node = node; }
public void ForwardIncoming(object sender, EventArgs e) {
XMLForms.HandleEvent(sender, e, node); }

public static readonly MethodInfo forwarder;
static XmlEventForwarder()
{
forwarder = typeof(XmlEventForwarder).GetMethod("ForwardIncoming",|
BindingFlags.Public | BindingFlags.Instance);
}

}

EventInfo ei = form.GetType().GetEvent("Click", BindingFlags.IgnoreCase |
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance |
BindingFlags.Static);
if (ei != null)
{

MethodInfo addHandler = ei.GetAddMethod();
// formNode - this is xmlNode which describe event

object[] addHandlerArgs = new object[] {
Delegate.CreateDelegate(ei.EventHandlerType, new
XmlEventForwarder(formNode), XmlEventForwarder.forwarder) };
addHandler.Invoke(form, addHandlerArgs);

}

When XMLForms.HandleEvent calls the method identified in your xml snippet,
the runtime will ensure that the eventargs actually passed in the event is
the right type for the handler. Since you're using reflection there, it
should just happen with no casting required.


Best regards,
Klaudiusz

Hi,

I try this but main problem is that CF hasn't Delegate.CreateDelegate
(only in full framework or in NetCF 3.5 but I need solution for NetCF
2.). When I try to use your code I get the same ArgumentException as
before (for KeyDown event). I use DelegateEx.CreateDelegate. I notice
taht the problem is in type of eventhandler. When I handle Click event
I pass to AddEventHandler delegate of EventHandler type it's work but
with KeyDown event don't work. So I try to use KeyEventHandler and
it's work. The problem is that it should be flexible and I don't know
how to do it.
 
B

Ben Voigt [C++ MVP]

Hi,
I try this but main problem is that CF hasn't Delegate.CreateDelegate
(only in full framework or in NetCF 3.5 but I need solution for NetCF
2.). When I try to use your code I get the same ArgumentException as
before (for KeyDown event). I use DelegateEx.CreateDelegate. I notice
taht the problem is in type of eventhandler. When I handle Click event
I pass to AddEventHandler delegate of EventHandler type it's work but
with KeyDown event don't work. So I try to use KeyEventHandler and
it's work. The problem is that it should be flexible and I don't know
how to do it.

The problem is that creating a delegate is covariant, but there's no
covariant conversion from one delegate type to another. That's probably why
support for Delegate.CreateDelegate got added in the newer CF.

You might be able to workaround if you're interested only in the standard
events of standard controls, by adding directly to the underlying collection
of handlers if it is more weakly typed. I seem to recall that a Dictionary
of EventHandler is used, although that might be different on CF as well.

Or take a look at Delegate.Combine, although I suspect it also requires that
both input delegates be the exact same type.
 

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