2012-09-03 8 views
7

Si tienen la siguiente:¿Cómo se maneja el evento a través de la cadena de objetos?

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

Puede MyClass3.Method1() provocar un evento que se maneja en MyClass1?

¿Cómo se escribiría el código de manejo de eventos si quisiera lograr esto?

Respuesta

1

Manejo de eventos El ABC supone que tiene suscriptor y publicador. Por lo tanto, es posible que desee que su MyClass3 tenga un evento público, mientras que MyClass1 se suscribe para este evento.

Sin embargo, en su código específico de esta complejidad no tiene ningún sentido - la forma más fácil simplemente utilizar una función de devolución de llamada:

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

¿El tipo 'Action' es nuevo? Solo estoy usando C# 2.0. ¿Se podría usar un "delegado" en su lugar? –

+0

@PaulLassiter Action es solo un delegado sin parámetros y tipo de devolución de nulo. Puedes definir algo equivalente por ti mismo. –

+0

delegado público void Acción(); –

3

Sí se puede, pero dado que cada nivel no sabe nada de los niveles más profundos de tu cadena, deberías crear eventos en cada clase. A algunos les gusta esto:

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

Entonces, ¿tiene que volver a encadenar los eventos a MyClass1, entonces, de hecho, MyClass1 no puede manejar un evento provocado por MyClass3? –

+1

Su problema es el hecho de que MyClass1 no conoce la instancia de MyClass3 que provocará el evento, por lo que no puede suscribirse al evento. –

+0

@PaulLassiter - Francesco me ganó. – Maarten

1

Usted puede añadir el evento a la clase de intermediario con el fin de conectar las cosas. Algo como esto:

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

Una cosa es posible que desee tener en cuenta es lo que haces con el "emisor" argumento en la clase de intermediario. Se podría hacer que miclase2 (como en el código anterior) o se puede mantener el remitente original como esto:

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

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

Para los controladores de eventos de la cadena, utilice el Agregar/Quitar sintaxis en miclase2. Desde MyClass1, configure SomeEvent y en MyClass3, resáltelo.

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

Aquí de alguna manera está "engañando" al convertir una variable local en un campo (MyClass3 en MyClass2). Además, no funciona, porque cls3 es nulo cuando te suscribes a SomeEvent of MyClass2. Esto significa que debe instanciar MyClass3 fuera de Method1 de MyClass2, pero no creo que esto sea algo que le guste a OP. –

+0

@FrancescoBaruchelli - gracias por señalar el error. –

1

Si se quiere evitar la solución de devolución de llamada y la cadena de acontecimientos en cada clase, que básicamente tienen 2 soluciones.

El primero consiste en convertir las variables locales de tipo MyClassX en campos, es decir, algo como sugirió Chris Gessler, pero siguiendo completamente este enfoque y eliminando los valores locales.

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

Su otra opción (pero realmente depende de lo que está tratando de hacer, si es factible, y no me gusta de todos modos) es simplemente definir el evento en MyClass3 como estática:

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);  
    } 
} 
Cuestiones relacionadas