Annulation des threads de travail dans les winforms
-
06-07-2019 - |
Question
J'ai deux listes de sélection, une maîtresse et l'autre enfant. Lorsque l'index change sur le gabarit principal, la liste déroulante enfant est correctement remplie avec les enregistrements associés au gabarit. Mon problème survient lorsqu'un maître met beaucoup de temps à récupérer tous les enregistrements et, avant de le faire, un utilisateur clique sur un autre maître qui prend moins de temps à remplir. En fin de compte, le maître qui prenait plus de temps remplit la zone de liste des enfants, même si l'utilisateur n'en fait plus partie.
J'utilise les threads BackgroundWorker pour le remplissage.
bw_LoadAll.DoWork += new DoWorkEventHandler(bg_LoadAllWork);
bw_LoadAll.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bg_LoadAllWorkCompleted);
bw_LoadAll.WorkerSupportsCancellation = true;
Je me suis abonné à l'événement SelectedIndexChanged pour le maître et je règle l'équivalent annulé sur true:
bw_LoadAll.CancelAsync();
Voici le code de la méthode DoWork:
List<object> s = Repository.Instance().LoadAll();
if (!bw_LoadAll.CancellationPending) {
e.Result = s;
} else {
e.Cancel = true;
}
Mais pour une raison quelconque, le code du travailleur terminé continue à être appelé. Voici le code rempli par le travailleur:
if (!e.Cancelled) {
ddl.DataSource = e.Result;
ddl.DisplayMember = "QuickName";
ddl.ValueMember = "ID";
}
Y a-t-il autre chose que je dois faire pour annuler le retour de ce fil?
La solution
Votre méthode, bg_LoadAllWork, doit être définie comme suit:
void bg_LoadAllWork(object sender, DoWorkEventArgs e)
{
// Do your work here...
}
À l'intérieur de bg_LoadAllWork, vous devez vérifier e.CancellationPending
et, le cas échéant, définissez e.Cancel = true;
Cette dernière partie est importante - si vous ne définissez jamais e.Cancel, votre " e.Cancelled " ne sera jamais égal à vrai. L’appel de CancelAsync n’annule pas réellement quoi que ce soit, c’est plus comme "Demander que le travail en arrière-plan s’annule lui-même". - vous devez mettre en place la logique permettant l'annulation.
Autres conseils
De CodeProject dans votre fonction do_work, vous devez vérifier Annulation en cours sur le thread de travail définit ensuite la variable DoWorkEventArgs.Cancel sur true.
Cela fait longtemps que je n'ai pas utilisé BackgroundWorker, mais si je me souviens bien, lorsque vous appelez bw_LoadAll.CancelAsync
, il n'y a pas d'avortement réel de votre méthode LoadAllWork
. sauf si LoadAllWork vérifie bw_LoadAll.CancelationPending
.
Confirmé par http://msdn.microsoft .com / fr-us / library / system.componentmodel.backgroundworker.cancelasync.aspx : "CancelAsync envoie une demande pour mettre fin à l'opération en arrière-plan en attente et définit la propriété CancellationPending sur true.
Lorsque vous appelez CancelAsync, votre méthode de travail a l'occasion d'arrêter son exécution et de quitter. Le code de l'opérateur doit vérifier périodiquement la propriété CancellationPending pour voir si elle a été définie sur true. "
Ainsi, dans votre gestionnaire d'événements SelectedIndexChanged, lorsque vous appelez bw_LoadAll.CancelAsync ()
, la définition de bw_LoadAll.CancelationPending
est définie sur true, mais n'annule pas réellement le Méthode LoadAllWork
. Le chargeur lent va encore finir.