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 :

WPF, Threads et InvalidOperationException


Sujet :

C#

  1. #1
    Membre régulier
    Profil pro
    Inscrit en
    Octobre 2005
    Messages
    222
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Octobre 2005
    Messages : 222
    Points : 110
    Points
    110
    Par défaut WPF, Threads et InvalidOperationException
    Bonjour,

    J'ai une application multithread avec une interface en WPF. L'interface est géré par ses propres threads, le déroulement de l'application dans d'autres threads.

    En utilisant Dispatcher et autre gestion d'Events, j'arrive plutôt pas mal à faire communiquer mes threads d'affichage et mes threads de fonctionnement.

    J'ai notamment un thread chargé de faire disparaitre une fenêtre WPF en cas d'inactivité. Pour cela, j'appelle un dispatcher qui s'occupe du Hide().
    Tout à l'air de marche pas mal...

    Sauf que maintenant, si je reprends EXACTEMENT le même code sur une fenêtre WPF contenant un WindowsFormHost, j'ai une belle InvalidOperationException ( Le thread appelant ne peut pas accéder à cet objet parce qu'un autre thread en est propriétaire.) qui arrive.

    J'ai fait une petite application toute bête qui reproduit exactement mon problème. En voici le code :

    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
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
     
    using System.Windows;
    using System.Threading;
    using System.Windows.Threading;
     
    namespace TEstThread
    {
        /// <summary>
        /// Logique d'interaction pour Window1.xaml
        /// </summary>
        public partial class Window1 : Window
        {
            Window2 DeuxiemeFenetre; //Une Window WPF classique avec rien de particulier (...mais si on y ajoute un WindowsFormHost, plus rien ne marche)
     
            Thread ThreadClignoteur; //Thread qui affiche ou cache la fenetre...
            Thread Demarrage; //Thread controllant l'ouverture de la fenetre
     
            bool clignote = true;
     
            /// <summary>
            /// Constructeur de la fenetre, qui contient juste un bouton Start ( btn_Lancer) et un bouton Stop (btn_Stop)
            /// </summary>
            public Window1()
            {
                InitializeComponent();
     
                //Initialisation du clignoteur
                ThreadClignoteur = new Thread(ThreadClignotage);
                ThreadClignoteur.SetApartmentState(ApartmentState.STA);
            }
     
     
            /// <summary>
            /// Lance le thread de clignotement
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void btn_Lancer_Click(object sender, RoutedEventArgs e)
            {
                ThreadClignoteur.Start();
            }
     
            /// <summary>
            /// Force la fermeture de la fenetre
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void btn_Stop_Click(object sender, RoutedEventArgs e)
            {
                clignote = false;
            }
     
     
            /// <summary>
            /// Clignote : lance le thread qui affiche la fenetre, puis essaie de cacher la fenetre... et recommence
            /// </summary>
            private void ThreadClignotage()
            {
                while (clignote)
                {
                    if (DeuxiemeFenetre == null || DeuxiemeFenetre.Visibility != Visibility.Visible)
                    {
                        newThreadFenetre();
                    }
                    Thread.Sleep(3000);
                    CacherFenetre2();
                    Thread.Sleep(2000);
                }
            }
     
            /// <summary>
            /// Cache la fenetre
            /// </summary>
            private void CacherFenetre2()
            {
                DeuxiemeFenetre.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (ThreadStart)delegate
                {
                    DeuxiemeFenetre.Hide();  
                });
            }
     
            /// <summary>
            /// Thread gérant l'affichage la fenetre
            /// </summary>
            private void newThreadFenetre()
            {
                Demarrage = new Thread(StartUI);
                Demarrage.SetApartmentState(ApartmentState.STA);
                Demarrage.Start();
            }
     
            /// <summary>
            /// Demarre la fenetre
            /// </summary>
            public void StartUI()
            {
                DeuxiemeFenetre = new Window2();
                DeuxiemeFenetre.ShowDialog();
            }
     
        }
    }
    J'ai commenté au maximum pour que vous compreniez.
    En gros, si "DeuxiemeFenetre" est une simple fenêtre WPF avec un Label, tout se passe bien.
    Maintenant, si je rajoute un WindowsFormHost à cette fenêtre, ça plante...

    Qu'ai-je fait de mal ? Comment m'en sortir ?

  2. #2
    Membre averti

    Inscrit en
    Septembre 2004
    Messages
    105
    Détails du profil
    Informations forums :
    Inscription : Septembre 2004
    Messages : 105
    Points : 339
    Points
    339
    Par défaut
    Après un rapide tour sur Google, j'ai l'impression que WindowsFormsHost n'aime pas être "Hide()"
    Donc, essaye plutôt de le fermer.
    Et si la fermeture cause des problèmes, appele: DeuxiemeFenetre.MonWindowsFormsHost.Dispose().

  3. #3
    Membre régulier
    Profil pro
    Inscrit en
    Octobre 2005
    Messages
    222
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Octobre 2005
    Messages : 222
    Points : 110
    Points
    110
    Par défaut
    Merci, effectivement, ca marche plutôt pas mal.
    Du coup, je viens de m'apercevoir d'un effet de bord.

    J'appelle maintenant la fonction DoClose() sur ma DeuxiemeFenetre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
       public void DoClose()
            {
              WFH.Dispose(); //Detruire mon WindowsFormHost
                this.Visibility = Visibility.Collapsed;
                this.Close();
    }
    La fenêtre se ferme bien.

    Mais, si je regarde la mémoire prise par mon programme, celle-ci ne cesse d'augmenter, sans jamais diminuer.

    A chaque tour dans la boucle de ThreadClignotage, je lance un nouveau thread d'ouverture d'une nouvelle DeuxiemeFenetre, mais l'espace mémoire de la fenêtre précédemment fermée ne se libère pas. Au bout de plusieurs heures, mon programme "explose" ...

    Pourquoi le Close() ne libère-t-il pas la mémoire ? (J'ai essayé de faire un "GC.Collect()" sans résultat)

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

Discussions similaires

  1. [Débutant] WPF Thread UI sur dependency property change
    Par kraigoun dans le forum Windows Presentation Foundation
    Réponses: 5
    Dernier message: 10/08/2013, 15h41
  2. Réponses: 7
    Dernier message: 02/12/2009, 17h49
  3. Réponses: 1
    Dernier message: 04/12/2008, 13h51
  4. Bizarrerie entre WPF et le Thread.CurrentPrincipal
    Par anthyme dans le forum Windows Presentation Foundation
    Réponses: 2
    Dernier message: 11/07/2008, 14h08
  5. Réponses: 1
    Dernier message: 15/09/2007, 15h13

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