Bonjour bonjour!
Je me suis pris la tête là-dessus toute la journée, j'admets n'avoir jamais trop touché au multithreading, mais quand même je suis sur les fesses...
Mise en situation:
J'ai donc une Form qui effectue des opérations "lourdes" (connexion, chargement de données, etc). Je fais faire ces opérations par un thread créé sur le tas, et j'affiche un petit gif animé pendant ce temps-là. Sauf que j'ai à un moment donné deux appels d'affilée à ma fonction "fais une opération en fond", et comme je rend le gif (in)visible de façon thread safe asynchrone, il semble que ça ne suive pas et que mon gif reste invisible...
Mais comme des sources parlent mieux que des mots:
-Les fonctions générales
-L'utilisation:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 // Permet d'effectuer une modification thread-safe sur un contrôle protected void addControlWork(Control c, Action a) { if (c.InvokeRequired) c.BeginInvoke(new MethodInvoker(a)); else a(); } //Lance une tâche de fond, affiche le logo chargement, désactive les autres contrôles protected void doWorkInBackground(MethodInvoker ) { addControlWork(loadingPicture, delegate() { loadingPicture.Visible = true; }); addControlWork(mainPanel, delegate() { mainPanel.Enabled = false; }); f.BeginInvoke(new AsyncCallback(endWorkInBackground), null); } //A la fin d'une tâche de fond, efface le logo chargement, active les autres contrôles protected void endWorkInBackground(IAsyncResult result) { if (this.Disposing) return; addControlWork(loadingPicture, delegate() { loadingPicture.Visible = false; }); addControlWork(mainPanel, delegate() { mainPanel.Enabled = true; }); }
Dans l'exemple ci-dessus, on peut voir que lorsque uneListBox_SelectedIndexChanged est appelé, uneComboBox_SelectedIndexChanged est appelé immédiatement après. Et c'est là que le bât blesse, mon pov' piti logo reste invisible, seul et abandonné dans les méandres de la mémoire de ma machine.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 private void uneListBox_SelectedIndexChanged(object sender, EventArgs e) { doWorkInBackground((MethodInvoker)(() => { object[] source = LongueOperation();; addControlWork(uneComboBox, delegate() { // Changing DataSource fires comboBox.SelectedIndexChanged uneComboBox.DataSource = source; }); })); } private void uneComboBox_SelectedIndexChanged(object s, EventArgs e) { doWorkInBackground((MethodInvoker)(() => { // Le code est pas intéressant ici object[] range = uneOperationLourde(); object[] source = uneAutreOperationLourde(); addControlWork(uneListBox, delegate() { uneListBox.Items.AddRange(range); }); addControlWork(uneComboBox, delegate() { uneComboBox.DataSource = source; }); })); }
Je souhaite donc savoir si quelqu'un a une idée de ce qui cloche, de comment améliorer ça, ou tout simplement si quelqu'un peut me donner une meilleure marche à suivre (j'ai entendu parler des await en 4.5?)
Merci bien!
Edit: Evidemment j'ai des solutions pansements, du genre créer deux fonctions startLoading et stopLoading dans lesquelles je m'occupe de la visibilité du logo et de l'activation du panel, mais c'est pas forcément très intuitif.
Edit: Pour résumer, ma fonction de démarrage de tâche de fond qui rend visible le gif de chargement est à un moment appelée avant qu'une autre tâche de fond ne soit terminée. Donc cette dernière se termine juste après le démarrage de la suivante, rendant mon gif invisible pendant le traitement de celle-ci. Il y a un moyen de "queue" les tâches de fond?
Partager