我在我的类上定义了一个事件,我想让该类的一个方法成为事件的处理程序。
这是我到目前为止所做的:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DelegatesAndEvents
{
class Program
{
static void Main(string[] args)
{
Person p = new Person();
p.NameChangeEventHandler += new Person.NameChangeEventHandlerDel;
p.Name = "Paul";
}
}
class Person
{
#region Events
public delegate void NameChangeEventHandlerDel(object sender, EventArgs args);
public event EventHandler NameChangeEventHandler;
protected void NameChange(EventArgs arg)
{
Console.WriteLine("Name change...");
}
#endregion
#region Properties
private string name;
public string Name
{
get { return name; }
set
{
NameChange(null);
name = value;
}
}
#endregion
public Person(string name = "John")
{
this.name = name;
}
}
}
如何在Main中注册事件处理程序?
答案 0 :(得分:5)
阅读How to: Publish Events that Conform to .NET Framework Guidelines,了解有关如何创建和使用事件的更多信息。这个例子并不像它应该那样清楚,所以我将在这里完成这个过程。
定义事件所需的第一部分是要使用的事件处理程序委托。这是所有希望收到有关此活动的通知的人所需的方法签名。您通常不必自己创建新的委托,您应该使用现有的EventHandler
(或通用EventHandler<TEventArgs>
)委托。如果您不需要包含有关该事件的任何其他参数,则可以使用非泛型版本。否则你将使用通用版本。在您的情况下,没有任何关于该事件的其他参数,因此您应该使用非泛型EventHandler
。
(如果您希望能够将旧值和新值等信息作为参数包含在内,那么您将使用通用版本以及从EventArgs
派生的适当类。有点高级主题所以我们将跳过它。)
下一部分是定义事件。就像你为你的班级定义一个属性一样简单。这里的区别在于您使用event
关键字来指定您要定义的事件后跟要使用的委托和事件的名称。命名事件以更改属性的约定通常采用模式PropertyNameChanged
。由于您希望在Name
属性更改时触发事件,因此您应将其命名为:NameChanged
。
public event EventHandler NameChanged;
可选(但强烈推荐)的步骤是定义用于引发事件的方法。这将使您更容易在需要时举起活动。通常的命名约定类似于事件的命名方式。这一次,OnEventName
。所以你在这里命名为OnNameChanged
。它通常被定义为受保护的虚方法,派生类可以轻松地覆盖它。函数的参数应该是事件所需的参数。由于此处没有参数,因此签名中可能没有参数。
有了这一切,只需要调用事件处理程序即可。它只是一个代表,所以只需要它。但是不要忘记先检查它是null
,这表示没有注册事件处理程序。处理程序的参数应该是this
(引发事件的对象)以及参数应该是什么。在这种情况下,没有参数,但您应该返回“空”EventArgs
的实例。
protected virtual void OnNameChanged()
{
EventHandler nameChanged = NameChanged; // always a good idea to store in a local variable
if (nameChanged != null)
{
nameChanged(this, new EventArgs());
}
}
最后一部分是在你的属性中连接它。如果赋值将更改属性的值,则您希望引发事件。非常简单,只需检查旧值是否与新值不同。如果是,请更改它并引发事件。否则,别做什么。
private string name;
public string Name
{
get { return name; }
set
{
if (!String.Equals(value, name)) // if the value gets changed...
{
name = value;
OnNameChanged(); // raise the event!!!
}
}
}
现在我们已经完成了事件的设置,您希望能够为此事件注册一些处理程序。为了能够做到这一点,首先我们需要我们想要等待Person
更改的Name
实例,我们需要一个事件处理方法,并为事件提供正确的签名。该事件被定义为使用EventHandler
委托,因此我们需要一个带签名的方法:void NameChanged(object sender, EventArgs e)
。请记住,sender
参数是引发事件的对象。在这种情况下,它是一个Person
对象,因此我们可以获取已更改的对象,并在需要时检查属性。你可以随意命名。我个人采用的模式是:InstanceName_EventName
。所以在这种情况下,我将其命名为:person_NameChanged
。
static void person_NameChanged(object sender, EventArgs e)
{
Person person = (Person)sender; // cast back to a Person so we can see what's changed
Console.WriteLine("The name changed!");
Console.WriteLine("It is now: " + person.Name); // let's print the name
}
定义完成后,将处理程序添加到事件中,如果有任何更改,我们会收到通知。
person.NameChanged += person_NameChanged;
如果您希望处理程序完全在类中,您可以在类中注册该事件。无需外接电线。你可以从构造函数中完成它。我不建议将您的代码添加到OnNameChanged()
事件引发方法中,该方法应保留用于简单地引发事件。
public Person(string name = "John")
{
this.name = name;
this.NameChanged += builtin_NameChanged;
}
private static void builtin_NameChanged(object sender, EventArgs e)
{
Person person = (Person)sender; // cast back to a Person so we can see what's changed
Console.WriteLine("The name changed!");
Console.WriteLine("It is now: " + person.Name); // let's print the name
}
请注意,在此特定示例中,处理程序是静态的,因此它不依赖于单个实例。它适用于任何Person
。请注意,由于它是静态的,因此您无法在方法中使用this
,这就是为什么需要使用发送方进行转换的原因。它是否是静态的取决于你最终,无论哪种方式都应该没问题。
所以要把这些放在一起,这就是你能做的:
class Person
{
public Person(string name = "John")
{
this.name = name;
this.NameChanged += builtin_NameChanged;
}
public string Name
{
get { return name; }
set
{
if (!String.Equals(value, name))
{
name = value;
OnNameChanged();
}
}
}
public event EventHandler NameChanged;
protected virtual void OnNameChanged()
{
EventHandler nameChanged = NameChanged;
if (nameChanged != null)
{
nameChanged(this, new EventArgs());
}
}
private static void builtin_NameChanged(object sender, EventArgs e)
{
Person person = (Person)sender;
Console.WriteLine("The name changed!");
Console.WriteLine("It is now: " + person.Name);
}
private string name;
}
class Program
{
static void Main(string[] args)
{
Person person = new Person();
person.Name = "Paul";
}
}
答案 1 :(得分:2)
我更改并评论了您的代码,但我不确定您打算做什么:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DelegatesAndEvents
{
class Program
{
static void Main(string[] args)
{
Person p = new Person();
//here you have an event of type EventHandler and want to subscribe with a delegate of type
//NameChangeEventHandlerDel. This can't work. Furthermore you have to create the delegate passing
//a method.
//p.NameChangeEventHandler += new Person.NameChangeEventHandlerDel;
// this could be better (even if I'm not sure about the necessity to use an event,
//but it probably depends on what you really are trying to do):
p.NameChangeEventHandler += new EventHandler(p.NameChange);
p.Name = "Paul";
}
}
class Person
{
#region Events
// why do you define the delegate NameChangeEventHandlerDel and then declare the event of type EventHandler?
public delegate void NameChangeEventHandlerDel(object sender, EventArgs args);
public event EventHandler NameChangeEventHandler;
protected void NameChange(EventArgs arg)
{
Console.WriteLine("Name change...");
}
#endregion
#region Properties
private string name;
public string Name
{
get { return name; }
set
{
// here you should not call your method directly, but trigger the event (if this is what you want)
//i.e not: NameChange(null); but something like:
if (NameChangeEventHandler != null)
NameChangeEventHandler(this, null);
name = value;
}
}
#endregion
public Person(string name = "John")
{
this.name = name;
}
}
}
答案 2 :(得分:0)
在您的人员中调用方法并开始在该方法中引发事件。当Person类引发事件时,由于main已订阅此事件。你接到一个回电话进入Main。
您刚刚订阅了此活动。活动体在哪里??
如果您重新获得winforms事件。你订阅了让按钮点击事件,如btn_Click(object,eventArgs)..然后你给这个事件方法的正文吧?同样的方式。
答案 3 :(得分:0)
我真的不明白你的意图,但是:
您尚未在Program类中订阅将处理名称更改事件的函数。
您尚未在Person类中触发该事件。你应该写:
protected void NameChange(EventArgs arg) { Console.WriteLine(“名称更改...”); NameChangeEventHandler(); }