Opération inter thread sur showdialog [Résolu]

Messages postés
37
Date d'inscription
jeudi 17 mai 2007
Dernière intervention
26 décembre 2010
- - Dernière réponse : cs_coq
Messages postés
6366
Date d'inscription
samedi 1 juin 2002
Dernière intervention
2 août 2014
- 4 janv. 2010 à 22:12
bonjour,

petite explication avant tout, j'ai une Form qui crée un thread, et lors d'une action, ce thread ouvre une autre Form (du style MessageBox perso). Je souhaite que celle ci soir en showdialog sur ma Form principale, mais j'ai une erreur "Opération inter thread"

[Form principale] ---------------> Thread -------------> [MessageBox perso]


Je passe en paramètre au thread mon owner
c_Thread = new C_Thread(this);

dans le thread afin de créer la massageBox perso:
public C_Thread(IWin32Window owner)
{
    this.owner = owner;
}

Puis dans une fonction du thread
memoryBox = new MemoryBox(owner);


Et enfin dans ma messagebox perso j'ai :
public MemoryBox(IWin32Window owner)
{
     InitializeComponent();
     this.owner = owner;
}

et dans ma fonction d'affichage:
base.ShowDialog(owner);

c'est ici que j'ai mon problème. j'ai essayé avec un invoke mais sans succé

Pouvez vous m'aider?
et merci d'avance
Afficher la suite 

Votre réponse

10 réponses

Meilleure réponse
Messages postés
6366
Date d'inscription
samedi 1 juin 2002
Dernière intervention
2 août 2014
3
Merci
Ok, tu fais l'invoke sur le contrôle lui même qui n'est pas encore initialisé du coup.

