How do I pass objects in EventArgs
Asked Answered
G

5

43

I have a usercontrol that raises an event after communicating with a web service. The parent handles this event when raised. What I thought would be the proper approach would be to pass the object returned from the webservice to the parent as eventargs???

If this is the proper way I can't seem to find the instructions on how to do so.

UserControl

public event EventHandler LoginCompleted;

then later after the service returns biz object:

if (this.LoginCompleted != null)
{
    // This is where I would attach / pass my biz object no?
    this.LoginCompleted(this, new EventArgs());
}

Parent

ctrl_Login.LoginCompleted += ctrl_Login_LoginCompleted;
....snip....
void ctrl_Login_LoginCompleted(object sender, EventArgs e)
{
    // Get my object returned by login
}

So my question is what would be the "approved" method for getting the user object back to the parent? Create a property class that everything can access and put it there?

Goingson answered 20/2, 2013 at 10:46 Comment(0)
D
51

You would have to declare your event using EventHandler<T> where T is your class that derives from EventArgs:

public event EventHandler<LoginCompletedEventArgs> LoginCompleted;

LoginCompletedEventArgs could look like this:

public class LoginCompletedEventArgs : EventArgs
{
    private readonly YourBusinessObject _businessObject;

    public LoginCompletedEventArgs(YourBusinessObject businessObject)
    {
        _businessObject = businessObject;
    }

    public YourBusinessObject BusinessObject
    {
        get { return _businessObject; }
    }
}

Usage would be like this:

private void RaiseLoginCompleted(YourBusinessObject  businessObject)
{
    var handler = LoginCompleted;
    if(handler == null)
        return;

    handler(this, new LoginCompletedEventArgs(businessObject));
}

Please notice how I implemented RaiseLoginCompleted. This is a thread-safe version of raising the event. I eliminates a possible NullReferenceException that can occur in a race condition scenario where one thread wants to raise the event and another thread un-subscribes the last handler after the if check but before actually invoking the handler.

Distressful answered 20/2, 2013 at 10:48 Comment(0)
T
14

Well, you could do all that or you could define a delegate as your EventHandler and define your properties in its signature.

Such as:

public delegate void MyEventEventHandler(int prop1, string prop2, object prop3...);

public event MyEventEventHandler MyEvent;
Tympanites answered 14/1, 2016 at 2:39 Comment(0)
G
7

I recommend use named tuples with EventHandler<TEventArgs>.

I like olddog's answer. Microsoft already has this delegate EventHandler< TEventArgs >.

public delegate void EventHandler<TEventArgs>(object sender, TEventArgs e);

You don't need to inherits from EventArgs.

Declare your event handler with named tuples.

public event EventHandler<(int id, string message, object LoginObject)> LoginCompleted;

In your client code, assign method to the LoginCompleted event handler

option 1: use lambda

LoginCompleted  += (o, e) =>
{
    Console.WriteLine($"Hello, sender is {o.ToString()}! id is {e.id}, message is {e.message}, and LoginObject is {e.LoginObject.ToString()}. ");
};

option 2: call a local method

LoginCompleted  += onLoginCompleted;

private static void onLoginCompleted  (object sender, (int id, string message,  object LoginObject) e)
{
    Console.WriteLine($"Hello, sender is {sender.ToString()}! id is {e.id}, message is {e.message}, and LoginObject is {e.LoginObject.ToString()}. ");
}

I just wrote an example, please refer to my repo

Gapes answered 28/4, 2020 at 7:49 Comment(1)
This is exactly what I was looking for. The repo was a big help. This is the simplest and easiest solutionRadii
B
5

I personally like Toni Petrina's approach (see https://coderwall.com/p/wkzizq/generic-eventargs-class). It differs from the accepted answer in that you don't have to create a special EventHandler class (e.g. LoginCompletedEventArgs).

(Note: I am using VS 2015 and C# v6. In older versions of Visual Studio and C#, you may have to add using System.Linq;)

Create a generic EventArgs<T> class that inherits from EventArgs...

class EventArgs<T> : EventArgs {

  public T Value { get; private set; }

  public EventArgs(T val) {
     Value = val;
  }

}

Declare your event handler...

public event EventHandler<EventArgs<object>> LoginCompleted;

Assuming you have declared and assigned an object named loginObject, add code to raise you event...

private void RaiseLoginCompleted() {
  if (LoginCompleted != null)
    LoginCompleted(this, new EventArgs<object>(loginObject));
}

In your client code, add the LoginCompleted event handler (uses Linq and calls a local method)...

LoginCompleted += (o, e) => onLoginCompleted(e.Value); // calls a local method

void onLoginCompleted(LoginObject obj) {
  // add your code here
}
Bumf answered 4/10, 2018 at 17:0 Comment(0)
A
3

sometimes it sucks to create a class for merely passing a bool as a derived EventArgs! so you can simply use Action instead of EventHandler. you can pass any type and how many parameters you like (Action supports Up to 16).

    class Raiser
    {
        public event Action<Raiser, bool,DateTimeOffset> OnCreate;

        public void Create()
        {
            OnCreate?.Invoke(this, true,DateTimeOffset.Now);
        }
    }

    class Listener
    {
        Raiser raiser;

        public Listener()
        {
            raiser = new Raiser();
            raiser.OnCreate += Raiser_OnCreate;
        }

        private void Raiser_OnCreate(Raiser arg1, bool arg2,DateTimeOffset dateTimeOffset)
        {
            throw new NotImplementedException();//Do Your works here
        }
    }

generally using Action and 'Func' are easier than Delegate.

Avidity answered 1/1, 2020 at 12:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.