Как передать объекты в EventArgs

У меня есть пользовательский элемент управления, который вызывает событие после связи с веб-службой. Родитель обрабатывает это событие при вызове. Я думал, что правильным подходом будет передача объекта, возвращаемого веб-службой, родительскому объекту в качестве аргументов события???

Если это правильный способ, я не могу найти инструкции о том, как это сделать.

Пользовательский контроль

public event EventHandler LoginCompleted;

затем позже, после того, как служба вернет объект biz:

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

Родитель

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

Итак, мой вопрос: каким будет «одобренный» метод для возврата пользовательского объекта родителю? Создать класс свойств, к которому все могут получить доступ, и поместить его туда?


person GPGVM    schedule 20.02.2013    source источник


Ответы (5)


Вам нужно будет объявить свое событие, используя EventHandler<T>, где T — ваш класс, производный от EventArgs:

public event EventHandler<LoginCompletedEventArgs> LoginCompleted;

LoginCompletedEventArgs может выглядеть так:

public class LoginCompletedEventArgs : EventArgs
{
    private readonly YourBusinessObject _businessObject;

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

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

Использование будет таким:

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

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

Обратите внимание, как я реализовал RaiseLoginCompleted. Это потокобезопасная версия вызова события. Я устраняю возможную NullReferenceException, которая может возникнуть в сценарии состояния гонки, когда один поток хочет инициировать событие, а другой поток отменяет подписку на последний обработчик после проверки if, но до фактического вызова обработчика.

person Daniel Hilgarth    schedule 20.02.2013

Что ж, вы можете сделать все это или определить делегата как свой EventHandler и определить свои свойства в его подписи.

Такие как:

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

public event MyEventEventHandler MyEvent;
person Joe.P    schedule 14.01.2016

Мне лично нравится подход Тони Петрины (см. https://coderwall.com/p/wkzizq/generic-eventargs-class). Он отличается от принятого ответа тем, что вам не нужно создавать специальный класс EventHandler (например, LoginCompletedEventArgs).

(Примечание: я использую VS 2015 и C# v6. В более старых версиях Visual Studio и C# вам может потребоваться добавить using System.Linq;)

Создайте универсальный класс EventArgs‹T›, наследуемый от EventArgs....

class EventArgs<T> : EventArgs {

  public T Value { get; private set; }

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

}

Объявите свой обработчик событий...

public event EventHandler<EventArgs<object>> LoginCompleted;

Предполагая, что вы объявили и назначили объект с именем loginObject, добавьте код для вызова события...

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

В клиентский код добавьте обработчик событий LoginCompleted (использует Linq и вызывает локальный метод)...

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

void onLoginCompleted(LoginObject obj) {
  // add your code here
}
person olddog    schedule 04.10.2018

иногда отстойно создавать класс для простой передачи логического значения как производного EventArgs! поэтому вы можете просто использовать Action вместо EventHandler. вы можете передавать любой тип и любое количество параметров (Action поддерживает до 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
        }
    }

обычно использовать Action и «Func» проще, чем Delegate.

person Mokhabadi    schedule 01.01.2020

Я рекомендую использовать именованные кортежи с EventHandler<TEventArgs>.

Мне нравится ответ старого пса. У Microsoft уже есть этот делегат EventHandler‹ TEventArgs >.

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

Вам не нужно наследовать от EventArgs.

Объявите свой обработчик событий с именованными кортежами.

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

В клиентском коде назначьте метод обработчику событий LoginCompleted.

вариант 1: использовать лямбда

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

вариант 2: вызвать локальный метод

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()}. ");
}

Я только что написал пример, пожалуйста, обратитесь к моему репо

person Yang Jk    schedule 28.04.2020