Ho un'applicazione WPF abbastanza complessa che (molto simile a VS2013) ha IDocuments
e ITools
ancorata nella shell principale dell'applicazione. Uno di questi Tools
deve essere arrestato in modo sicuro quando la finestra principale viene chiusa per evitare di entrare in uno stato "cattivo". Quindi io uso il metodo public override void CanClose(Action<bool> callback)
di Caliburn Micro per eseguire alcuni aggiornamenti del database, ecc. Il problema che ho è tutto il codice di aggiornamento in questo metodo utilizza MongoDB Driver 2.0 e questa roba è async
. Qualche codice; Al momento sto cercando di eseguireAttendere il completamento dell'attività senza bloccare la filettatura dell'interfaccia utente
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();
}
}
}
Ora, per cominciare non ho avuto il ManualResetEventSlim
e questo sarebbe, ovviamente, tornare alla CanClose
chiamante prima ho aggiornato il mio database sullo sfondo [filo-piscina] thread. Nel tentativo di impedire il ritorno fino a quando ho finito i miei aggiornamenti ho cercato di bloccare il ritorno, ma questo congela il thread dell'interfaccia utente e impedisce che qualcosa accada.
Come posso eseguire il mio codice di pulizia senza tornare al chiamante troppo presto?
Grazie per il vostro tempo.
Nota, non posso ignorare il OnClose
metodo che utilizza la firma asincrono come il codice chiamante non attendere che (non ho alcun controllo su questo).
Non dovrebbero chiamante prendere la decisione di chiudere la finestra in base alla richiamata e non se restituito dal metodo? Penserei che se si esegue il rollback del task e si ritorni immediatamente, la finestra non dovrebbe essere chiusa fino a quando non si effettua una callback (true/false). –
Nah, sfortunatamente no. Se non si imposta la richiamata, Caliburn assume che sia stato 'callback (true)' che "dice" questo componente può essere chiuso. Se inserisco 'callback (false)' ofcourse, l'operazione close viene cancellata del tutto. – MoonKnight
Potrei scrivere la mia classe di comportamento vicino ma penso che dovrei essere in grado di fare ciò che voglio qui senza andare in mare ... – MoonKnight