2012-09-03 20 views
7

場合は、以下があります。オブジェクトのチェーン全体でイベントを処理する方法は?

public static void main() { 
    MyClass1 obj = new MyClass1(); 
    obj.Method1(); 
} 
public class MyClass1() { 
    public void Method1() { 
     MyClass2 obj = new MyClass2(); 
     obj.Method1(); 
    } 
} 
public class MyClass2() { 
    public void Method1() { 
     MyClass3 obj = new MyClass3(); 
     obj.Method1(); 
    } 
} 
public class MyClass3() { 
    public void Method1() { 
     // Raise event here that is handled in MyClass1?  
    } 
} 

MyClass3.Method1()MyClass1に処理されるイベントを発生させることはできますか?

これを達成したい場合、イベント処理コードはどのように書かれますか?

答えて

1

イベント処理ABCでは、サブスクライバとパブリッシャがあると想定しています。 MyClass1はこのイベントを購読していますが、MyClass3には公開イベントが必要です。

しかし、あなたの特定のコードでは、この複雑さはどんな意味がありません - ちょうどコールバック関数を使用するための最も簡単な方法:

public static void main() { 
    MyClass1 obj = new MyClass1(); 
    obj.Method1(); 
} 
public class MyClass1{ 
    public void Method1() { 
     MyClass2 obj = new MyClass2(); 
     obj.Method1(MyEventHandler); 
    } 

    public void MyEventHandler() { 
    //... 
    } 

} 
public class MyClass2{ 
    public void Method1(Action callback) { 
     MyClass3 obj = new MyClass3(); 
     obj.Method1(callback); 
    } 
} 
public class MyClass3{ 
    public void Method1(Action callback) { 
     // Raise event here that is handled in MyClass1?  
     callback(); 
    } 
} 
+0

「アクション」タイプは新しいですか?私はC#2.0のみを使用しています。代わりに 'delegate'を使用できますか? –

+0

@PaulLassiterアクションはパラメータとvoid型の戻り値を持たないデリゲートです。あなたは自分で同等のものを定義することができます。 –

+0

パブリックデリゲートvoid Action(); –

3

はい、それはできますが、各レベルはより深いレベルについて知らないので、あなたのチェーンの中で、あなたは各クラスのイベントを作成する必要があります。このようなもの:

public static void main() { 
    MyClass1 obj = new MyClass1(); 
    obj.MyEvent += (s, e) => { Console.WriteLine("Fired!"); }; 
    obj.Method1(); 
} 

public class MyClass1 { 
    public void Method1() { 
     MyClass2 obj = new MyClass2(); 
     obj.MyEvent += (s, e) => { OnMyEvent(); }; 
     obj.Method1(); 
    } 
    public event EventHandler MyEvent; 
    private void OnMyEvent() { 
     var myEvent = MyEvent; 
     if (myEvent != null) 
      myEvent(this, EventArgs.Empty); 
    } 
} 
public class MyClass2 { 
    public void Method1() { 
     MyClass3 obj = new MyClass3(); 
     obj.MyEvent += (s, e) => { OnMyEvent(); }; 
     obj.Method1(); 
    } 
    public event EventHandler MyEvent; 
    private void OnMyEvent() { 
     var myEvent = MyEvent; 
     if (myEvent != null) 
      myEvent(this, EventArgs.Empty); 
    } 
} 
public class MyClass3 { 
    public void Method1() { 
     // Raise event here that is handled in MyClass1?  
     OnMyEvent(); 
    } 
    public event EventHandler MyEvent; 
    private void OnMyEvent() { 
     var myEvent = MyEvent; 
     if (myEvent != null) 
      myEvent(this, EventArgs.Empty); 
    } 
} 
+0

イベントをMyClass1に戻す必要があります。実際、MyClass1はMyClass3によって生成されたイベントを処理できません。 –

+1

あなたの問題は、MyClass1がイベントを発生させるMyClass3のインスタンスを知らないため、イベントを購読できないという事実です。 –

+0

@PaulLassiter - フランチェスコはそれに私を打ち負かした。 – Maarten

1

イベントを仲介クラスに追加すると、イベントを接続できます。このような何か:あなたが考慮する必要があります

using System; 
using System.Windows.Forms; 

namespace Demo 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      MyClass1 obj = new MyClass1(); 
      obj.Method1(); 
     } 
    } 

    public class MyClass1 
    { 
     public void Method1() 
     { 
      MyClass2 obj = new MyClass2(); 
      obj.SomethingHappened += somethingHappened; 
      obj.Method1(); 
     } 

     private static void somethingHappened(object sender, EventArgs e) 
     { 
      Console.WriteLine("Something happened!"); 
     } 
    } 

    public class MyClass2 
    { 
     public void Method1() 
     { 
      MyClass3 obj = new MyClass3(); 
      obj.SomethingHappened += onSomethingHappened; 
      obj.Method1(); 
     } 

     public event EventHandler SomethingHappened; 

     private void onSomethingHappened(object sender, EventArgs e) 
     { 
      var handler = SomethingHappened; 

      if (handler != null) 
      { 
       handler(this, e); 
      } 
     } 
    } 

    public class MyClass3 
    { 
     public void Method1() 
     { 
      onSomethingHappened(); 
     } 

     private void onSomethingHappened() 
     { 
      var handler = SomethingHappened; 

      if (handler != null) 
      { 
       handler(this, new EventArgs()); 
      } 
     } 

     public event EventHandler SomethingHappened; 
    } 
} 

