[Résolu][C#] UI & threads dans un bateau

Hello les gens,

Je suis actuellement en train de développer un petit outil pour nos dévs internes en WPF. Technologie que je ne maitrise pas du tout mais que j’ai hâte de décortiquer. Et qui dit WPF, dit Thread (enfin je suppose).
Etant plutôt spécialisé dans le dév d’application web et d’assembly, je ne connais très peu les Threads.

Alors mon problème, c’est que durant un traitement long, et si je n’utilise que le Thread principal qui n’est que celui de l’UI. L’application se fige tant que ce n’est pas finis. Chose vraiment pas top du tout. Donc, hop, je crée un nouveau Thread dédié à ce traitement long. MAIS, malheureusement, elle a besoin d’accéder aux données saisies sur l’interface utilisateur.

Et je ne vois pas comment je peux complètement isoler ce traitement sans dépendre des éléments de l’UI. Donc, j’ai procédé de cette manière en plaçant des :

Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, (MethodInvoker)delegate() { // Mon bout de traitement long accédant à mes contrôles });

Dans le nouveau Thread créé spécialement pour mon traitement long.

Alors, c’est nettement mieux, MAIS, l’ordre d’exécution des Threads est bizarre. Quel est le comportement d’un Thread ? A quel moment il s’exécute par rapport au thread principal ? J’ai des bouts de traitements où mes variables sont null alors que justement je leur ai fournit les valeurs juste avant.

Exemple: Ma méthode DoThing est attaché un Thread.

[code]private void btnDoThings_Click(object sender, RoutedEventArgs e)
{
Thread myThread = new Thread(new ThreadStart(DoThings));
myThread.SetApartmentState(ApartmentState.STA);
myThread.Start();
}

private void DoThings()
{
CrmBoolean isDuplicate = CrmBoolean.Null;
bool isAdvancedFind = false;
int restrictionLevel = -1;

			Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, (MethodInvoker)delegate()
			{
				ApplicationLoading(true);

				isDuplicate = (chkIsDuplicate.IsChecked.Value) ? new CrmBoolean(true) : new CrmBoolean(false);
				isAdvancedFind = chkValidForAdvancedFind.IsChecked.Value;
				restrictionLevel = cmbRestrictionLevel.SelectedIndex;
			});
			
			// Normalement, ma variable isAdvancedFind doit avoir soit true ou false or je n'ai rien.
			crmContext.SetDisplayMaskFlag(item, DisplayMasks.ValidForAdvancedFind, isAdvancedFind);

			switch (restrictionLevel)
			{
								case 0:
									break;
								case 1:
									crmContext.SetRequiredLevelFlag(item, AttributeRequiredLevel.None);
									break;
								case 2:
									crmContext.SetRequiredLevelFlag(item, AttributeRequiredLevel.Recommended);
									break;
								case 3:
									crmContext.SetRequiredLevelFlag(item, AttributeRequiredLevel.Required);
									break;
								default:
									break;
		   }
		   // ....

}[/code]

Par contre, si vous avez un très bon tuto sur les threads et notamment pour la gestion de la barre de progression vu que je l’utilise aussi.

Voilà, voilà.

Dispatcher possède deux méthode : BeginInvoke et Invoke.

  • BeginInvoke est asynchrone : l’appel n’est pas bloquant et n’attend pas que le traitement soit exécuté. C’est ce qu’il se passe dans ton cas. C’est pour ça que les variables restent à leur valeur initiale.
  • Invoke est synchrone : la méthode est bloqué, attend que le traitement soit effectué par le UI Thread. C’est ce qu’il faudrait faire dans ton cas.

Pour le reste, Google “WPF dispatcher best practices”. Tu tomberas sur une bonne page sur MSDN sur le modèle de Threading en WPF. A bien digérer avant de se lancer dans des trucs.

Regarde aussi du côté de Caliburn (plus simple) ou de Prism (assez grosse usine) qui sont des framework WPF qui doivent certainement inclure des exemples de gestion des interactions avec les UI Threads.

Autre chose que j’ai oublié de parler.
Je veux déclencher l’animation d’une progressBar avant de commencer le traitement. Et la stopper à la fin. Problème, l’animation ne s’affiche absolument pas alors que l’affichage d’un message informatif que le traitement est en cours est bien présente. Et dès que je debug, l’animation est bien là. :confused:

Chose étrange, puisque sur un autre traitement, mais moins complexe, la progressBar fonctionne parfaitement.

Une idée ?

Styx31 → hmmm, je vais regarder le coup du Invoke ainsi que ton lien et le framework. Merci.

Edit:
Bon, problème résolu en passant le thread en synchrone.
Cela dit, les threads spa facile. :smiley:
Merci bien.