如何在班级之间传递事件?
我知道这听起来很荒谬(确实如此),但在过去的一段时间里我一直被这个问题难住了。搜索没有出现类似的问题,所以我想我会提出它。
涉及的对象如下:
WinForm -> Speaker -> Tweeter
-> Woofer
[Speaker、Tweeter、Woofer] 都声明了一个发送简单字符串消息的“SpeakToMe”事件。事件使用标准模式声明:
public delegate void SpeakToMeHandler(object sender, SpeakToMeEventArgs e);
public event SpeakToMeHandler SpeakToMe;
protected virtual void OnSpeakToMe(string message)
{
if (SpeakToMe != null) SpeakToMe(this, new SpeakToMeEventArgs(DateTime.Now.ToString() + " - " + message));
}
SpeakToMeEventArgs 是一个继承自 EventArgs 的简单类并包含一个字符串属性(Message)。
这些事件本身都运行良好。例如,我在表单中设置了一个按钮来创建、订阅和触发 [扬声器、高音扬声器、低音扬声器] 的事件。每个报告都正确返回。
问题在于,Speaker 创建了 [Tweeter, Woofer] 并订阅了它们的事件。
我想要的是 [Tweeter, Woofer] 触发他们的事件,Speaker 消耗它并触发它自己的事件。我认为这应该非常简单:
void tweeter_SpeakToMe(object sender, SpeakToMeEventArgs e)
{
Console.Out.WriteLine("the tweeter is speaking: " + e.Message);
this.OnSpeakToMe("tweeter rockin' out [" + e.Message + "]");
}
单步执行此函数(在扬声器中),Console.Out.WriteLine 可以工作。继续单步执行 OnSpeakToMe,显示委托为空。
Speaker的SpeakToMe事件由表单订阅。我知道这应该防止事件的委托为空。
我确定这很简单,我错过了什么?
顺便说一句,如果你好奇我为什么要找这个。 [扬声器、高音扬声器、低音扬声器] 是我的演示替身,用于非常长的数据处理操作。该表格同时运行其中几个,并需要每个班级的进度更新。
一如既往,非常感谢任何和所有的帮助!
更新:感谢大家的所有反馈。我真的很感谢你的帮助!我学到了一些很好的技巧(@David Basarab 和 @Brian)以及一些关于如何构建事物的不同想法。再次,非常感谢!
如果我从基本意义上理解你想要什么。是让高音扬声器和低音扬声器触发扬声器也订阅的事件,然后触发自己的事件。
这是我的代码,具有此输出
输出
OnSpeak 消息 = OnSpeakToMeHander 原始消息:由 Tweeter 触发
OnSpeak 消息 = OnSpeakToMeHander 原始消息:由低音扬声器触发
class Program
{
static void Main(string[] args)
{
Console.Clear();
try
{
Speaker speaker = new Speaker();
speaker.speakerEvent += new SpeakToMeHandler(Program.OnSpeak);
// Cause events to be fied
speaker.Tweeter.CauseEvent();
speaker.Woofer.CauseEvent();
}
catch (Exception ex)
{
Console.WriteLine("Error: {0}", ex.Message);
Console.WriteLine("Stacktrace: {0}", ex.StackTrace);
}
}
public static void OnSpeak(object sendere, SpeakToMeEventArgs e)
{
Console.WriteLine("OnSpeak Message = {0}", e.Message);
}
}
public delegate void SpeakToMeHandler(object sender, SpeakToMeEventArgs e);
public class SpeakToMeEventArgs : EventArgs
{
public string Message { get; set; }
}
public class Speaker
{
public event SpeakToMeHandler speakerEvent;
public Tweeter Tweeter { get; set; }
public Woofer Woofer { get; set; }
public void OnSpeakToMeHander(object sender, SpeakToMeEventArgs e)
{
if (this.speakerEvent != null)
{
SpeakToMeEventArgs args = new SpeakToMeEventArgs
{
Message = string.Format("OnSpeakToMeHander Orginal Message: {0}", e.Message)
};
this.speakerEvent(this, args);
}
}
public Speaker()
{
this.Tweeter = new Tweeter();
this.Woofer = new Woofer();
Tweeter.tweeterEvent += new SpeakToMeHandler(this.OnSpeakToMeHander);
Woofer.wooferEvent += new SpeakToMeHandler(this.OnSpeakToMeHander);
}
}
public class Tweeter
{
public event SpeakToMeHandler tweeterEvent;
public void CauseEvent()
{
SpeakToMeEventArgs args = new SpeakToMeEventArgs()
{
Message = "Fired By Tweeter"
};
if (this.tweeterEvent != null)
{
this.tweeterEvent(this, args);
}
}
}
public class Woofer
{
public event SpeakToMeHandler wooferEvent;
public void CauseEvent()
{
SpeakToMeEventArgs args = new SpeakToMeEventArgs()
{
Message = "Fired By Woofer"
};
if (this.wooferEvent != null)
{
this.wooferEvent(this, args);
}
}
}
Eric Lippert 警告不要使用
if (SpeakToMe != null)
代码。虽然在您的情况下这可能不是问题(即,如果您从不删除事件),但您应该养成使用它的习惯:
var tmp = SpeakToMe;
if (tmp!=null) tmp(/*arguments*/);
在 C#6 及更高版本中,请考虑以下简洁的代码:
SpeakToMe?.Invoke(e)
public class Speaker
{
public Speaker()
{
this.MyTweeter = new Tweeter();
}
public Tweeter MyTweeter { get; private set; }
public event SpeakToMeHandler SpeakToMe
{
add { MyTweeter.SpeakToMe += value; }
remove { MyTweeter.SpeakToMe -= value; }
}
}
//Handler class
public class Speaker {
public delegate void HandleMessage(string message);
public event HandleMessage OnMessage;
public void SendMessage(string message) {
if (OnMessage != null) { OnMessage(message); }
}
}
//then used like...
Speaker handler = new Speaker();
handler.OnMessage += (message) => { Console.WriteLine("Woofer: {0}", message); };
handler.OnMessage += (message) => { Console.WriteLine("Tweeter: {0}", message); };
handler.SendMessage("Test Message");