Opération inter thread sur showdialog

Résolu
mastereur Messages postés 37 Date d'inscription jeudi 17 mai 2007 Statut Membre Dernière intervention 26 décembre 2010 - 8 déc. 2009 à 13:21
cs_coq Messages postés 6349 Date d'inscription samedi 1 juin 2002 Statut Membre 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
A voir également:

10 réponses

cs_coq Messages postés 6349 Date d'inscription samedi 1 juin 2002 Statut Membre Dernière intervention 2 août 2014 101
15 déc. 2009 à 22:56
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
*/
3
mastereur Messages postés 37 Date d'inscription jeudi 17 mai 2007 Statut Membre Dernière intervention 26 décembre 2010
4 janv. 2010 à 03:11
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();
        }
    }
    [...]
}
3
mastereur Messages postés 37 Date d'inscription jeudi 17 mai 2007 Statut Membre Dernière intervention 26 décembre 2010
8 déc. 2009 à 17:09
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
0
cs_coq Messages postés 6349 Date d'inscription samedi 1 juin 2002 Statut Membre Dernière intervention 2 août 2014 101
12 déc. 2009 à 11:16
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
*/
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
mastereur Messages postés 37 Date d'inscription jeudi 17 mai 2007 Statut Membre Dernière intervention 26 décembre 2010
13 déc. 2009 à 21:11
non, il n'est pas encore affiché.

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

 this.ShowDialog(this.owner);
0
cs_coq Messages postés 6349 Date d'inscription samedi 1 juin 2002 Statut Membre Dernière intervention 2 août 2014 101
15 déc. 2009 à 21:32
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
*/
0
mastereur Messages postés 37 Date d'inscription jeudi 17 mai 2007 Statut Membre Dernière intervention 26 décembre 2010
15 déc. 2009 à 21:42
    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
0
mastereur Messages postés 37 Date d'inscription jeudi 17 mai 2007 Statut Membre Dernière intervention 26 décembre 2010
15 déc. 2009 à 21:43
petite erreur;
les codes au dessus sont dans la même classe MemoryBox
0
mastereur Messages postés 37 Date d'inscription jeudi 17 mai 2007 Statut Membre Dernière intervention 26 décembre 2010
16 déc. 2009 à 18:57
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");
[...]
0
cs_coq Messages postés 6349 Date d'inscription samedi 1 juin 2002 Statut Membre Dernière intervention 2 août 2014 101
4 janv. 2010 à 22:12
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
*/
0
Rejoignez-nous