如何在EventArgs中传递对象

时间:2013-02-20 10:46:55

标签: c#-4.0

我有一个usercontrol,它在与Web服务通信后引发事件。父项在引发时处理此事件。我想到的将是正确的方法是将从webservice返回的对象作为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
    }

所以我的问题是将用户对象恢复为父级的“已批准”方法是什么?创建一个可以访问的属性类并将其放在那里?

5 个答案:

答案 0 :(得分:39)

您必须使用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检查之后但在实际调用处理程序之前取消订阅最后一个处理程序。 / p>

答案 1 :(得分:8)

嗯,你可以做到这一切,或者你可以将一个委托定义为你的EventHandler并在其签名中定义你的属性。

如:

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

public event MyEventEventHandler MyEvent;

答案 2 :(得分:1)

我个人喜欢Toni Petrina的方法(请参阅https://coderwall.com/p/wkzizq/generic-eventargs-class)。它与接受的答案不同,因为您不必创建特殊的EventHandler类(例如LoginCompletedEventArgs)。

注意:我正在使用VS 2015和C#v6。在Visual Studio和C#的旧版本中,您可能必须添加using System.Linq;

创建一个继承自EventArgs ...

的通用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
}

答案 3 :(得分:0)

有时创建一个仅将布尔值作为派生的EventArgs传递的类很糟糕!因此您只需使用Action而不是EventHandler。您可以传递任何类型以及您喜欢的参数数量(动作最多支持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容易。

答案 4 :(得分:0)

我建议将named tuplesEventHandler<TEventArgs>一起使用。

我喜欢老狗的answer。 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:使用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()}. ");
};

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

我只是写了一个示例,请参考我的repo