Ce code ne sert à rien (s'il avait pu fonctionner) : changer le contexte du thread pour l'affectation de ce champ n'aurait aucun impact :
            this.Invoke(new MethodInvoker(delegate
            {
                this.owner = owner;
            }));


C'est sur les interactions avec les éléments graphiques (les appels aux méthodes qui utilisent les API Win32 qui sont en dessous de WinForm) qu'il faut faire le changement de contexte, et il faut pour cela effectuer l'invoke sur un contrôle ayant été créé par le thread d'UI.
Le mieux serait probablement de gérer le changement de contexte dans le thread pour que toute l'exécution du code de MemoryBox se fasse dedans, mais si tu tiens à conserver l'architecture actuelle il faudrait changer le type de owner pour qu'il s'agisse de Control au minimum ou passer en paramètre supplémentaire le SynchronizationContext associé au thread d'UI afin d'utiliser sa méthode post au moment de l'affichage (au lieu de Control.Invoke).

Exemple rapide avec Control.Invoke :
    public partial class MemoryBox : Form
    {
        // Internal values
        MemoryBoxResult lastResult = MemoryBoxResult.Cancel;
        MemoryBoxResult result = MemoryBoxResult.Cancel;
        Control owner;

        // Enums
        // Results


        /// <summary>
        /// The default constructor for MemoryBox.
        /// </summary>
        public MemoryBox(Control owner)
        {
            InitializeComponent();
            this.owner = owner;
        }

        /// <summary>
        /// Call this function instead of ShowDialog, to check for remembered
        /// result.
        /// </summary>
        /// <returns></returns>
        public MemoryBoxResult ShowMemoryDialog()
        {
            result = MemoryBoxResult.Cancel;
            if (lastResult == MemoryBoxResult.NoToAll)
            {
                result = MemoryBoxResult.No;
            }
            else if (lastResult == MemoryBoxResult.YesToAll)
            {
                result = MemoryBoxResult.Yes;
            }
            else
            {
                this.PostInParentContext(delegate
                    {
                        this.ShowInTaskbar = false;
                        this.ShowDialog(this.owner);
                    });
            }
            return result;
        }

        public String LabelText { get; set; }


        public MemoryBoxResult ShowMemoryDialog(String label, string title)
        {
            this.PostInParentContext(delegate
                    {
                        this.Text = title;
                    });
            LabelText = label;
            return ShowMemoryDialog();
        }

        private void PostInParentContext(MethodInvoker del)
        {
            if (this.owner.InvokeRequired)
            {
                this.owner.Invoke(del);
            }
            else
            {
                del.Invoke();
            }
        }
    }



/*
coq
MVP Visual C#
CoqBlog
*/

Dire « Merci » 3

Quelques mots de remerciements seront grandement appréciés. Ajouter un commentaire

Codes Sources a aidé 105 internautes ce mois-ci

Commenter la réponse de cs_coq
Messages postés
37
Date d'inscription
jeudi 17 mai 2007
Dernière intervention
26 décembre 2010
3
Merci
Voici mon code pour ceux que ça interesse :

Dans la Form principale:
public partial class Crtr : Form
{
    private Thread threadTraitement;
    [...]
    public Crtr()
    {
        [...]
        c_Thread = new C_Thread(this);
        [...]
    }
    [...]
}


Dans le thread:
public class C_Thread
{
    [...]
    private MemoryBox memoryBox;
    private Control owner;
    [...]

    public C_Thread(Control owner)
    {
        this.owner = owner;
    }
    [...]
    public void ma fonction()
    {
        [...]
        memoryBox = new MemoryBox(owner);
        [...]
    }
    [...]
}


Dans la MemoryBox:
public partial class MemoryBox : Form
{
    [...]
    private Control owner;
    [...]
    public MemoryBox(Control owner)
    {
        InitializeComponent();
        this.owner = owner;
    }
    [...]
    public MemoryBoxResult ShowMemoryDialog()
    {
        [...]
        this.PostInParentContext(delegate
        {
            this.ShowInTaskbar = false;
            this.ShowDialog(this.owner);
        });
        [...]
    }
    [...]
    private void PostInParentContext(MethodInvoker del)
    {
        if (this.owner.InvokeRequired)
        {
            this.owner.Invoke(del);
        }
        else
        {
            del.Invoke();
        }
    }
    [...]
}

Dire « Merci » 3

Quelques mots de remerciements seront grandement appréciés. Ajouter un commentaire

Codes Sources a aidé 105 internautes ce mois-ci

Commenter la réponse de mastereur
Messages postés
37
Date d'inscription
jeudi 17 mai 2007
Dernière intervention
26 décembre 2010
0
Merci
je pense avoir avancer, j'ai mis le showdialog dans un invoke par contre j'ai une erreur :
Impossible d'appeler Invoke ou BeginInvoke sur un contrôle tant que le handle de fenêtre n'a pas été créé.

Je ne saisie pas bien le probleme ave le handle
Commenter la réponse de mastereur
Messages postés
6366
Date d'inscription
samedi 1 juin 2002
Dernière intervention
2 août 2014
0
Merci
Bonjour,

Au moment de l'appel à Control.Invoke sur le contrôle créé dans le thread d'UI, celui ci est affiché ?


/*
coq
MVP Visual C#
CoqBlog
*/
Commenter la réponse de cs_coq
Messages postés
37
Date d'inscription
jeudi 17 mai 2007
Dernière intervention
26 décembre 2010
0
Merci
non, il n'est pas encore affiché.

c'est dans mon showdialog ou je passerai mon paramètre owner

 this.ShowDialog(this.owner);
Commenter la réponse de mastereur
Messages postés
6366
Date d'inscription
samedi 1 juin 2002
Dernière intervention
2 août 2014
0
Merci
Heu, j'ai du mal à voir l'architecture du truc.
Tu aurais un exemple simple qui reproduit le problème ?

/*
coq
MVP Visual C#
CoqBlog
*/
Commenter la réponse de cs_coq
Messages postés
37
Date d'inscription
jeudi 17 mai 2007
Dernière intervention
26 décembre 2010
0
Merci
    public partial class MemoryBox : Form
    {
        // Internal values
        MemoryBoxResult lastResult = MemoryBoxResult.Cancel;
        MemoryBoxResult result = MemoryBoxResult.Cancel;
        IWin32Window owner;
        
        // Enums
        // Results

        /// <summary>
        /// The default constructor for MemoryBox.
        /// </summary>
        public MemoryBox(IWin32Window owner)
        {
            InitializeComponent();
            this.Invoke(new MethodInvoker(delegate
            {
                this.owner = owner;
            }));
        }


et l'appel pour l'affichage
#region Public Methods
        /// <summary>
        /// Call this function instead of ShowDialog, to check for remembered
        /// result.
        /// </summary>
        /// <returns></returns>
        public MemoryBoxResult ShowMemoryDialog()
        {
            result = MemoryBoxResult.Cancel;
            if (lastResult == MemoryBoxResult.NoToAll)
            {
                result = MemoryBoxResult.No;
            }
            else if (lastResult == MemoryBoxResult.YesToAll)
            {
                result = MemoryBoxResult.Yes;
            }
            else
            {
                this.ShowInTaskbar = false;
                this.ShowDialog(this.owner);

            }
            return result;
        }

        public MemoryBoxResult ShowMemoryDialog(String label, string title)
        {
            this.Text = title;
            LabelText = label;
            return ShowMemoryDialog();
        }
        #endregion
Commenter la réponse de mastereur
Messages postés
37
Date d'inscription
jeudi 17 mai 2007
Dernière intervention
26 décembre 2010
0
Merci
petite erreur;
les codes au dessus sont dans la même classe MemoryBox
Commenter la réponse de mastereur
Messages postés
37
Date d'inscription
jeudi 17 mai 2007
Dernière intervention
26 décembre 2010
0
Merci
j'essaye de comprendre ta solution.
par contre je ne voit pas comment passer alors mes paramètres dans le thread puis dans la memoryBox...
Pour rappel :
dans la form:
private C_Thread c_Thread;
private Thread threadTraitement;
[...]
c_Thread = new C_Thread(this);
[...]
this.threadTraitement = new Thread(new ThreadStart(this.c_Thread.lancementTraitement));
this.threadTraitement.Start();

dans mon thread :

private MemoryBox memoryBox;
private IWin32Window owner;
[...]
public C_Thread(IWin32Window owner)
{
     this.owner = owner;
}
[...]
memoryBox = new MemoryBox(owner);
[...]
MemoryBoxResult result memoryBox.ShowMemoryDialog("le fichier " + nomFichier + " éxiste déjà!> écraser? ", "Ecrasement");
[...]
Commenter la réponse de mastereur
Messages postés
6366
Date d'inscription
samedi 1 juin 2002
Dernière intervention
2 août 2014
0
Merci
Ha tiens j'ai dû zapper un mail...

Merci d'avoir donné le retour final, ça fait plaisir de voir ce genre de suivi jusqu'au bout :-)


/*
coq
MVP Visual C#
CoqBlog
*/
Commenter la réponse de cs_coq

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.