如何在EventArgs中传递对象

GPG*_*GVM 31 c#-4.0

我有一个usercontrol,它在与Web服务通信后引发一个事件.父项在引发时处理此事件.我认为正确的方法是将webservice返回的对象作为eventargs传递给父对象???

如果这是正确的方法,我似乎无法找到如何这样做的说明.

用户控件

public event EventHandler LoginCompleted;
Run Code Online (Sandbox Code Playgroud)

然后在服务返回biz对象之后:

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

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

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

Dan*_*rth 42

你将不得不使用声明你的活动EventHandler<T>,其中T是您的类派生自EventArgs:

public event EventHandler<LoginCompletedEventArgs> LoginCompleted;
Run Code Online (Sandbox Code Playgroud)

LoginCompletedEventArgs 可能看起来像这样:

public class LoginCompletedEventArgs : EventArgs
{
    private readonly YourBusinessObject _businessObject;

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

    public YourBusinessObject BusinessObject
    {
        get { return _businessObject; }
    }
}
Run Code Online (Sandbox Code Playgroud)

用法如下:

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

    handler(this, new LoginCompletedEventArgs(businessObject));
}
Run Code Online (Sandbox Code Playgroud)

请注意我的实施方式RaiseLoginCompleted.这是引发事件的线程安全版本.我消除了NullReferenceException在竞争条件场景中可能发生的情况,其中一个线程想要引发事件而另一个线程在if检查之后但在实际调用处理程序之前取消订阅最后一个处理程序.


Joe*_*e.P 10

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

如:

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

public event MyEventEventHandler MyEvent;
Run Code Online (Sandbox Code Playgroud)

  • 恕我直言更清洁,更有效率 (2认同)

Yan*_* Jk 7

我建议使用命名元EventHandler<TEventArgs>

我喜欢老狗的回答。Microsoft 已经拥有此委托EventHandler< TEventArgs >

public delegate void EventHandler<TEventArgs>(object sender, TEventArgs e);
Run Code Online (Sandbox Code Playgroud)

您不需要继承自EventArgs.

使用命名元组声明您的事件处理程序。

public event EventHandler<(int id, string message, object LoginObject)> LoginCompleted;
Run Code Online (Sandbox Code Playgroud)

在您的客户端代码中,将方法分配给 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()}. ");
};
Run Code Online (Sandbox Code Playgroud)

选项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()}. ");
}
Run Code Online (Sandbox Code Playgroud)

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


小智 5

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

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

创建一个继承自 EventArgs 的通用 EventArgs<T> 类...

class EventArgs<T> : EventArgs {

  public T Value { get; private set; }

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

}
Run Code Online (Sandbox Code Playgroud)

声明您的事件处理程序...

public event EventHandler<EventArgs<object>> LoginCompleted;
Run Code Online (Sandbox Code Playgroud)

假设您已声明并分配了一个名为 的对象loginObject,请添加代码以引发事件...

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

在您的客户端代码中,添加LoginCompleted事件处理程序(使用 Linq 并调用本地方法)...

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

void onLoginCompleted(LoginObject obj) {
  // add your code here
}
Run Code Online (Sandbox Code Playgroud)