- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我至少阅读了十几篇关于事件的文章和 SO 线程,并弄清楚了基本的想法,但我对如何以正确的方式做到这一点有些困惑。似乎至少有两种常见的事件编写方法,一种比另一种更值得推荐。
我看到很多 Material 中作者跳过了部分过程,并假设出于某种原因您会知道这一点。还有很多教程,如“MyEventExample”和“SomeProcessGoesHere”,这使得理解整个示例变得更加困难。很多例子都在教你如何做某事,但最后却声明你在现实中当然永远不会那样做——但它们并没有提供你会 去做。
最后,使用事件的场景的每个组件的命名约定似乎无处不在。我很难弄清楚某些概念在何处应用,因为每个人都以不同的方式命名它的每一部分。
所以这就是我所追求的:我在游戏中有一个简单的情况,它会利用事件。我希望有人参与并编写事件接线,演示推荐的方法以及最常见的命名和结构约定。我知道要求为我编写代码是一种糟糕的形式,但我确实在寻找编写代码的方式,以便我可以自信地开始自己编写代码。
请忽略这是否是一个好的游戏设计,甚至是否适合举办事件。我只是对如何正确编写事件内容感兴趣,这是我的示例空间。
//In my game I have a number of entities which can 'talk' to the player.
//An NPC can greet them, a zone might 'greet' them by displaying "Cityville"
//when they enter it, their inventory might tell them they're out of space,
//and so on. Everything would pass a Message object to a Messenger object,
//which would then deliver the messages as it saw fit.
public class Messenger
{
private Queue<Message> _messages = new Queue<Message>();;
private Stack<Message> _archive = new Stack<Message>();;
public IEnumerable<Message> Messages { get { return _messages.AsEnumerable(); } }
public IEnumerable<Message> Archive { get { return _archive.AsEnumerable(); } }
public void Add(Message message)
{
_messages.Enqueue(message);
}
public void Deliver()
{
Message msg = _messages.Dequeue();
_archive.Push(msg);
//Here's where I'd broadcast to any subsystem listening
//that the message was delivered
//Event args should be (_archive.Peek(), DateTime.Now);
}
public event MessageDeliveryEvent Delivery;
protected virtual void OnDelivery(MessageHandlerDeliveryEventArgs e)
{
if (this.Delivery != null) { this.Delivery(this, e); }
}
}
//Okay, here's my delegate declared outside any class. One tutorial suggested
//putting it in the same file as the event arguments class so it would be
//easier to find, which sounds reasonable to me, but I dunno.
public delegate void MessageDeliveryEvent(object sender, MessageHandlerDeliveryEventArgs e);
//I've seen examples where they don't even write an event arguments class.
//I think you could probably just pass the same stuff directly, but the
//separate class sounds like a good idea, more flexible if things change.
public class MessageHandlerDeliveryEventArgs : EventArgs
{
private readonly Message _message;
private readonly DateTime _delivered;
public MessageHandlerDeliveryEventArgs(Message message, DateTime delivered)
{
_message = message;
_delivered = delivered;
}
public Message Message { get { return _message; } }
public DateTime DeliveryDateTime { get { return _delivered; } }
}
//So in the UI layer I'd have things like a ChatBox which would be a
//scrolling list of everything said to the player. There would also be a
//GeneralInfoBox control that displayed things like what zone you just
//entered, or that your inventory is full. Both would listen to the
//Messenger object for a delivery event, and then check the Message object
//associated with that event to see if they needed to handle the display
//of that message.
public class ChatBox
{
//OMG there's a new message, lemme see if I should display it
private void TheThingThatListensToMessengerEvents(Message message, DateTime datetime)
{
if Message.Type == MessageType.Chat { Print(datetime.ToString() + ": " + message.Text); }
}
public string Print(string text) {}
}
public class GeneralInfoBox
{
//OMG there's a new message, lemme see if I should display it
private void TheThingThatListensToMessengerEvents(Message message)
{
if Message.Type == MessageType.General { Print(message.Text); }
}
public string Print(string text) {}
}
如果我能澄清任何事情,请告诉我。如果有一个非常好的教程我显然错过了,请随时指出我。提前致谢。
这是我的示例,其中包含事件。也许它会帮助像我一样思考的其他人(上帝帮助他们)想象它。
public class MessageHandler
{
private Queue<Message> _messages = new Queue<Message>();
private Stack<Message> _archive = new Stack<Message>();
public MessageHandler() { }
public IEnumerable<Message> Messages { get { return _messages.AsEnumerable(); } }
public IEnumerable<Message> Archive { get { return _archive.AsEnumerable(); } }
public void Add(Message message)
{
_messages.Enqueue(message);
}
public void Deliver()
{
Message msg = _messages.Dequeue();
_archive.Push(msg);
//Call the method which broadcasts the event
OnDelivery(new MessageDeliveryEventArgs(_archive.Peek(), DateTime.Now));
}
//The event
public event EventHandler<MessageDeliveryEventArgs> Delivery;
//The method which broadcasts the event
protected virtual void OnDelivery(MessageDeliveryEventArgs messageDeliveryEventArgs)
{
EventHandler<MessageDeliveryEventArgs> handler = Delivery;
if (handler != null) { handler(this, messageDeliveryEventArgs); }
}
}
//The event arguments class for the event of interest. Carries information about this kind of event
public class MessageDeliveryEventArgs : EventArgs
{
private readonly Message _message;
private readonly DateTime _delivered;
public MessageDeliveryEventArgs(Message message, DateTime delivered)
{
_message = message;
_delivered = delivered;
}
public Message Message { get { return _message; } }
public DateTime DeliveryDateTime { get { return _delivered; } }
}
//A UI control which listens for an event in a Messenger object
public class ChatBox
{
//Specify the instance of the Messenger class to whose event(s) we plan to subscribe
public ChatBox(MessageHandler messenger)
{
//Subscribe this control's OnDelivery method to the Delivery event of the specified instance of Messenger
messenger.Delivery += this.OnDelivery;
}
//The method which we intend to subscribe to the Delivery event of an instance of Messenger
private void OnDelivery(object sender, MessageDeliveryEventArgs e)
{
if (e.Message.Format == MessageFormat.Local)
{
Print(String.Format("{0}: {1}", e.DeliveryDateTime, e.Message.Text));
}
}
private void Print(string text) { }
}
最佳答案
这是设置标准 .Net 事件所遵循的典型约定的示例:
using System;
namespace ObserverExample
{
class Program
{
static void Main(string[] args)
{
var subject = new Subject();
var observer = new Observer();
observer.Observe(subject);
subject.SomeAction();
Console.ReadLine();
}
}
public class Subject
{
public event EventHandler<TopicEventArgs> TopicHappening;
public void SomeAction()
{
OnTopicHappening(new TopicEventArgs("Hello, observers!"));
}
protected virtual void OnTopicHappening(TopicEventArgs topicEventArgs)
{
EventHandler<TopicEventArgs> handler = TopicHappening;
if (handler != null)
handler(this, topicEventArgs);
}
}
public class TopicEventArgs : EventArgs
{
public TopicEventArgs(string message)
{
Message = message;
}
public string Message { get; private set; }
}
public class Observer
{
public void Observe(Subject subject)
{
subject.TopicHappening += subject_TopicHappening;
}
void subject_TopicHappening(object sender, TopicEventArgs e)
{
Console.WriteLine(e.Message);
}
}
}
此示例中涉及的三个主要类是 Subject
, Observer
, 和 TopicEventArgs
. Program
类仅用于为示例提供驱动程序。
首先查看 Program.Main() 方法,首先实例化 Subject(将引发事件的对象)和 Observer(将订阅引发的事件的对象)的实例。接下来,向观察者传递一个主题实例,使其有机会订阅任何所需的事件。最后,调用主体的 SomeAction() 方法,这会引发事件。
查看主题,我们看到名为 TopicHappening 的事件 EventHandler<TopicEventArgs>
被公开宣布。 EventHandler 类型是在 .Net 2.0 中引入的,它允许在不必显式定义委托(delegate)类型的情况下声明事件。 Subject 类也有两个方法,SomeAction()
和 OnTopicHappening()
.方法SomeAction()
表示应用程序中的点,Subject 执行一些它想要通知世界(即“任何观察者”)的任务。方法OnTopicHappening(TopicEventArgs)
方法提供类中将引发事件的逻辑点。首先,请注意它遵循 On[事件名称] 的命名约定。虽然此方法可以命名为任何名称,但此模式已按惯例广泛采用。其次,请注意它被定义为采用 TopicEventArgs 类型的单个参数。这也遵循标准约定,目的是在引发事件的逻辑点(在 SomeAction() 方法中)而不是从引发事件的物理点来决定引发哪些事件参数。第三,注意它被声明为 protected 虚拟。通常遵循此模式以允许任何扩展 Subject 的类覆盖引发 TopicHappening 事件时究竟发生了什么。在 OnTopicHappening() 方法中,TopicHappening 事件在检查是否为 null 并被调用之前被分配给一个单独的变量。这是为了避免可能的竞争条件,即事件可能在检查 null 之后但在调用事件之前被另一个线程(即所有观察者取消订阅)清除。
查看 TopicEventArgs 类,这代表我们的主题提出的事件主题。当主题需要将信息与引发的事件相关联时,通常会创建自定义 EventArgs 类。对于只希望发送没有任何关联参数的信号事件的主题,应使用基 EventArgs.Empty 类。
最后,Observer 类定义将从 Subject 接收事件通知的对象。在此示例中,Observer 类公开了一个 Observe() 方法,作为接收对 Subject 实例的引用的一种方式。在该方法中,一个名为 subject_TopicHappening 的私有(private)事件处理程序方法被分配给主题上的 TopicHappening 事件。此名称格式是 Visual Studio 在注册处理事件时键入 += 时自动生成的委托(delegate)的结果。这实质上是将此方法添加到方法集合中,以便在主题引发事件时调用。调用时,私有(private) subject_TopicHappening 方法只是将事件参数中包含的消息写入控制台。
希望这对您有所帮助。
关于c# - 帮助我以正确的方式编写此事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3272042/
我正在尝试将 WPF CodeBehid 事件(如 Event、Handler、EventSetter)转换为 MVVM 模式。我不允许使用 System.Windows.Controls,因为我使用
我可能误解了 Backbone 中的事件系统,但是当我尝试以下代码时什么也没有发生。当我向 Backbone.Events 扩展对象添加新属性时,它不应该触发某种更改、更新或重置事件吗?就像模型一样吗
我遇到了一个简单的问题,就是无法弄清楚为什么它不起作用。我有一个子组件“app-buttons”,其中我有一个输入字段,我想听,所以我可以根据输入值过滤列表。 如果我将输入放在我有列表的根组件中,一切
System.Timers.Timer 的 Elapsed 事件实际上与 System.Windows.Forms.Timer 的 Tick 事件相同吗? 在特定情况下使用其中一种比使用另一种有优势吗
嗨,这个 javascript 代码段是什么意思。(evt) 部分是如此令人困惑.. evt 不是 bool 值。这个怎么运作? function checkIt(evt) { evt
我正在使用jquery full calendar我试图在事件被删除时保存它。 $('calendar').fullCalendar ({
我有两个链接的鼠标事件: $('body > form').on("mousedown", function(e){ //Do stuff }).on("mouseup", function(
这是我的代码: $( '#Example' ).on( "keypress", function( keyEvent ) { if ( keyEvent.which != 44 ) {
我尝试了 dragOver 事件处理程序,但它没有正常工作。 我正在研究钢琴,我希望能够弹奏音符,即使那个键上没有发生鼠标按下。 是否有事件处理程序? 下面是我正在制作的钢琴的图片。 最佳答案 您应该
当悬停在相邻文本上时,我需要使隐藏按钮可见。这是通过 onMouseEnter 和 onMouseLeave 事件完成的。但是当点击另外的文本时,我需要使按钮完全可见并停止 onMouseLeave
我有ul标签内 div标签。我申请了mouseup事件 div标记和 click事件 ul标签。 问题 每当我点击 ul标签,然后都是 mouseup和 click事件被触发。 我想要的是当我点击 u
我是 Javascript 和 jQuery 的新手,所以我有一个非常愚蠢的疑问,请耐心等待 $(document).click(function () { alert("!"); v
我有一个邮政编码解析器,我正在使用 keyup 事件处理程序来跟踪输入长度何时达到 5,然后查询服务器以解析邮政编码。但是我想防止脚本被不必要地调用,所以我想知道是否有一种方法可以跟踪 keydown
使用事件 API,我有以下代码来发布带有事件照片的事件 $facebook = new Facebook(array( "appId" => "XXX", "se
首次加载 Microsoft Word 时,既不会触发 NewDocument 事件也不会触发 DocumentOpen 事件。当 Word 实例已打开并打开新文档或现有文档时,这些事件会正常触发。
我发现了很多相关问题(这里和其他地方),但还没有具体找到这个问题。 我正在尝试监听箭头键 (37-40) 的按键事件,但是当以特定顺序使用箭头键时,后续箭头不会生成“按键”事件。 例子: http:/
给定的 HTML: 和 JavaScript 的: var $test = $('#test'); $test.on('keydown', function(event) { if (eve
我是 Node.js 的新手,希望使用流运行程序。对于其他程序,我必须同时启动一个服务器(mongodb、redis 等),但我不知道我是否应该用这个运行一个服务器。请让我知道我哪里出了问题以及如何纠
我正在尝试使用 Swift 和 Cocoa 创建一个适用于 OS X 的应用程序。我希望应用程序能够响应关键事件,而不将焦点放在文本字段上/文本字段中。我在 Xcode 中创建了一个带有 Storyb
我有以下代码: (function(w,d,s,l,i){ w[l]=w[l]||[];w[l].push({
我是一名优秀的程序员,十分优秀!