2011-08-11 100 views
3

我在我的類上定義了一個事件,並且希望使該類的某個方法成爲該事件的處理程序。使用自定義代理註冊當前類上事件的處理程序

這是我到目前爲止有:

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

如何註冊事件處理程序,而不必做它在主?

回答

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

調用你的人的方法,並開始在該方法中引發事件。當Person類提出事件時,由於main已訂閱了此事件。你接到Main的電話。

您剛剛訂閱了該活動。活動組織在哪裏?

如果你rem的winforms事件。你訂閱可以說按鈕點擊事件,如btn_Click(object,eventArgs)..然後你給這個事件方法正確的權利?這裏是一樣的。

0

我真的不明白你的意圖是什麼,但:

  1. 你還沒有訂閱的計劃類的函數將處理更名事件。

  2. 你還沒有在Person類中解僱過這個事件。你應該寫:

    protected void NameChange(EventArgs arg) { Console.WriteLine(「Name change ...」); NameChangeEventHandler(); }

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; 
     } 
    } 
} 
相關問題