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 :

Accès en ecriture a une fenetre Windows à partir d'un thread


Sujet :

C#

  1. #1
    Membre régulier
    Inscrit en
    Février 2010
    Messages
    103
    Détails du profil
    Informations forums :
    Inscription : Février 2010
    Messages : 103
    Points : 70
    Points
    70
    Par défaut Accès en ecriture a une fenetre Windows à partir d'un thread
    Bonjour,
    J'ai plusieurs instance de classe qui sont exécuté dans des threads. Ces classes sont responsable à l'exécution d'un ensemble de traitements et à l'affichage des résultats dans des fenêtres Windows.
    Le problème c'est que l’accès à une fenêtre à partir d'un thread est interdit.

    Qui peux m'aider à trouver la meilleurs solution pour ça?
    Merci

  2. #2
    Membre régulier
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Novembre 2012
    Messages
    50
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Industrie

    Informations forums :
    Inscription : Novembre 2012
    Messages : 50
    Points : 75
    Points
    75
    Par défaut
    interdit ? Qu'a tu comme message d'erreur ? erreur compilation ? exception ? soit plus precis stp et n'hesite pas a mettre un bout de code pour que l'on comprenne bien ton problème.

  3. #3
    Modérateur
    Avatar de DotNetMatt
    Homme Profil pro
    CTO
    Inscrit en
    Février 2010
    Messages
    3 611
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : CTO
    Secteur : Finance

    Informations forums :
    Inscription : Février 2010
    Messages : 3 611
    Points : 9 742
    Points
    9 742
    Billets dans le blog
    3
    Par défaut
    Effectivement il n'est pas possible d'agir sur le main thread (UI) depuis un worker thread. Il existe plusieurs mécaniques, mais pour t'aider il faudrait en savoir plus sur ce que tu utilises :
    - BackgroundWorker ?
    - Tasks ?
    - Threads ?

    Comme l'a dit djchou, il faudrait aussi savoir ce que tu cherches à faire, et un bout de code ne sera pas de trop !

  4. #4
    Membre régulier
    Inscrit en
    Février 2010
    Messages
    103
    Détails du profil
    Informations forums :
    Inscription : Février 2010
    Messages : 103
    Points : 70
    Points
    70
    Par défaut
    Oui vous avez raison, mais désolé je ne peux pas mettre mon code par ce que c'est dans un cadre professionnel.
    Mais voila j'ai fais un exemple qui illustre mon problème.

    J'ai ici une instance d'une classe personne dans je veux afficher ses paramètres dans 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
     
    class Personne
    {
         public string Nom { get; set; }
        public string Prenom { get; set; }
        public int Age { get; set; }
     
        public Personne ()
        {
            Nom = "Mon Nom";
            Prenom = "Mon Prenom";
            Age = 27;
        }
    }
    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
     
    public partial class Form1 : Form
    {
        Personne Moi = new Personne ();
     
        public Form1()
        {
            InitializeComponent();
        }
     
        private void AfficherPersonne()
        {
            TB_Nom.Text = Moi.Nom;
            TB_Prenom.Text = Moi.Prenom;
            TB_Age.Text = Moi.Age.ToString();
        }
     
        private void BT_AfficherPersonne_Click(object sender, EventArgs e)
        {
            Thread ThreadPersonne = new Thread (AfficherPersonne);
            ThreadPersonne.Start();
        }
    }
    Lors de l'exécution de la fonction BT_AfficherPersonne_Click l’exception suivante aura lieu.
    Opération inter-threads non valide : le contrôle 'TB_Nom' a fait l'objet d'un accès à partir d'un thread autre que celui sur lequel il a été créé.

    Dans cette cas je sais que je peux utiliser soit les "delegate" soit les "event" c'est a dire je lance un événement a la fin du ThreadPersonne pour exécuter la fonction AfficherPersonne() mais il me semble que ces deux méthodes sont (tiré par les cheveux) (demande beaucoup de déclarations)
    Je cherche une méthode plus professionnel.

  5. #5
    Membre éclairé
    Avatar de Etanne
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Novembre 2003
    Messages
    469
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Haut Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2003
    Messages : 469
    Points : 855
    Points
    855
    Par défaut
    Ce n'est pas forcement tiré par les cheveux

    Vous pouvez sinon utiliser le BackgroundWorker comme l'a indiqué DotNetMatt. Il utilise aussi un évenement (ProgressChanged).

    Pour ma part mes threads utilisent différents events pour communiquer avec ma couche de présentation.

  6. #6
    Membre régulier
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Novembre 2012
    Messages
    50
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Industrie

    Informations forums :
    Inscription : Novembre 2012
    Messages : 50
    Points : 75
    Points
    75
    Par défaut
    Perso, j'utilise les threads pour gagner en perf sur des traitement assez lourd
    Si tu veux un "truc" plus professionnel, sépare déjà tes couches :
    pour ma part j'utilise soit le MVC ou le MVP selon les appli mais dans tous les cas, dans ma form j'ai uniquement le code dedié aux composants. La création des instrances se fait dans une autre couche presenter/manager et la tu as quelque chose de bcp plus pro.

  7. #7
    Membre régulier
    Inscrit en
    Février 2010
    Messages
    103
    Détails du profil
    Informations forums :
    Inscription : Février 2010
    Messages : 103
    Points : 70
    Points
    70
    Par défaut
    C'est vraiment génial djchou. Merci beaucoup.
    Mais juste je n'arrive pas a comprendre comment tu fais la création des instances dans une autre couche presenter/manager?

    J'ai essayé de déclarer des instances globaux de classes dans un fichier Publisher.cs en éliminant la déclaration de classe Publisher dans ce fichier.

    Voici un exemple d'ont j'ai essayé de déclarer une instance de la classe personne dans le fichier Publisher.cs comme suit (mais ce n'ira pas)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    using System;
    using System.Collections.Generic;
    using System.Text;
     
    namespace WindowsFormsApplication2
    {
        Personne Moi;
    }
    Peux tu me donner un exemple comment tu fais ça ?
    Merci


    Citation Envoyé par djchou Voir le message
    Perso, j'utilise les threads pour gagner en perf sur des traitement assez lourd
    Si tu veux un "truc" plus professionnel, sépare déjà tes couches :
    pour ma part j'utilise soit le MVC ou le MVP selon les appli mais dans tous les cas, dans ma form j'ai uniquement le code dedié aux composants. La création des instrances se fait dans une autre couche presenter/manager et la tu as quelque chose de bcp plus pro.

  8. #8
    Membre régulier
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Novembre 2012
    Messages
    50
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Industrie

    Informations forums :
    Inscription : Novembre 2012
    Messages : 50
    Points : 75
    Points
    75
    Par défaut
    Voici un exemple qui se base sur le pattern MVP, un peu plus complexe a mon sens que le MVC mais meilleur(a mon sens et je précise que ce n'est que mon avis):
    Code de la form :
    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
     
    public partial class Form1 : Form ,IMain
        {
            private readonly FormPresenter _presenter;
     
            public Form1()
            {
                InitializeComponent();
                _presenter = new FormPresenter(this);
            }
     
            private void buttonCreerPeronne_Click(object sender, EventArgs e)
            {
                _presenter.CreerPersonne();
            }
     
            private void buttonAfficherPeronne_Click(object sender, EventArgs e)
            {
                // je demande au presenter d'afficher la premiere personne de la liste
                _presenter.AfficherPersonne(0);
            }
     
            public void AfficherPersonne(string nom)
            {
                //methode qui permet l'affichage d'une personne
                this.textBox1.Text = nom;
            }
        }
    le code du presenter :
    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
     
    public class FormPresenter
        {
            private readonly IMain _view;
            private IList<personne> personnes;
     
            public FormPresenter(IMain view)
            {
                _view = view;
                personnes = new List<personne>();
            }
     
            public void CreerPersonne()
            {
                var pers = new personne
                    {
                        Nom = "De la Vega",
                        prenom = "Don Diego",
                        age = 50
                    };
                personnes.Add(pers);
            }
     
            public void AfficherPersonne(int position)
            {
               //le presenter n'a pas connaissance de la vue, mais
               // connait les methodes de la form grace a l'interface qu'elle             //implemente
                _view.AfficherPersonne(personnes[position].Nom);
            }
        }
    et le code de l'interface necessaire au presenter pour communique avec la form :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
        interface IMain
        {
            void AfficherPersonne(string nom);
        }
    c 'est sur ca rajoute un peu de fichiers mais le code est eclairci, aucune dépendance entre la form et le presenter, gros avantage : tu peux implémenter des tests unitaires

  9. #9
    Expert éminent Avatar de Graffito
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    5 993
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 5 993
    Points : 7 903
    Points
    7 903
    Par défaut
    Je ne suis pas sur que ccette solution puisse convenir à ton problème, mais il est possible de créer une form depuis un thread grace à cette classe :
    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
      public class HmiFormTools 
      {
        //--------------- Create HmiForm -----------------------
        private  static Form                       HmiFormAtCreation        = null ;
        private  static Type                       HmiFormTypeAtCreation    = null ;
        private  static object[]                   HmiFormInitObjects       = null ;
        private  static string                     HmiFormInitMethodName    = null ;
     
        private static void InvokeMethodByName(System.Windows.Forms.Form TheForm,string MethodName,object[] TheObjects)
        {
          System.Reflection.MethodInfo m = TheForm.GetType().GetMethod(MethodName,System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance) ;
          if (m!=null) m.Invoke(TheForm,new object[] { TheObjects }) ;
          else throw new ArgumentException("Internal error : Cannot find method "+MethodName+" for form "+TheForm.GetType().ToString()) ;
        }
     
        public static Form Create_HmiForm(Type FormType,int TimeOutInSeconds,string InitMethodName,object[] InitObjects)
        {// If form is killed by user action, calling process shall set returned object to null
          HmiFormAtCreation      = null           ;
          HmiFormTypeAtCreation  = FormType       ;
          HmiFormInitMethodName  = InitMethodName ;
          HmiFormInitObjects     = InitObjects    ;
          // Create a new thread from which to start the form
          System.Threading.Thread HmiFormThread = new System.Threading.Thread(new System.Threading.ThreadStart(HmiForm_Start));
          HmiFormThread.SetApartmentState(System.Threading.ApartmentState.STA) ;
          HmiFormThread.Start();
          for (int i=0;i<TimeOutInSeconds*4 && HmiFormTypeAtCreation!=null;i++) System.Threading.Thread.Sleep(250) ;
          return HmiFormAtCreation ;
        }
     
        static public void HmiForm_Start()
        { 
          HmiFormAtCreation = (Form)Activator.CreateInstance(HmiFormTypeAtCreation,true) ;
          InvokeMethodByName(HmiFormAtCreation,HmiFormInitMethodName,HmiFormInitObjects) ;
          HmiFormTypeAtCreation=null ; // in order to indicate the end of init
          Application.Run(HmiFormAtCreation);
        }
     
        static public bool HmiForm_Close(Form HmiForm,EventHandler KillTheFormEventHandler)
        { // use that routine, when calling process wants to close the form
          // example : HmiForm_Close(ref HmiTestForm,new EventHandler(HmiTestForm.KillMe)) ;
          //           HmiTestForm = null ; 
          bool Result=true ;
          if (HmiForm!=null) try { HmiForm.Invoke(KillTheFormEventHandler) ; HmiForm.Dispose() ; }
            catch { Result=false ; } ;
          return Result ;
        }
    Exemple d'implémentation
    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
    // Form creation/closure in the Tread 
        HmiTestForm HmiTestFrm = (HmiTestForm)HmiFormTools.Create_HmiForm(typeof(HmiTestForm),5,"InitAsHmiForm",new object[] {"AAA","BBBB"}) ;
        ...
        HmiFormTools.HmiForm_Close(HmiTestFrm,new EventHandler(HmiTestFrm.KillHmiForm)) ; // eventually, to force closure from thread
     
        // Example of a form  
        public partial class HmiTestForm : Form
        {
          public HmiTestForm() { InitializeComponent(); }
     
          public void InitAsHmiForm(object[] InitObjects) 
          {
            string s="" ;
            for (int i=0;i<InitObjects.Length;i++) s=Environment.NewLine+(string)InitObjects[i] ;
            textBox1.Text=s ;
          }
     
          public void KillHmiForm(object o, EventArgs e) { Close(); }
     
        } // HmiTestForm

  10. #10
    Membre expert


    Homme Profil pro
    Développeur informatique
    Inscrit en
    Avril 2006
    Messages
    970
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2006
    Messages : 970
    Points : 3 304
    Points
    3 304
    Par défaut
    Voici un exemple d'utilisation du BackGroundWorker proposé par DotNetMatt que j'ai écris il y a quelques temps. Je pense que cela pourrait t'aider :

    http://dotnet.developpez.com/telecha...ckgroundWorker

  11. #11
    Inactif  

    Homme Profil pro
    Ingénieur test de performance
    Inscrit en
    Décembre 2003
    Messages
    1 986
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur test de performance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Décembre 2003
    Messages : 1 986
    Points : 2 605
    Points
    2 605
    Par défaut
    Bonjour.

    Un lien qui explique la chose :

    http://msdn.microsoft.com/en-us/library/ms171728.aspx

    Le mot clé c'est "InvokeRequired".

    Si tu tentes d'accéder à un "control" depuis un thread, une exception est générée. Il suffit de faire un "Invoke" sur le "control".

  12. #12
    Membre régulier
    Inscrit en
    Février 2010
    Messages
    103
    Détails du profil
    Informations forums :
    Inscription : Février 2010
    Messages : 103
    Points : 70
    Points
    70
    Par défaut
    Merci a tous.
    Toutes vos réponses sont géniales. Merci.

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

Discussions similaires

  1. Réponses: 2
    Dernier message: 03/02/2006, 16h21
  2. [VB.net] Acces aux controles d'une form a partir d'une autre
    Par Fab62_ dans le forum Windows Forms
    Réponses: 3
    Dernier message: 25/01/2006, 12h47
  3. [C#] Comment recharger une fenetre windows
    Par nokta dans le forum Windows Forms
    Réponses: 3
    Dernier message: 29/11/2005, 18h54
  4. Le dessin avec VC dans une fenetre windows
    Par ccensam dans le forum MFC
    Réponses: 3
    Dernier message: 03/11/2005, 23h40
  5. Réponses: 2
    Dernier message: 24/03/2004, 10h22

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