2011-06-01 35 views
7

Tengo una aplicación Silverlight mvvm que carga la vista principal con 2 controles de usuario cargados en 2 ContentControls, uno con el cuadro de lista que muestra elementos y otro con el botón editar. Cuando hago clic en el botón editar, se cargan 2 nuevos controles de usuario en ContentControls, uno que muestra datos para editar (EditData) y otro que tiene el botón Guardar y Cancelar (EditAction). cuando hago clic en el botón Guardar, se provoca un evento que se define en la clase GlobalEvents.cs separada como:El evento se dispara más y más veces

public event EventHandler OnSaveButtonClicked; 
public void RaiseSaveButtonClicked() 
{ 
    this.OnSaveButtonClicked(this, EventArgs.Empty); 
} 

y suscribirse a él en el otro control de usuario EditData, porque tengo que transferir esos datos editados a través EventArgs personalizados, así que han puesto en el constructor de es modelo de vista:

this.globalEvents.OnSaveButtonClicked += (s, e) => SaveData(); 

y en el Guardar datos:

public void SaveData() 
{ 
    globalEvents.RaiseSaveData(EditedGuy);  
} 

cual plantea otra vísperas nt que carga controles de usuario previos en su contenido de control y muestra datos editados en el cuadro de lista. Eso está bien, pero cada vez que hago clic en editar y luego lo vuelvo a guardar, aumenta el evento dos veces, y de nuevo 3 veces, luego 4 y así sucesivamente. ¿Cómo puedo lograr que se eleve solo UNA vez? Pensé que podría ser debido a que cada vez que haga clic en editar una nueva instancia del control de usuario se carga y no sé, tal vez la suscripción al evento se mantiene, por lo que he intentado pegar

this.globalEvents.OnSaveButtonClicked -= (s, e) => SaveData(); 

a la Desechar() método, pero sin éxito. ¿Cómo puedo hacer que esto funcione?

Respuesta

7

No puede usar lambdas cuando desea cancelar el registro de eventos.

this.globalEvents.OnSaveButtonClicked += (s, e) => SaveData(); 

Esto creará una instancia - llamémosla ejemplo A - Tipo de manejador de sucesos y agregarlo como un manipulador.

this.globalEvents.OnSaveButtonClicked -= (s, e) => SaveData(); 

esto no eliminará ejemplo de un evento, sino crear una nueva instancia - instancia B - y trata de sacarlo de la evento.

Para solucionar este problema, cree un método poco o guardar el método anónimo en un campo:

class ViewModel 
{ 

    private EventHandler _saveButtonClickedHandler; 
    // ... 

    public ViewModel() 
    { 
     _saveButtonClickedHandler = (s, e) => SaveData(); 
     this.globalEvents.OnSaveButtonClicked += _saveButtonClickedHandler; 
     // ... 
    } 

    public void Dispose() 
    { 
     this.globalEvents.OnSaveButtonClicked -= _saveButtonClickedHandler; 
     // ... 
    } 

    // ... 
} 
+0

¡Muchas gracias! No sabía que las lambdas no pueden usarse para anular el registro de eventos. Mi mal, gracias por mostrarme el camino correcto:] –

2
this.globalEvents.OnSaveButtonClicked += (s, e) => SaveData(); 

Esta línea se llama varias veces, así que va a agregar un nuevo controlador de eventos cada vez .

Necesitas o bien mover esa línea a algún lugar en el que sólo se llama una vez o cambiar el controlador de eventos para:

this.globalEvents.OnSaveButtonClicked += SaveData; 

public void SaveData(object sender, EventArgs e) 
{ 
    globalEvents.RaiseSaveData(EditedGuy);  
    this.globalEvents.OnSaveButtonClicked -= SaveData(); 
} 

Así se quita el controlador de eventos después de tratar con ella. Esto supone que el controlador se agregará la próxima vez que entre en el modo de edición.

+0

Gracias, esto era exactamente lo que estaba buscando. –

+0

Una cosa más, solo para aclarar algo, traté de colocar la llamada al evento en un método diferente en lugar del constructor, pero luego en la clase GlobalEvents en esta línea this.OnSaveButtonClicked (this, EventArgs.Empty); obtengo la excepción de refferencia nula. ¿Por qué? –

0

Tendrá que poner en un método adecuado controlador de eventos que llama a SaveData() y registrar/anular el registro de eso. De lo contrario, intenta anular el registro de otro método anónimo "nuevo" en lugar del original que ha registrado, que, como es anónimo, ya no puede acceder.

public void SaveButtonClicked(object sender, EventArgs e) 
{ 
    SaveData(); 
} 

this.globalEvents.OnSaveButtonClicked += SaveButtonClicked; 

this.globalEvents.OnSaveButtonClicked -= SaveButtonClicked; 
2

Se podría definir una variable eventhandler delegado privada en su clase y asignarle en su constructor:

private SaveButtonClickedHandler _handler; 

asignar el manejador en su constructor:

_handler = (s,e) => SaveData(); 
this.globalEvents.OnSaveButtonClicked += _handler; 

Desechar:

this.globalEvents.OnSaveButtonClicked -= _handler; 

"SaveButtonClickedHandler" es un pseudo-código/marcador de posición para cualquiera que sea el nombre del delegado.

Hasanain

+0

Esta respuesta exacta ya se ha dado hace casi 10 minutos ... –

+0

Cierto, no vi tu respuesta cuando comencé a escribir esto ... – Hasanain

Cuestiones relacionadas