2009-02-17 11 views
5

Resumen de una línea: ¿Cuál es la mejor práctica para desenganchar controladores de eventos creados en el constructor de un UserControl en Silverlight2?Cuándo desenganchar eventos en Silverlight

Antecedentes: Actualmente estoy desarrollando una aplicación de línea de negocio en Silverlight2. Como Silverlight es un complemento de navegador, no existe el concepto de una ventana: todo se hace dentro de UserControls. La forma en que manejo diferentes "formularios" en la aplicación es tener un control de usuario de nivel superior que contiene un Viewbox. Para mostrar diferentes formas, configuro la propiedad Child de Viewbox para diferentes UserControls. Mi aplicación tiene una clase Singleton PageManager que se llama para abrir y cerrar formularios. Los formularios (UserControls) se almacenan en una pila. Al abrir un formulario, se coloca en la parte superior de la pila, al cerrarlo se lo quita de la pila y se muestra el que está debajo.

Intento seguir el patrón Model-View-ViewModel. En cada formulario (derivado de UserControl), tengo un ViewModel que maneja todos los datos para la Vista. ViewModel expone eventos para que se pueda notificar a la UI cuando se hayan completado operaciones tales como cargar y guardar.

En mi formulario, suscribirse al evento en el constructor, después Tengo el modelo de vista

public partial class MyPage : UserControl 
{ 

    public MyViewModel ViewModel{get; set;} 

    // other constructors, which create the viewmodel and call the constructor below. 

    public MyPage(MyViewModel viewModel) 
    { 
     InitializeComponent(); 
     ViewModel = viewModel; 
     this.LayoutRoot.DataContext = this.ViewModel; 

     // subscribe to event so we can do stuff 
     this.ViewModel.LoadCompleted += new MyViewModel.LoadCompletedEventHandler(ViewModel_LoadCompleted); 
    } 

Mi pregunta es: ¿Ahora que me he suscrito a este evento, cuando puedo eliminar el ¿entrenador de animales? ¿Creo un destructor y lo hago allí, o crea una situación de gallina y huevo donde el recolector de basura no destruirá el objeto hasta que todas las referencias (es decir, los controladores de eventos) hayan desaparecido? ¿Creo una interfaz que los formularios deben implementar que especifique una función UnhookEvents a la que se llama cuando el formulario está cerrado por el PageManager?

Editar: Gracias por las respuestas. ¿Qué pasa con la situación en la que ViewModel dura más que el formulario (UserControl)? Parte de mi aplicación permite a los usuarios crear una estructura bastante compleja, pero en el 95% de los casos es mucho más simple. Lo que hice fue crear 2 formularios que usan el mismo modelo de vista. Los usuarios pueden comenzar a completar el formulario simple, luego cambiar al modo avanzado, que crea un nuevo formulario, pasando el ViewModel a él.

En el formulario de configuración sencilla:

private void AdvancedSessionSetupButton_Click(object sender, RoutedEventArgs e) 
    { 
     PageManager.GetPageManager().Close(this); 
     PageManager.GetPageManager().Open(new CreateSessionPage(this.ViewModel), "Create Session"); 
    } 

En la forma de configuración avanzada:

private void BasicSessionSetupButton_Click(object sender, RoutedEventArgs e) 
    { 
     PageManager.GetPageManager().Close(this); 
     PageManager.GetPageManager().Open(new CreateBasicSessionPage(this.ViewModel), "Create Session"); 
    } 

Después PageManager.Close, lo único que hacen referencia a la forma son los eventos dentro del modelo de vista. Supongo que ahí es donde debería desengancharlos.

Respuesta

2

un destructor, más comúnmente conocido por los programadores C# como Finalizadores, no es necesario en este caso. Asumiendo que ViewModel_LoadCompleted es una función miembro, contiene un puntero a "this" que está dando al objeto ViewModel que está completamente contenido por "this". El recolector de basura debería ignorar esto inteligentemente.

En este caso, lo correcto es no perder el tiempo desvincularlos.

En general, debe desvincular un controlador de eventos cuando pase "this" (explícita o implícitamente) a algún objeto que mantenga esa referencia más larga que la duración prevista de "this". Por ejemplo, si configura un controlador en el evento de control principal. Ahora el padre tiene una referencia a usted a través del controlador, así como en su colección de controles de Niños. En este caso, deberías desvincular cuando te retiren del padre.

En caso de duda, implemente IDisposable y desvincular en la llamada a Dispose().

+0

Typo, "descripuctor" –

+0

¿Qué pasa si mi ViewModel dura más que el UserControl? (Editaré la pregunta para mostrar cómo) – geofftnz

+0

Si su modelo dura más tiempo que el control del usuario, tampoco tiene que preocuparse por desvincularlo. El modelo no debe tener una referencia al control. Cuando el control se sale del alcance, será basura recolectada y ya no apuntará al modelo. –

1

Los eventos se desenlazan automáticamente cuando el recolector de basura pasa por su objeto.

Pero se puede desvincular de forma explícita con el "- =" sintaxis en cualquier momento:

this.ViewModel.LoadCompleted -= ViewMode_LoadCompleted; 

Se puede implementar un destructor:

~MyPage 
{ 
    this.ViewModel.LoadCompleted -= ViewMode_LoadCompleted; 
} 
Cuestiones relacionadas