2011-08-11 15 views
3

私は自分のクラスにイベントを定義しました。クラスのメソッドの1つをイベントのハンドラにしたいと考えています。現在のクラスのイベントハンドラをカスタムデリゲートで登録する

これは私がこれまで持っているものです。

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

今、私たちはすべてのイベントで設定していることを、あなたは、このイベントのためにいくつかのハンドラを登録することができるようにしたいです。これを行うには、最初にNameの変更を待つPersonのインスタンスが必要で、イベントの正しいシグネチャを持つイベント処理メソッドが必要です。このイベントは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()イベントの発生方法にコードを追加することはお勧めしません。その方法は単にイベントを発生させるために予約する必要があります。

この特定の例では、ハンドラは静的であるため、単一のインスタンスに関連付けられていないことに注意してください。一般的には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クラスによってイベントが発生すると、メインイベントがこのイベントにサブスクライブしているためです。メインにコールバック撮影します。

あなたはイベントを購読しました。イベントの本文はどこですか?

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; 
     } 
    } 
} 
関連する問題