繁体   English   中英

使用自定义委托为当前 class 上的事件注册处理程序

[英]Registering a handler for an event on the current class with a custom delegate

我在我的 class 上定义了一个事件,我想让 class 的方法之一成为该事件的处理程序。

这是我到目前为止所拥有的:

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 中进行?

阅读如何:发布符合 .NET 框架指南的事件,了解有关如何创建和使用事件的更多信息。 那里的例子并不像它应该的那样清楚,所以我将在这里介绍整个过程。


定义事件所需的第一部分是要使用的事件处理程序委托。 这是所有希望接收有关此事件的通知的人都需要的方法签名。 您通常不必自己创建新委托,您应该使用现有的EventHandler (或通用EventHandler<TEventArgs> )委托。 如果您不需要包含有关该事件的任何其他 arguments,则可以使用非通用版本。 否则,您将使用通用版本。 在您的情况下,该事件不需要任何其他 arguments ,因此您应该使用非通用EventHandler

(如果您希望能够将诸如旧值和新值之类的信息包含为 arguments,则可以使用通用版本以及从EventArgs派生的适当 class 。有点高级主题,所以我们将跳过它。)


下一部分是定义事件。 就像您为 class 定义一个属性一样简单。 这里的不同之处在于您将使用event关键字来指定您正在定义一个事件,然后是要使用的委托和事件的名称。 Changed .更改属性的事件命名约定通常在模式 Changed中。 由于您希望在Name属性更改时触发一个事件,因此您应该将其命名为: NameChanged

public event EventHandler NameChanged;

一个可选(但强烈推荐)步骤是定义用于引发事件的方法。 这将使您更容易在需要时提出事件。 通常的命名约定类似于事件的命名方式。 .这一次, On 因此,您将在此处将其命名为OnNameChanged 它通常被定义为受保护的虚拟方法,派生类可以轻松地覆盖它。 arguments 到 function 应该是事件所需的 arguments。 由于此处没有 arguments,因此签名中可能没有 arguments。

一切就绪后,只需调用事件处理程序即可。 它只是一个代表,所以只需调用它。 但是不要忘记首先检查它是否是null ,这表示没有注册事件处理程序。 处理程序的 arguments 应该是this (引发事件的 object)以及 arguments 应该是什么。 在这种情况下,没有 arguments 但您应该返回“空” 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!!!
        }
    }
}

现在我们已经设置好了事件,您希望能够为该事件注册一些处理程序。 为了能够做到这一点,首先我们需要要等待Name更改的Person实例,并且我们需要一个具有正确签名的事件处理方法。 该事件被定义为使用EventHandler委托,因此我们需要一个带有签名的方法: void NameChanged(object sender, EventArgs e) 请记住, sender参数是引发事件的 object。 在这种情况下,它是一个Person object,因此我们可以获取已更改的 object,并根据需要检查属性。 你可以随意命名它。 _ .我个人的模式我 go 是: _ 所以在这种情况下,我将其命名为: 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;

如果您希望处理程序完全位于 class 中,您可以在 class 中注册事件。 无需在外部接线。 你可以从构造函数中做到这一点。 我不建议将您的代码添加到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
}

请注意,在此特定示例中,处理程序是 static,因此它不绑定到单个实例。 它一般适用于任何Person 请注意,由于它是 static,因此您将无法在方法中使用this ,这就是为什么需要对发件人进行强制转换的原因。 是否是 static 最终取决于您,无论哪种方式都应该没问题。


所以把这一切放在一起,这就是你可以做的:

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";
    }
}

我更改并评论了您的代码,但我不确定您打算做什么:

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;
        }
    }
}

在您的人中调用一个方法并开始在该方法中引发事件。 每当人 class 引发事件时,因为主已订阅此事件。 您会收到 Main 的回电。

您刚刚订阅了该活动。 活动主体在哪里??

如果你 rem winforms 事件。 您订阅让我们说按钮单击事件,例如 btn_Click(object, eventArgs).. 然后您为这个事件方法提供一个主体,对吗? 这里也一样。

我真的不明白你的意图是什么,但是:

  1. 您尚未在将处理名称更改事件的程序 class 中订阅 function。

  2. 您尚未在 Person class 中触发事件。 你应该写:

    protected void NameChange(EventArgs arg) { Console.WriteLine("名称更改..."); NameChangeEventHandler(); }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM