Handling events without explicitly defining a handler

J

Jay Douglas

Greetings,

I have a Windows form application that (naturally) instantiates all sorts of
objects. I have a base object that contains an event. Lots of other
objects inherit from this event. When the base object or any derived object
is instantiated I would like to automagically start listening for the event.
An example and a further explanation follows:

public delegate NeedFoodDelegate(object sender, EventArgs args);

public class Animail
{
public event NeedFoodDelegate OnNeedFood;

public void StartHunger()
{
if (OnNeedFood != null)
OnNeedFood(this, new EventArgs());
}
}

public class Cat : Animal
{
}

public class Dog : Animal
{
}

Now the winform application will be creating Cat, Dog, and Animal
frequently. I would like to have one event handler for ALL instances. It's
virtually impossible for me to explicitly define and event handler for each
object as Cat and Dog may be many layers deep in the object hierarchy.

I may be using the wrong design pattern all together to monitor the events
in all the object. I was thinking about using the MSMQ but these events and
notifications do not need to span multiple AppDomains so I figure MSMQ would
be over kill.

I hope I described this clearly.

Any and all suggestions are appreciated.

Thanks,
Jay
 
M

Markus

Jay,
Now the winform application will be creating Cat, Dog, and Animal
frequently. I would like to have one event handler for ALL instances.
It's virtually impossible for me to explicitly define and event
handler for each object as Cat and Dog may be many layers deep in the
object hierarchy.


I hope I got you right, but for me, there seem to be a simple
possibility (when everything inherits from Animal):

Don't create events, as you are in the hierarchy, but create a virtual
method in the Animal class instead (events should be created, if a
complete other class wants to be notified about what is happening. If
you are in the hierarchy, then there is no real need for events...):

public class Animal
{
[...]

public virtual void OnNeedFood(...)
{
DoEatDefault();
}
}

and in the derived classes overwrite (if necessary) this method:

public class Dog : Animal
{
public override void OnNeedFood(....)
{
DoEatDogFood();
}
}


hope to help
Markus
 
L

Larry Lard

Jay said:
Greetings,

I have a Windows form application that (naturally) instantiates all sorts of
objects. I have a base object that contains an event. Lots of other
objects inherit from this event.

Typo for 'from this base object', I'll assume.
When the base object or any derived object
is instantiated I would like to automagically start listening for the event.

Why the need for automagic; couldn't you just hook up the global event
handler whenever you create an Animal (or anything derived from it) ?

Or, you could have the constructors for all Animals accept an event
handling delegate, and pass the global event handler in each time you
create one?

Or (ugh), you could hardcode the global event handler into the
constructors (this is horrible).

Or, you could enforce that all Animal creation is done by a factory,
which hooks up the global event handler to all the Animals it produces.
Now the winform application will be creating Cat, Dog, and Animal
frequently. I would like to have one event handler for ALL instances.

That's not a problem - a method can be the *target* of as many events
as you want (eg think of a Minesweeper app - the method to handle
Button Clicks is gonig to be the target of the Click event of *every*
button!).
It's
virtually impossible for me to explicitly define and event handler for each
object as Cat and Dog may be many layers deep in the object hierarchy.

I don't really get what you mean by this last sentence.
I may be using the wrong design pattern all together to monitor the events
in all the object. I was thinking about using the MSMQ but these events and
notifications do not need to span multiple AppDomains so I figure MSMQ would
be over kill.

MSMQ is definitely not needed here.
 
S

Stoitcho Goutsev \(100\)

Jay,

You can declare the event static in the base class, thus all the objects in
the hierarchy will share the same event.

Another solution is to implement a system of services similiar to the one
that VS has, but for small applications that could be overkill.

Simplification of this design with services is to declare the services as
classes that expose static events and static methods to fire those events.
Any object that wants to listen for some service event can go ahead and
subscribe for a static event of a service class e.g.
NutritionService.HungruAnimal += .....

than eny animal that becomes hungry can fire the event e.g.
NutritionService.NeedFood(this, EventArgs.Emtpy) ;

Hope you got the idea.
 
J

Jay Douglas

