Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pass a return value back through an EventHandler

Im trying to write to an API and I need to call an eventhandler when I get data from a table. Something like this:

    public override bool Run(Company.API api)
    {
        SomeInfo _someInfo = new SomeInfo();

        if (_someInfo.Results == 1)
            return true;
        else
            return false;

        using (MyTable table = new MyTable(api))
        {
            table.WhenData += new EventHandler<DataEventArgs<Record>>(table_WhenData);
            table.WhenDead += new EventHandler<EventArgs>(table_WhenDead);
            table.Start();
        }

    public void table_WhenData(object sender, DataEventArgs<Record> e)
    {
        return true;
    }

The problem that Im having is I dont know how to pass a return value back from table_WhenData to the Run method.

Ive tried many ways (like trying to pass _someInfo to the method) but I just cant seem to get the syntax right.

Any suggestion is greatly appreciated.

like image 323
Leroy Jenkins Avatar asked Sep 18 '09 18:09

Leroy Jenkins


People also ask

Can event handler return a value?

Firing an event is a one-way signal. By default most event handlers return void , because single event may have several subscribers, and return value could become ambiguous. However, it is possible for handlers to return values. Simple delegates may have any return type.

Is an EventHandler a delegate?

The EventHandler delegate is a predefined delegate that specifically represents an event handler method for an event that does not generate data. If your event does generate data, you must use the generic EventHandler<TEventArgs> delegate class.

Is it possible to pass an additional parameter to an event handler?

Of course you can. (If it was the event you define yourself, you would need to create you own event arguments class where you would put all the information you need.

How does EventHandler work?

Each key node has a handler that receives key events when the key has focus. The handler responds to the key-pressed and key-released events for the Enter key by changing the color of the key on the screen. The event is then consumed so that the keyboard node, which is the parent node, does not receive the event.


4 Answers

The common pattern here is not to return any data from the event handler, but to add properties to your event argument object so that the consumer of the event can set the properties which the caller can then access. This is very common in UI handling code; you see the Cancel event concept all over the place.

The following is pseudo code, and not compile ready. Its intent is to show the pattern.

public class MyEventArgs : EventArgs {    public bool Cancel{get;set;} }  public bool fireEvent() {     MyEventArgs e=new MyEventArgs();      //Don't forget a null check, assume this is an event     FireEventHandler(this,e);      return e.Cancel; }  public HandleFireEvent(object sender, MyEventArgs e) {  e.Cancel=true; } 

Edit

I like how Jon Skeet worded this: make the EventArgs mutuable. That is, the consumer of the event can modify the state of the EventArgs object allowing for the raiser of the event to get to that data.

like image 63
JoshBerke Avatar answered Sep 20 '22 16:09

JoshBerke


I know this is an old post, but just in case anyone comes across it, it is certainly possible to do this. You declare your own delegate that returns a value, then base the event off this new delegate. Here is an example:

In the event declarer / publisher:

// the delegate public delegate string ReturnStringEventHandler(object sender, EventArgs args); // the event public event ReturnStringEventHandler StringReturnEvent; // raise the event protected void OnStringReturnEvent(EventArgs e)     {         if (StringReturnEvent != null)  // make sure at least one subscriber               // note the event is returning a string               string myString = StringReturnEvent(this, e);     } 

In the event subscriber:

// Subscribe to event, probably in class constructor / initializer method StringReturnEvent += HandleStringReturnEvent;  // Handle event, return data private string HandleStringReturnEvent(object sender, EventArgs e) {     return "a string to return"; } 

.NET provides an example of this in the AssemblyResolve event, which uses the ResolveEventHandler delegate to return data, in this case a reference to the desired Assembly. MSDN Article on AssemblyResolve event

I have personally used both the AssemblyResolve event and the custom delegate technique to return data from an event, and they both work as expected on Visual Studio 2010.

like image 39
AFischbein Avatar answered Sep 20 '22 16:09

AFischbein


The only way you can do it is to make one of the arguments (preferably the "args" rather than the sender) mutable. If it's not already mutable, you've basically got problems - there's just no way of getting the information out.

(Okay, there's one way - you can keep the event argument itself immutable, but make one member of it a method which ends up calling a delegate registered by the code raising the event in the first place. But that's horrible...)

like image 40
Jon Skeet Avatar answered Sep 21 '22 16:09

Jon Skeet


A simple solution is to use a closure:

public override bool Run() {
    SomeInfo someInfo = ...
    table.WhenData += (obj, args) => {
        someInfo.Return = something
    };
}
like image 40
Igor ostrovsky Avatar answered Sep 21 '22 16:09

Igor ostrovsky