2010-08-28 13 views
6

Ich habe eine ziemlich komplexe Silverlight 4 Out-of-Browser-Anwendung gemacht. Eines meiner Hauptansichtsmodelle fügt dem Application.Current.MainWindow.Closing-Ereignis einen Ereignishandler hinzu. Dies funktioniert gut, wenn die Anwendung zum ersten Mal ausgeführt wird. Es kann den Schließvorgang abbrechen.MainWindow.Closing-Ereignis nicht immer in Silverlight ausgelöst 4 OOB-App

Jedoch manchmal nach dem Ausführen von Operationen wie Anzeigen und Schließen eines ChildWindow, ruft das Closing-Ereignis von MainWindow nicht mehr mein Handler auf.

Im Debugger habe ich eine Uhr zu dem zugrunde liegenden Closing-Event-Delegaten von MainWindow hinzugefügt. Es ist nicht null, bevor das ChildWindow angezeigt wird. Dann manchmal nachdem das ChildWindow geschlossen ist, ist der Delegat null. Dies erklärt, warum mein Handler nicht mehr angerufen wird. Aber warum wird dieser Delegierte nulled? Und warum passiert es nur gelegentlich? Meine Anwendung löst meinen Ereignishandler zu keinem Zeitpunkt auf.

Dies ist der Delegierte Ich beobachte:

System.Windows.Application.Current.MainWindow.m_closingEvent 

Andere Sachen: Ich verwende Caliburn Micro

+0

Klingt wie eine wirklich gute Frage. Die erste Diagnose, die ich verwenden würde, ist eine einfache OOB-App (keine Kalibrierung usw.) zu erstellen, die einfach ChildWindows öffnet und schließt und RootVisuals austauscht, um zu sehen, ob eine einfache Repro erstellt werden kann. – AnthonyWJones

+0

Ok, ich habe das gleiche Problem - sobald ich das ChildWindow nicht öffne/schließe, wird das Closing Event ausgelöst. Manchmal, wenn ich den Debugger angeschlossen habe, wird es auch, aber nicht immer schießen. Ich habe den ApplicationWrapper unten ohne Freude ausprobiert. Irgendwelche Vorschläge?! – Rodney

Antwort

8

Ich hatte genau das gleiche Problem. Wir haben eine große Silverlight-Anwendung mit OOB.

Aus irgendeinem Grund wurde das m_ClosingEvent nach einiger Zeit beendet. Ich war nicht in der Lage, die Ursache für dieses Problem zu finden, aber ich denke, dass es etwas damit zu tun haben könnte, dass wir das Root-Visual oder alle Child-Fenster, die wir zeigen, ändern.

Ich verwende eine Klasse 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.. 
} 

Und die InvokeClosing Methode wurde nie genannt. Aber wenn ich es änderte, um

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

Das m_ClosingEvent ist nicht nulled.

Versuchen Sie also einfach das "ursprüngliche" MainWindow in einem Feld zu speichern und prüfen Sie, ob das Ihr Problem löst.

+0

Ich habe das gerade ausprobiert und es scheint arbeiten! Ich muss noch ein paar weitere Maschinen testen, aber es sieht so aus, als ob du es gelöst hast (und es einfach gelöst hast!) Danke dir so sehr! Ich werde dies als die Antwort markieren und dein Kopfgeld bald vergeben. –

+0

Ich kann das nicht zum Laufen bringen - wo ist die Klasse IApplicationWrapper? Es scheint nicht in Silverlight 4 und Google gibt sehr wenig Informationen darüber? – Rodney

+0

Im Framework gibt es keine IApplicationWrapper-Schnittstelle. Es ist nur eine Schnittstelle, die ich geschrieben habe, um Abhängigkeitsinjektion und Unittests für alles zu ermöglichen, was vom ApplicationWrapper abhängig ist. Aber wenn Sie sich nicht darum kümmern, könnten Sie einfach den Anwendungswrapper kopieren und ihn von Ihrem Hauptfenster aus initialisieren. –

3

Statt Falle Einhaken, warum ein Dienst stattdessen nicht registrieren? Erstellen Sie eine Klasse, die IApplicationService und IApplicationLifetimeAware implementiert. Letzteres gibt Ihnen ein "onexiting" und "onexited" Ereignispaar. Sie platzieren den Dienst in der Anwendung, indem Sie in einem Abschnitt, der in App.xaml aufgerufen wird, darauf zeigen. Ich habe dies für viele Projekte verwendet und hatte nie ein Problem damit, dass die existierenden Methoden nicht aufgerufen wurden.

+0

Danke für die Antwort, aber ich muss das Beenden des Ereignisses (nach Aufforderung des Benutzers) abbrechen. Diese Schnittstelle scheint dafür keine Option zu bieten. –

+0

+1, Nicht weil es eine Antwort auf das Problem in der Nähe ist, sondern weil es nur eine saubere Sache zu tun ist. Es ist auch einfach zu vergessen, App-Lifetime-Objekte, so ist es schön, daran erinnert werden, müssen Sie nicht alles in App Start und Beenden. – AnthonyWJones

+0

+1, war auf der Suche nach einer sauberen Lösung, dass das Problem. Prost. –

1

Ok, nachdem mein Haar und viele Fehlstarts I finally found the answer herausziehen - es scheint ein bekannter Fehler mit der Abschlussveranstaltung, OOB und ChildWindows offen/geschlossen ... ist

Der Trick zu sein, um eine statische Referenz zu speichern zum Hauptfenster:

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

Danke. Genau das habe ich gebraucht. – xanadont

+0

Danke @Rodney, aber ich sehe nicht, wo Sie _mainWindow verwenden? Leider funktionieren die Links zu silverlight.net nicht mehr. – float

+0

Auch App.GetApp.MainWindow; GetApp ist unbekannt? – float