Ich habe eine recht komplexe WPF-Anwendung, die (ähnlich wie VS2013) IDocuments
und ITools
in der Haupt-Shell der Anwendung angedockt hat. Einer dieser Tools
muss sicher heruntergefahren werden, wenn das Hauptfenster geschlossen ist, um nicht in einen "schlechten" Zustand zu geraten. Also verwende ich die public override void CanClose(Action<bool> callback)
-Methode von Caliburn Micro, um einige Datenbankupdates usw. durchzuführen. Das Problem, das ich habe, ist der gesamte Update-Code in dieser Methode, der MongoDB Driver 2.0 verwendet und dieses Zeug ist async
. Irgendein Code; zur Zeit versuche ich
Nun, um mit zu beginnen, hatte ich nicht ManualResetEventSlim
und dies würde offensichtlich zum CanClose
-Aufrufer zurückkehren, bevor ich meine Datenbank im Hintergrund [thread-pool] -Thread aktualisiert habe. In einem Versuch, die Rückkehr zu verhindern, bis ich meine Updates fertig habe, habe ich versucht, die Rückkehr zu blockieren, aber das friert den UI-Thread ein und verhindert, dass etwas passiert.
Wie kann ich meinen Bereinigungscode ausführen, ohne zu früh zum Anrufer zurückzukehren?
Danke für Ihre Zeit.
Beachten Sie, dass ich die Methode OnClose
nicht mit einer asynchronen Signatur überschreiben kann, da der aufrufende Code nicht darauf warten würde (ich habe keine Kontrolle darüber).
Ich glaube nicht, dass Sie viel Wahl haben, als die Rückkehr zu blockieren. Ihre Aktualisierungen sollten dennoch ausgeführt werden, obwohl der Benutzeroberflächen-Thread gesperrt ist. Ich würde kein ManualResetEventSlim verwenden, sondern nur eine einfache wait () und eine einzelne Aufgabe ohne eine Fortsetzung. Der Grund dafür ist standardmäßig Task.Run verhindert, dass der untergeordnete Task (Ihre Fortsetzung) an den übergeordneten Thread angehängt wird und Ihre Fortsetzung möglicherweise keine Zeit hat, bevor das Fenster geschlossen wird, siehe diesen Beitrag .
%Vor%Sie können auch TaskFactory.StartNew mit TaskCreationOptions.AttachedToParent verwenden, wenn Sie wirklich eine Fortsetzung benötigen.
BEARBEITEN: Ich habe meine Antwort mit @Saeb Amini kombiniert, es ist insgesamt ein bisschen ein Hack, aber Sie behalten eine gewisse Reaktion auf die Benutzeroberfläche.
EDIT 2: Hier ist eine Beispieldemonstration der Lösung (getestet mit einem neuen WPF-Projekt):
%Vor% Sie können etwas ähnliches zu WinForms Application.DoEvents
Für WPF wird jedoch ein Flag verwendet, das Ihre Aufgabe auslöst, nicht Wait
ing dafür, aber die UI-Nachrichten werden kontinuierlich in einer Schleife verarbeitet, bis Ihre Aufgabe erledigt ist und setzt die Flagge. z.B. :
Es ist ein bisschen hacky, aber angesichts Ihrer Situation und ohne Kontrolle über den aufrufenden Code könnte es Ihre einzige Option sein, eine responsive UI zu unterhalten, ohne sofort zum Anrufer zurückzukehren.
Ich habe die async / await-Kombination versucht, um diese Art von Problem zu lösen. Zuerst konvertieren wir die Sync void CanClose in async void. Dann ruft die async void-Methode die asynchrone Task-Methode auf, um die Arbeit zu erledigen. Wir müssen dies tun, weil die Gefahr von Async beim Abfangen von Ausnahmen ungültig wird.
%Vor%Meiner Meinung nach hat die Verwendung dieses Ansatzes Vorteile:
Hinweis:
Tags und Links c# asynchronous task blocking semaphore