IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C# Discussion :

Thread et BackgroundWorker [Débutant]


Sujet :

C#

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Homme Profil pro
    Inscrit en
    Octobre 2013
    Messages
    143
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Octobre 2013
    Messages : 143
    Par défaut Thread et BackgroundWorker
    Bonjour,

    Je sais qu'il s'agit d'un sujet récurent et j'ai pu voir plusieurs post à ce sujet ici et ailleurs (stackoverflow) mais je reste quand même bloqué.

    Dans mon application (Winform) j'ai un bouton refresh qui permet de mettre à jour les données de mon Datagridview depuis ma base de données. Pour cela, j'ai voulu afficher une seconde form avec une progressbar qui se met en superposition de la form principale.
    Pour mettre en place cela j'ai vu sur des forums que je pouvais utiliser un BackgroundWorker pour gérer le traitement de mise à jour et la progression de ma progressbar dans ma second form.
    Après avoir suivi des exemples, le DoWork s'arrêtait après la première instruction de ma fonction RefreshData(). J'ai vite compris que je recevais une exception mais qui ne s'affichait pas. Grâce à internet j'ai pu régler ce soucis et afficher l'erreur.

    Cependant, une fois l'exception bien visible j'ai pu comprendre que j'avais un problème de Thread.
    "Error : System.InvalidOperationException: Opération inter-threads non valide : le contrôle 'refresh_bnt' a fait l'objet d'un accès à partir d'un thread autre que celui sur lequel il a été créé...."

    De ce que j'ai pu comprendre en cherchant sur le net, il s'agit d'un soucis entre le thread principale de l'UI et celui du BackroundWorker. J'avoue que je suis pas vraiment familier avec la notion de Thread (et je devrais peut-être). J'ai cherché comment je pouvais régler ce problème et c'est là que je bloque.
    Tout ce que j'ai vu, proposent des solutions différentes (utiliser des Invoke, ajouter en paramètre le sender du DoWork dans la fonction etc...).

    C'est pour ça que je me suis décidé à demander de l'aide concernant mon cas pour mieux comprendre. Je vous mets ci-dessous la structure de mon code et vous remercie par avance pour vos retours

    NB : mon backroundworker se trouve dans la Form1 (principale) avec la propriété "WorkerReportsProgress" à true

    Form1
    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
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
     
    private FormBackgroundWorker frmPgBar = new FormBackgroundWorker(); // Form2
    private bool DoWork = false;
     
    private void refresh_btn_Click(object sender, EventArgs e)
    {
    	DoWork = true;
     
    	backgroundWorker1.RunWorkerAsync();
     
    	frmPgBar.ShowDialog();
    }
     
    private void RefreshData()
    {
    	// Traitement :
    	// Mise à jour de la BDD
    	// Actualisation du DatagridView
    	// Appel dans différentes partie du code de :
    	// backgroundWorker1.ReportProgress(nombre); // nombre : avancement que je donne au fur et à mesure
     
    	DoWork = false;
    }
     
    private void backgroundWorker1_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
    {
    	RefreshData();
    }
     
    private void backgroundWorker1_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
    {
    	// update the ProgressBar in frmPgBar
    	frmPgBar.SetProgressBarValue(e.ProgressPercentage);
    }
     
    private void backgroundWorker1_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
    {
    	if (e.Error != null)
    	{
    		// You have an exception, which you can examine through the e.Error property.
    		MessageBox.Show("Error : " + e.Error.ToString());
    	}
    	else
    	{
    		// No exception in DoWork.
    		if (!DoWork)
    		{
    			frmPgBar.Close();
    			backgroundWorker1.ReportProgress(0);
    		}
    	}
    }
    Form2
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    public void SetProgressBarValue(int pbValue)
    {
        progressBar1.Value = pbValue;
        this.pourcentage_lb.Text = pbValue.ToString() + "%";
    }

  2. #2
    Membre confirmé
    Homme Profil pro
    Inscrit en
    Octobre 2013
    Messages
    143
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Octobre 2013
    Messages : 143
    Par défaut
    C'est bon, j'ai pu régler mon problème.

    Je post ma solution si jamais ça peut aider

    En gros dans ma fonction principale j'appelais d'autres fonctions qui faisaient du traitement sur l'interface de la Form1. Du coup, j'ai créé un delegate pour chaque fonctions qui touchent à l'UI et au lieu d'appeler directement ces fonctions je fais un Invoke.

    Exemple :

    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
     
    private delegate void EnabledControl_CB(bool value);
     
    private void EnabledControl(bool value)
    {
                this.refresh_btn.Enabled            = value;
                this.date_dtp.Enabled                = value;
                this.layoutFilter_tlp.Enabled       = value;
    }
     
    private void RefreshData()
    {
          this.Invoke(new EnabledControl_CB(EnabledControl ), new object[] { false });
     
          // Reste du code...
    }

  3. #3
    Membre Expert
    Homme Profil pro
    edi
    Inscrit en
    Juin 2007
    Messages
    941
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : edi

    Informations forums :
    Inscription : Juin 2007
    Messages : 941
    Par défaut
    Ce n'est pas comme ça qu'il faut faire avec le BackgroundWorker. Tu attaches ta requête au DoWork et celle-ci sera exécutée sur un Thread en tâche de fond. Mais tu dispose aussi des événements ProgressChanged et RunWorkerCompleted ; une méthode attachée à l'un de ces événements sera exécutée sur le Thread du BackgroundWorker, c.à.d dans ton cas au Thread de l'UI. ProgessChanged sert à envoyer des notifications en cours de traitement (mettre WorkerSupportsCancellation à true auparavant) par un appel à ReportProgress() dans la méthode du DoWork ; RunWorkerCompleted est appelée à la fin du traitement, qu'il ait été mené au bout, ai été annulé ou ait échoucé (levée d'une Exception). C'est le backgroundWrker qui s'occupe de gérer la synchronisation des Thread de façon transparent pour l'utilisateur afin justement d'éviter des Invoke().

  4. #4
    Membre confirmé
    Homme Profil pro
    Inscrit en
    Octobre 2013
    Messages
    143
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Octobre 2013
    Messages : 143
    Par défaut
    Bonjour,

    Merci pour ton retour

    Que veux-tu dire par attacher ma requête au DoWork ?

  5. #5
    Membre Expert
    Homme Profil pro
    edi
    Inscrit en
    Juin 2007
    Messages
    941
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : edi

    Informations forums :
    Inscription : Juin 2007
    Messages : 941
    Par défaut
    Ce que tu as déjà fait : créer une méhode pour exécuter le travail en tâche de fond et l'ajouter à l'événement DoWork de ton BackgroundWorker.

  6. #6
    Membre confirmé
    Homme Profil pro
    Inscrit en
    Octobre 2013
    Messages
    143
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Octobre 2013
    Messages : 143
    Par défaut
    Justement, en mettant ma fonction RefreshData() dans le DoWork() sans les Invoke() dans le RefreshData() pour les parties qui touche l'UI ça ne marche pas.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 11
    Dernier message: 21/09/2015, 19h31
  2. Thread ou BackGroundWorker
    Par pradier4 dans le forum VB.NET
    Réponses: 3
    Dernier message: 26/08/2012, 14h42
  3. Executer le traitement dans un thread ou BackgroundWorker
    Par skunkies dans le forum Windows Forms
    Réponses: 13
    Dernier message: 28/05/2009, 23h41
  4. Réponses: 4
    Dernier message: 15/06/2007, 10h41
  5. [WinForms]BackgroundWorker et threads
    Par b4u dans le forum Général Dotnet
    Réponses: 2
    Dernier message: 13/12/2006, 18h55

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo