Ich habe eine ziemlich komplexe WPF-Anwendung, die (ähnlich wie VS2013) IDocuments
und ITools
im Hauptgehäuse der Anwendung angedockt hat. Eine dieser Tools
muss sicher heruntergefahren werden, wenn das Hauptfenster geschlossen ist, um zu vermeiden, in einen "schlechten" Zustand zu kommen. Also verwende ich Caliburn Micro public override void CanClose(Action<bool> callback)
Methode, um einige Datenbank-Updates etc. Das Problem, das ich habe, ist der gesamte Update-Code in dieser Methode verwendet MongoDB Driver 2.0 und das Zeug ist async
. Irgendein Code; momentan bin ich versuche,Warten, bis Task abgeschlossen ist, ohne UI-Thread zu blockieren
public override void CanClose(Action<bool> callback)
{
if (BackTestCollection.Any(bt => bt.TestStatus == TestStatus.Running))
{
using (ManualResetEventSlim tareDownCompleted = new ManualResetEventSlim(false))
{
// Update running test.
Task.Run(async() =>
{
StatusMessage = "Stopping running backtest...";
await SaveBackTestEventsAsync(SelectedBackTest);
Log.Trace(String.Format(
"Shutdown requested: saved backtest \"{0}\" with events",
SelectedBackTest.Name));
this.source = new CancellationTokenSource();
this.token = this.source.Token;
var filter = Builders<BsonDocument>.Filter.Eq(
BackTestFields.ID, DocIdSerializer.Write(SelectedBackTest.Id));
var update = Builders<BsonDocument>.Update.Set(BackTestFields.STATUS, TestStatus.Cancelled);
IMongoDatabase database = client.GetDatabase(Constants.DatabaseMappings[Database.Backtests]);
await MongoDataService.UpdateAsync<BsonDocument>(
database, Constants.Backtests, filter, update, token);
Log.Trace(String.Format(
"Shutdown requested: updated backtest \"{0}\" status to \"Cancelled\"",
SelectedBackTest.Name));
}).ContinueWith(ant =>
{
StatusMessage = "Disposing backtest engine...";
if (engine != null)
engine.Dispose();
Log.Trace("Shutdown requested: disposed backtest engine successfully");
callback(true);
tareDownCompleted.Set();
});
tareDownCompleted.Wait();
}
}
}
Jetzt ausführen, um mit zu beginnen ich nicht die ManualResetEventSlim
habe und dies den CanClose
Anrufer offensichtlich zurückkehren würde, bevor ich meine Datenbank auf dem Hintergrund [Thread-Pool] Thread aktualisiert. In einem Versuch, die Rückkehr zu verhindern, bis ich meine Updates beendet habe, habe ich versucht, die Rückkehr zu blockieren, aber das friert den UI-Faden ein und verhindert, dass etwas geschieht.
Wie kann ich meinen Bereinigungscode ausführen, ohne zu früh zum Anrufer zurückzukehren?
Vielen Dank für Ihre Zeit.
Hinweis, ich kann die OnClose
Methode Asynchron-Signatur nicht außer Kraft setzen, wie der aufrufende Code es nicht erwarten würde (ich habe keine Kontrolle über diese).
Sollte der Anrufer nicht die Entscheidung treffen, um das Fenster basierend auf dem Rückruf zu schließen und nicht, ob Sie von der Methode zurück? Ich würde denken, dass, wenn Sie Ihre Aufgabe drehten und sofort zurückkehrten, das Fenster nicht geschlossen werden sollte, bis Sie Rückruf (wahr/falsch) machen. –
Nein, leider nicht. Wenn ich den Callback nicht zurücksetze, nimmt Caliburn an, dass es "Callback (true)" ist, was "sagt", dass diese Komponente geschlossen werden kann. Wenn ich 'callback (false)' natürlich einfüge, wird der Close-Vorgang komplett abgebrochen. – MoonKnight
Ich könnte meine eigene enge Verhaltensklasse schreiben, aber ich denke, ich sollte in der Lage sein, das zu tun, was ich will, ohne über Bord zu gehen ... – MoonKnight