2010-08-28 9 views
6

He creado una aplicación bastante compleja de Silverlight 4 fuera del navegador. Uno de mis modelos de vistas principales agrega un controlador de eventos al evento Application.Current.MainWindow.Closing. Esto funciona bien cuando la aplicación se ejecuta inicialmente. Puede cancelar la operación de cierre.Evento MainWindow.Closing no siempre se plantea en la aplicación OOB de Silverlight 4

Sin embargo, a veces después de realizar operaciones como mostrar y cerrar un ChildWindow, el evento Closing de MainWindow ya no llama a mi controlador.

En el depurador, agregué un reloj al delegado de evento de cierre subyacente de MainWindow. No es nulo antes de mostrar ChildWindow. Luego a veces después de que ChildWindow está cerrado, el delegado es nulo. Esto explica por qué mi controlador no se llama más. Pero, ¿por qué se anula este delegado? ¿Y por qué solo está sucediendo ocasionalmente? Mi aplicación no desvincula mi controlador de eventos en ningún momento.

Este es el delegado estoy viendo:

System.Windows.Application.Current.MainWindow.m_closingEvent 

Otras cosas: estoy usando Caliburn Micro

+0

Parece una muy buena pregunta. El primer diagnóstico que utilizaría es crear una aplicación OOB simple (sin calibración, etc.) que simplemente abra y cierre ChildWindows y canjee RootVisuals para ver si se puede crear una reproducción simple. – AnthonyWJones

+0

Ok, tengo el mismo problema: tan pronto como no abro/cierro ChildWindow, el evento Closing se dispara. Algunas veces, si tengo el depurador conectado, también se activará pero no siempre. Probé el ApplicationWrapper a continuación sin alegría. ¡¿Alguna sugerencia?! – Rodney

Respuesta

8

Tuve exactamente el mismo problema. Tenemos una gran aplicación Silverlight ejecutando OOB.

Por alguna razón, el m_ClosingEvent fue anulado después de ejecutarse por un tiempo. No he podido encontrar la causa de este problema, pero creo que puede tener algo que ver con que cambiemos las visualizaciones de la raíz o todas las ventanas secundarias que mostramos.

Estoy usando una clase ApplicationWrapper.

public class ApplicationWrapper : IApplicationWrapper 
{ 
    public void Initialize() 
    { 
    HookCloseEvent(true); 
    } 
    private void HookCloseEvent(bool hook) 
    { 
    if (hook && IsRunningOutOfBrowser) 
    { 
     Application.Current.MainWindow.Closing += OnClosing; 
    } 
    else 
    { 
     if (IsRunningOutOfBrowser) 
     { 
     Application.Current.MainWindow.Closing -= OnClosing; 
     } 
    } 
    } 
    private void OnClosing(object sender, ClosingEventArgs e) 
    { 
    InvokeClosing(e); 
    } 

... etc.. 
} 

Y el método InvokeClosing nunca fue llamado. Pero cuando lo cambié a

public class ApplicationWrapper : IApplicationWrapper 
{ 
    private Window _mainWindow; 

    public void Initialize() 
    { 
    if(IsRunningOutOfBrowser) 
    { 
     _mainWindow = Application.Current.MainWindow; 
    } 
    HookCloseEvent(true); 
    } 

    private void HookCloseEvent(bool hook) 
    { 
    if (hook && IsRunningOutOfBrowser) 
    { 
     _mainWindow.Closing += OnClosing; 
    } 
    else 
    { 
     if (IsRunningOutOfBrowser) 
     { 
     _mainWindow.Closing -= OnClosing; 
     } 
    } 
    } 

    private void OnClosing(object sender, ClosingEventArgs e) 
    { 
    InvokeClosing(e); 
    } 

... etc... 
} 

El m_ClosingEvent no se anula.

Por lo tanto, intente simplemente almacenar la ventana principal "inicial" en un campo y verifique si eso resuelve su problema.

+0

Acabo de probar esto y parece ¡trabajar! Necesitaré probar en algunas máquinas más para estar seguro, pero parece que lo has resuelto (¡y lo resolvió simplemente!) ¡Muchas gracias! Voy a marcar esto como la respuesta y otorgaré tu recompensa pronto. –

+0

No puedo hacer que esto funcione, ¿dónde está la clase IApplicationWrapper? No parece estar en Silverlight 4 y Google devuelve muy poca información sobre él. – Rodney

+0

No hay interfaz IApplicationWrapper en el marco. Es solo una interfaz que escribí para habilitar la inyección de dependencias y la prueba unitaria para cualquier cosa que dependa de la aplicación. Pero si no te importa, podrías copiar el contenedor de la aplicación e Inicializarlo desde tu ventana principal, supongo. –

3

En lugar de conectar al evento, por qué no registrar un servicio en su lugar? Cree una clase que implemente IApplicationService y IApplicationLifetimeAware. Este último le da un par de eventos "onexiting" y "onexited". Coloque el servicio en la aplicación señalando en una sección llamada en su App.xaml. Lo he usado para muchos proyectos y nunca tuve un problema con los métodos de salida que no se llaman.

+0

Gracias por la respuesta, pero necesito la capacidad de cancelar el evento que sale (después de preguntar al usuario). Esa interfaz no parece proporcionar una opción para eso. –

+0

+1, No porque sea una respuesta al problema en cuestión, sino porque es simplemente una tarea ordenada. Además, es demasiado fácil olvidar los objetos de la vida útil de la aplicación por lo que es bueno que te lo recuerden, no tienes que hacer todo lo que tienes que hacer en Inicio y Salida de la aplicación. – AnthonyWJones

+0

+1, estado buscando una solución ordenada para ese problema. Aclamaciones. –

1

Ok, después de retirarse el pelo y muchas salidas en falso I finally found the answer - Parece que es un problema conocido con el acto de clausura, fuera de banda y ChildWindows abiertas/cierra ...

El truco consiste en almacenar una referencia estática a la ventana principal:

public MainPage() 
{ 
    InitializeComponent(); 
    Loaded += MainPage_Loaded; 
} 

private void MainPage_Loaded(object sender, System.Windows.RoutedEventArgs e) 
{ 
    //you have to store this to work around the bug 
    //http://forums.silverlight.net/forums/p/185664/424174.aspx 
    _mainWindow = App.GetApp.MainWindow; 

    App.GetApp.MainWindow.Closing += (s, e1) => 
    { 
     if (UIUtilities.ShowMessage("Would you like to exit AMT Mobile?", "Exit Application", MessageBoxButton.OKCancel) != MessageBoxResult.OK) 
     { 
      e1.Cancel = true; 
     } 
    }; 
} 
+0

Gracias. Esto es precisamente lo que necesitaba. – xanadont

+0

Gracias @Rodney pero no veo dónde usa _mainWindow? Lamentablemente, los enlaces a silverlight.net ya no funcionan. – float

+0

También App.GetApp.MainWindow; GetApp es desconocido? – float

Cuestiones relacionadas