簡體   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