我有一个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
}
所以我的问题是将用户对象恢复为父级的“已批准”方法是什么?创建一个可以访问的属性类并将其放在那里?
答案 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 ...
的通用EventArgsclass 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 tuples与EventHandler<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