Avec le code ci-dessous, les mises à jour finales de l'interface utilisateur effectuées dans la version finale de l'opération Continueront jamais eu lieu. Je pense que c'est à cause de l'attente() que j'ai à la fin.La séquence du flux de travail de tâche est erronée
La raison pour laquelle je fais cela est parce que sans l'attente, la méthode retournera le IDataProvider avant que son fini soit construit en arrière-plan.
Quelqu'un peut-il m'aider à faire les choses correctement?
Cheers,
Berryl
private IDataProvider _buildSQLiteProvider()
{
IDataProvider resultingDataProvider = null;
ISession session = null;
var watch = Stopwatch.StartNew();
var uiContext = TaskScheduler.FromCurrentSynchronizationContext();
// get the data
var buildProvider = Task.Factory
.StartNew(
() =>
{
// code to build it
});
// show some progress if we haven't finished
buildProvider.ContinueWith(
taskResult =>
{
// show we are making progress;
},
CancellationToken.None, TaskContinuationOptions.None, uiContext);
// we have data: reflect completed status in ui
buildProvider.ContinueWith(
dataProvider =>
{
// show we are finished;
},
CancellationToken.None, TaskContinuationOptions.OnlyOnRanToCompletion, uiContext);
try {
buildProvider.Wait();
}
catch (AggregateException ae)
{
foreach (var e in ae.InnerExceptions)
Console.WriteLine(e.Message);
}
Console.WriteLine("Exception handled. Let's move on.");
CurrentSessionContext.Bind(session);
return resultingDataProvider;
}
====
juste pour être clair
Je ne parviens pas à parler au fil ui. Le premier continue avec les mises à jour l'interface utilisateur juste très bien. Le problème que j'ai est le calendrier de la dernière mise à jour de l'interface utilisateur et le retour du fournisseur de données. J'ai commenté une partie du code pour réduire le niveau de bruit dans ce message et me concentrer sur le séquençage des tâches.
====
ok, le code de travail
private void _showSQLiteProjecPicker()
{
var watch = Stopwatch.StartNew();
var uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
ISession session = null;
// get the data
var buildProvider = Task.Factory.StartNew(
() =>
{
var setProgress = Task.Factory.StartNew(
() =>
{
IsBusy = true;
Status = string.Format("Fetching data...");
},
CancellationToken.None, TaskCreationOptions.None, uiScheduler);
var provider = new SQLiteDataProvider();
session = SQLiteDataProvider.Session;
return provider;
});
buildProvider.ContinueWith(
buildTask =>
{
if(buildTask.Exception != null) {
Console.WriteLine(buildTask.Exception);
}
else {
Check.RequireNotNull(buildTask.Result);
Check.RequireNotNull(session);
_updateUiTaskIsComplete(watch);
CurrentSessionContext.Bind(session);
var provider = buildTask.Result;
var dao = provider.GetActivitySubjectDao();
var vm = new ProjectPickerViewModel(dao);
_showPicker(vm);
}
},
CancellationToken.None, TaskContinuationOptions.OnlyOnRanToCompletion, uiScheduler);
}
BGW apporte son propre ensemble de problèmes mais je suis d'accord que ce serait bien pour ce scénario. Je soupçonne que le TPL sera plus facile et plus flexible une fois que je l'aurai compris, et cette question concerne l'utilisation de la TPL, pas la manière de rendre compte des progrès en général. Plus important encore, si vous regardez le code, je capture le contexte de l'interface utilisateur sans être dépendant de WPF (une bonne chose), et le premier ContinueWith * fait "mettre à jour le ui. Cheers – Berryl
@Statis. Oui, l'attente à la fin était un perdant, tout comme le premier ContinueWith à mettre à jour la progression.Le dernier ContinueWith était conceptuellement correct, mais au lieu du premier ContinueWith, il doit être une nouvelle tâche (comme you & Nicholas suggéré) MAIS il doit être imbriqué dans la tâche d'origine, ET il doit avoir le thread UI.En plus de vouloir apprendre le TPL et normaliser mon approche de la programmation asynchrone, je vais éventuellement vouloir greffer d'autres tâches ici sera douloureux avec la BGW Merci pour votre aide. – Berryl