ことの一つは、あなたが仲介クラスで「送信者」の引数に何をすべきかです。あなたは(上記のコードのように)それMyClass2を作ることができるか、あなたはこのように、元の送信者を保つことができる:チェーンイベントハンドラに

private void onSomethingHappened(object sender, EventArgs e) 
{ 
    var handler = SomethingHappened; 

    if (handler != null) 
    { 
     handler(sender, e); 
    } 
} 
2

、MyClass2の構文の追加/削除を使用します。 MyClass1からSomeEventを設定し、MyClass3でそれを発生させます。

public class MyClass1    
{    
    MyClass2 obj = new MyClass2(); 

    public MyClass1() 
    { 
     obj.SomeEvent += obj_SomeEvent; 
    } 

    public void Method1()    
    {      
     obj.Method1();    
    }    

    private static void obj_SomeEvent(object sender, EventArgs e)    
    {    
     Console.WriteLine("Some event fired");    
    }    
} 


public class MyClass2() 
{  
    MyClass3 cls3 = new MyClass3(); 

    public void Method1() 
    {  
     cls3.FireSomeEvent();  
    } 

    public event MyEventHandler SomeEvent 
    { 
     add { this.cls3.SomeEvent += value; } 
     remove { this.cls3.SomeEvent -= value; } 
    } 
} 

public class MyClass3() 
{ 
    public event EventHandler SomeEvent; 

    private void OnSomeEvent() 
    { 
     if (SomeEvent!= null) 
     { 
      SomeEvent(this, new EventArgs()); 
     } 
    } 

    public void FireSomeEvent 
    { 
     OnSomeEvent(); 
    } 
} 
+0

ここでは、ローカル変数をフィールド(MyClass2のMyClass3)に変換することをやっているのです。さらに、MyClass2のSomeEventに登録するとcls3がnullになるため、動作しません。つまり、MyClass3をMyClass2のMethod1の外部にインスタンス化する必要がありますが、これはOPが好きなことではないと思います。 –

+0

@FrancescoBaruchelli - バグを指摘してくれてありがとう。 –

1

コールバックソリューションと各クラスのイベントチェーンを回避するには、基本的に2つのソリューションがあります。

最初のものは、MyClassXタイプのローカル変数をフィールドに変換することです。つまり、Chris Gesslerの提案ですが、このアプローチに完全に従い、ローカル変数を削除することです。

public static void main() { 
    MyClass1 obj = new MyClass1(); 
    obj.c2.c3.SomeEvent += obj_SomeEvent;  
    obj.Method1(); 
} 

private static void obj_SomeEvent(object sender, EventArgs e)    
{    
    Console.WriteLine("Some event fired");    
} 

public class MyClass1() { 
    public MyClass2 c2 = new MyClass2(); 

    public void Method1() { 
     c2.Method1(); 
    } 
} 
public class MyClass2() { 
    public MyClass3 c3 = new MyClass3(); 

    public void Method1() { 
     c3.Method1(); 
    } 
} 
public class MyClass3() { 
    public event EventHandler SomeEvent; 

    private void OnSomeEvent() 
    { 
     if (SomeEvent!= null) 
     { 
      SomeEvent(this, new EventArgs()); 
     } 
    } 
    public void Method1() { 
     OnSomeEvent();  
    } 
} 

あなたの他のオプションは、(それは本当にあなたはそれが可能であればやろうとしているかに依存しており、私はとにかく好きではない)、単に静的としてMyClass3でイベントを定義することです:

public static void main() { 
    MyClass3.SomeEvent += obj_SomeEvent; 
    MyClass1 obj = new MyClass1(); 
    obj.Method1(); 
} 

private static void obj_SomeEvent(object sender, EventArgs e)    
{    
    Console.WriteLine("Some event fired");    
} 

public class MyClass1() { 
    public void Method1() { 
     MyClass2 obj = new MyClass2(); 
     obj.Method1(); 
    } 
} 
public class MyClass2() { 
    public void Method1() { 
     MyClass3 obj = new MyClass3(); 
     obj.Method1(); 
    } 
} 
public class MyClass3() { 
    public static event EventHandler SomeEvent; 

    private void OnSomeEvent(MyClass3 anObj) 
    { 
     if (SomeEvent!= null) 
     { 
      SomeEvent(anObj, new EventArgs()); 
     } 
    } 

    public void Method1() { 
     OnSomeEvent(this);  
    } 
}