如何在课程之间传递事件?
我知道这听起来很荒谬(而且确实如此)但过去一段时间我一直对此感到难过。搜索没有出现类似的问题所以我想我会构成它。
以下是涉及的对象:
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]的事件。每个都报告正确。
问题是当Speaker创建[Tweeter,Woofer]并订阅他们的活动时。
我想要的是[Tweeter,Woofer]发动他们的事件,发言人消耗它并解雇它自己的事件。我认为这应该是非常直接的:
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,显示委托为空。
演讲者的SpeakToMe活动由表格订阅。我明白这应该可以防止事件的委托为空。
我确定这很简单,我错过了什么?
顺便说一下,如果你对我为什么要这个感到好奇。 [演讲者,Tweeter,Woofer]是我进行长时间数据处理操作的演示站点。表单同时运行其中的几个,并且需要每个类的进度更新。与往常一样,非常感谢任何和所有帮助!
更新:感谢大家的所有反馈。我非常感谢你的帮助!我找到了几个很好的提示(@David Basarab& @Brian)以及一些关于如何构建事物的不同想法。再次,非常感谢!
答案 0 :(得分:4)
如果我从基本意义上理解你想要的东西。是要让Tweeter和Woofer发起扬声器订阅的事件,然后点燃它自己。
这是我的代码,具有此输出
<强>输出强>
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);
}
}
}
答案 1 :(得分:4)
Eric Lippert警告if (SpeakToMe != null)
代码。虽然在你的情况下它可能不是一个问题(即如果你永远不会删除事件),你应该养成使用它的习惯:
var tmp = SpeakToMe;
if (tmp!=null) tmp(/*arguments*/);
在C#6及更高版本中,请考虑使用此terser代码:
SpeakToMe?.Invoke(e)
建议采用后一种方法on the MSDN
答案 2 :(得分:2)
委托将为null的唯一方法是表单实际上没有订阅该事件。你有没有在某个时候创建一个新的扬声器实例?如果您订阅了一个实例,然后使用相同的变量创建了一个新实例,则不会连接新实例的事件。
答案 3 :(得分:1)
您可以使用长形式的事件声明将事件传递给内部对象。
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; }
}
}
答案 4 :(得分:0)
为什么不为事件分配额外的处理程序,而不是传递事件?您不仅限于一种方法。
//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");