problem with Invoking an event

  • Thread starter Joanna Carter \(TeamB\)
  • Start date
J

Joanna Carter \(TeamB\)

I am trying to invoke an event using reflection.

//////////////////////

public class Test
{
public event EventHandler NameChanged;

public void CallEvent()
{
EventInfo ei = GetType().GetEvent("NameChanged");

if(ei != null)
{
Type handlerType = ei.EventHandlerType;

MethodInfo invokeMethod = handlerType.GetMethod("Invoke");

object[] args = new object[] { this, EventArgs.Empty };

invokeMethod.Invoke(this, args);
}
}
}

////////////////

....but the Invoke method is blowing up with an unhandled TargetException.

Anyone got any ideas what I am dong wrong ?

Joanna
 
A

Alexander Shirshov

Joanna,

You say you want to invoke the *event*, and the code is trying to invoke the
*event handler*, the listener of the event. If you want to raise the event
you should call GetRaiseMethod()...

Oh, wait! Read this first:
http://www.dotnet247.com/247reference/msgs/51/258691.aspx. Looks like you're
out of luck...

Are you trying to raise events of your own class? Then you could add
RaiseNameChanged method. If you need to raise events of BCL classes, then
you could exploit the fact that many of them use the pattern of providing a
protected On<event name> method which raises the event.

HTH,
Alexander
 
J

Joanna Carter \(TeamB\)

You say you want to invoke the *event*, and the code is trying to invoke the
*event handler*, the listener of the event. If you want to raise the event
you should call GetRaiseMethod()...

Oh, wait! Read this first:
http://www.dotnet247.com/247reference/msgs/51/258691.aspx. Looks like you're
out of luck...

Yup, I already tried that :)
Are you trying to raise events of your own class? Then you could add
RaiseNameChanged method. If you need to raise events of BCL classes, then
you could exploit the fact that many of them use the pattern of providing a
protected On<event name> method which raises the event.

The problem I am trying to circumvent is the necessity for any object whose
properties are to be displayed in a TextBox, etc to have a
(PropertyName)Changed event fired to update the control. This means having
to have one explicitly named event per property.

Now, it is bad enough having to have these extra events in every class, but
also having to have a wrapper method as well is starting to detract from the
idea of 'automatic' data-aware controls.

My idea was to be able to have one method that raised the appropriate 'by
name' using something similar to the code I originally posted.

What is your opinion as to why I am getting the TargetException, because
apart from that, it would seem like I am doing all the steps that should be
necessary ?

Joanna
 
A

Alexander Shirshov

What is your opinion as to why I am getting the TargetException, because
apart from that, it would seem like I am doing all the steps that should
be
necessary ?

My guess you're getting the exception because nobody has subscribed to the
event. As I said before you're invoking the handler and not invoking the
event. In "normal" C# you'd write something like this:

if (NameChanged != null)
{
// Perform the equivalent of NameChanged(this, EventArgs.Empty);

foreach (Delegate handler in NameChanged.GetInvocationList())
{
handler.Invoke();
}
}

and your code just do this:

NameChanged.GetInvocationList()[0].Invoke();

(Compiled with Outlook Express but you should get the idea)

.....

But wait, I might have something for you! If I understand correctly you're
binding your own classes to controls and you don't want to add all
corresponding <property name>Changed events. If that's the case then have a
look at this excellent article:
http://www.interact-sw.co.uk/iangblog/2004/10/23/propertychange

HTH,
Alexander
 
J

Joanna Carter \(TeamB\)

My guess you're getting the exception because nobody has subscribed to the
event. As I said before you're invoking the handler and not invoking the
event. In "normal" C# you'd write something like this:

Well officially, the control has subscribed, but I understand that what I
was doing did not stand much chance of working.

So, I resorted to using an internal Dictionary<string, EventHandler> like
this

/////////////////////////////

public class EventTest
{
private Dictionary<string, object> values = new Dictionary<string,
object>();

protected Dictionary<string, EventHandler> events = new
Dictionary<string, EventHandler>();

public EventTest()
{
PropertyInfo[] properties = GetType().GetProperties();

foreach(PropertyInfo propInfo in properties)
{
Type[] paramTypes = new Type[] { propInfo.PropertyType };

Type testType =
typeof(TestType<>).BindGenericParameters(paramTypes);

valueTypes.Add(propInfo.Name, Activator.CreateInstance(testType));
}

EventInfo[] events = GetType().GetEvents();

foreach(EventInfo ei in events)
this.events.Add(ei.Name, null);
}

private const string sChanged = "Changed";

private void AddChangedDelegate(string name, EventHandler del)
{
events[name + sChanged] += del;
}

private void RemoveChangedDelegate(string name, EventHandler del)
{
events[name + sChanged] -= del;
}

private void OnChanged(string name, EventArgs args)
{
if(events[name] != null)
events[name](this, args);
}

protected object GetValue(string name)
{
return values[name]);
}

protected void SetValue(string name, object value)
{
values[name]) = value;
OnChanged(name, EventArgs.Empty);
}

private const string sName = "Name";
private const string sAge = "Age";

public string Name
{
get { return GetValue(sName) == null ? String.Empty : (string)
GetValue(sName); }
set { SetValue(sName, value); }
}

public int Age
{
get { return (int) GetValue(sAge); }
set { SetValue(sAge, value); }
}

public event EventHandler NameChanged
{
add { AddChangedDelegate(sName, value); }
remove { RemoveChangedDelegate(sName, value); }
}
}

/////////////////////

This is much simpler, only requiring the obligatory (PropertyName)Changed
events for each property :) + :-(

Although I am not jettisoning my code as it makes handling events not
destined for controls easier to manage.
But wait, I might have something for you! If I understand correctly you're
binding your own classes to controls and you don't want to add all
corresponding <property name>Changed events. If that's the case then have a
look at this excellent article:
http://www.interact-sw.co.uk/iangblog/2004/10/23/propertychange

Now why didn't you post that earlier !!! <vbg>

I had just finished the version above, checked the newsgroups, read this
article, picked my jaw up from the desk :), changed my code and all is well
with the world !!!

Thank you, thank you, thank you.

I might have been doing OO design for years, but this .NET framework is just
so massive; thank goodness for the internet allowing us to 'meld minds'.

Joanna
 

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