Question

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.LoginCompleted(this, new EventArgs() //this is where I would attach / pass my biz object no?);  
        }

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?

Was it helpful?

Solution

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.

OTHER TIPS

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;

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
}

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

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top