Larry, Markus, Stoitcho,

I totally explained my design issue incorrectly. Lack of sleep does that to
a person =/

Okay, I have multiple controls and forms that instantiate Animal and objects
the derive from animal. A mock form and control hierarchy follows:

Form1 (Main form loaded)
+ Animail List UserControl
+ Animail Edit UserControl
Form2 (Instantiated by Form1)
+ Animal List UserControl
+ Animail Edit UserControl


Zero to many controls may be instantiated in various control containers. A
control container may contain any of the controls.
What I need to monitor is if ANY form or control instantiates an Animal
object. The reason I need to monitor the instantiation of the Animal object
globally is to refresh the data from the database that created the object in
the first place.

To drill a little deeper in to my objective, the data store may change at
any time. (Allowing for offline/online/redundancy data access). Animal
will utilize an IUpdateable interface that will contain [int
IUpdateable.UpdateTimeDelay] and [void IUpdateable.UpdateData()]. If I
could monitor all of these Animal objects in one location then naturally my
code will be more normalized.


Any ideas are suggestions are greatly appreciated.
Again, Thanks!
Jay
 
L

Larry Lard

Jay said:
Larry, Markus, Stoitcho,

I totally explained my design issue incorrectly. Lack of sleep does that to
a person =/

Okay, I have multiple controls and forms that instantiate Animal and objects
the derive from animal. A mock form and control hierarchy follows:

Form1 (Main form loaded)
+ Animail List UserControl
+ Animail Edit UserControl
Form2 (Instantiated by Form1)
+ Animal List UserControl
+ Animail Edit UserControl


Zero to many controls may be instantiated in various control containers. A
control container may contain any of the controls.
What I need to monitor is if ANY form or control instantiates an Animal
object. The reason I need to monitor the instantiation of the Animal object
globally is to refresh the data from the database that created the object in
the first place.

OK this sounds like it would be best handles by static members in
Animal, that get manipulated by the Animal constructor (all the derived
constructors will eventually call up to the base constructor). This
means that users of the Animals don't know or care about this internal
detail, which is good
To drill a little deeper in to my objective, the data store may change at
any time. (Allowing for offline/online/redundancy data access). Animal
will utilize an IUpdateable interface that will contain [int
IUpdateable.UpdateTimeDelay] and [void IUpdateable.UpdateData()]. If I
could monitor all of these Animal objects in one location then naturally my
code will be more normalized.

How about if class Animal contains a static collection of Animals, to
which Animals get added (by the constructor) when they are created, and
removed from when they are destroyed (by Disposal I suppose is the way
to go, although I guess finalization would provide less of a code
burden on users)? (Hmm, I suppose this means that it will have to be a
collection of weak references rather than normal references, otherwise
the Animals would never die).

Then when something happens, you can just go through this collection
and ask each Animal to update itself if required.
 
M

Markus

OK this sounds like it would be best handles by static members in
Animal, that get manipulated by the Animal constructor (all the derived
constructors will eventually call up to the base constructor). This
means that users of the Animals don't know or care about this internal
detail, which is good


Something similar came to my mind, just look at the following code:


using System;

namespace Test
{
public class ListenerHelper
{
private static readonly ListenerHelper instance =
new ListenerHelper();

public static ListenerHelper Instance
{
get { return instance; }
}

public event EventHandler ListenForCreations;

public void Fire(object sender)
{
if (ListenForCreations != null)
ListenForCreations(sender, null);
}
}


public abstract class Animal
{
public Animal()
{
Console.WriteLine("I am generally an Animal");
ListenerHelper.Instance.Fire(this);
}
}

public class Dog : Animal
{
public Dog(string name)
{
Console.WriteLine("I am a dog, my name is " + name);
}
}

public class MainClass
{
public static void Main()
{
ListenerHelper.Instance.ListenForCreations +=
new EventHandler(CreationListener);
new Dog("bello");
}

private static void CreationListener(object sender, EventArgs e)
{
Console.WriteLine("Creation Listener: " +
sender.GetType().ToString());
}

}

}


hth and that I got you right this time ;-)
Markus
 

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