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: Créer des UserControl dans un BackgroundWorker .


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: Créer des UserControl dans un BackgroundWorker .
    Bonjour,

    Il est maintenant connu que WPF (XAML) interdit toute modification de l'interface ailleurs que dans le Thread principal.

    Dans le cadre mon application, j'ai un BackgroundWorker qui doit générer des UserControls, et forcement ca ne marche pas.

    Je ne peux pas me passer du BackgroundWorker car la génération est plutôt longue et ne doit pas bloquer l'application, de plus j'affiche la progression dans une ProgressBar.

    Donc, en utilisant les quelques neurones qu'il me reste, je me suis débrouillé pour que :
    - Le BackgroundWorker me crée tous les éléments utiles pour créer mes UserControls.
    - Le BackgroundWorker remplit un tableau contenant tous ces élements.
    - Le BackgroundWorker fait correctement progresser ma ProgressBar.
    - Une fois le BackgroundWorker terminé, l'event RunWorkerCompleted est lancé.

    Je souhaiterai maintenant créer mes UserControls à partir de mon tableau d'éléments, mais cela dans le Thread Principal pour ne pas avoir d'erreur... (car je dois faire des "new UCtest()" qui lève une erreur si ce n'est pas le thread principal qui s'en occupe)

    Malheureusement, je ne vois pas comment faire.

    Je ne sais pas si j'étais très clair, mais en même temps le problème est assez compliqué aussi.


    J'ai essayé :
    - Créer mes UCs depuis la fonction du RunWorkerCompleted , sans succès.
    - Mon RunWorkerCompleted lance une autre fonction via un Dispatcher, sans succés.
    - Mon RunWorkerCompleted place un booléen qui débloque mon thread principal qui attend, mais si le thread principal est bloqué en attendant, mon BackgroundWorker n'a plus d'intérêt.
    - Mon RunWorkerCompleted lance une autre évènement pour être capté par le thread principal, mais ca ne marche pas comme ca...

    Je suis assez perdu là...à l'aide !!

  2. #2
    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
    Bon alors, apres quelques recherche, une partie des erreurs venait de mon constructeur de UCTest() qui faisait une modification d'un sous-éléments graphiques sans Dispatcher..

    Si je rajoute un Dispatcher dans mon constructeur de UCTest, je n'ai plus la même erreur. J'ai un TargetInvocationException qui ne m'aide pas plus....

  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
    Bon, je vais essayer d'être plus clair, d'autant que j'ai un peu avancé.

    Mon appli est un explorateur de fichier/=.
    Cela se présente sous la forme d'une Windows WPF contenant une ListBox.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    System.Windows.Controls.ListBox FileContainer;
    Lorsque je choisi un chemin disque, je dois lister les fichiers présents dans le dossier, et les afficher dans la Listbox grace à un UserControl UCFile.

    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
     
    public partial class UCFile : UserControl , IComparable<UCFile>
    {
    		public UCFile(String _filepath, ImageSource _img, EventHandler<MessageEventArgs> _selectevent, EventHandler<MessageEventArgs> _dclickevent)
    		{
    			this.InitializeComponent();
                CompletePath = _filepath;
     
                //Affichage du libellé, affichage de la miniature
                this.lblFileName.Text = System.IO.Path.GetFileName(_filepath);
                this.imgFileIcon.Source = _img;
     
                //Evenement de click et selection
                UCFile_DoubleClicked = _dclickevent;
                UCFile_Selected = _selectevent;
     
                ResizeAll();
    		}
    ...
    }
    Donc, voila ce qui se passe lorsque je choisit un chemin
    Je lance un BackgroundWorker_DoWork qui va :
    - lister les fichiers
    - générer la miniature du fichier
    - créer un objet ThumbAssoc qui contient tout ce qui est nécessaire à la création d'un UCFile. (car impossible de créer un UCFILE directement, car nécessite un thread en mode STA)
    - Ajouter le ThumbAssoc créée à un ArrayList
    - Trier l'ArrayList

    Une fois terminée, le BackgroundWorker_Complete va :
    - Pour chaque ThumbAssoc
    - Créer un UCFile correspondant
    - L'ajouter à la ListBox

    Voilà, sur le papier tout à l'air d'aller...

    Mais j'ai une erreur de type :
    Le thread appelant ne peut pas accéder à cet objet parce qu'un autre thread en est propriétaire.
    dans le constructeur de UCFile lors de l'affectation de l'image.

    Si je rajoute un Dispatcher sur la ligne qui plante, c'est un TargetInvocationException

    En fait le problème vient de l'affichage de la miniature dans l'UCFile.

    Car si je change mon constructeur d'UCFile comme ca :

    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
     
    public partial class UCFile : UserControl , IComparable<UCFile>
    {
    		public UCFile(String _filepath, ImageSource _img, EventHandler<MessageEventArgs> _selectevent, EventHandler<MessageEventArgs> _dclickevent)
    		{
    			this.InitializeComponent();
                CompletePath = _filepath;
     
                //Affichage du libellé, affichage de la miniature
                this.lblFileName.Text = System.IO.Path.GetFileName(_filepath);
     
    //ON RETIRE LA GESTION DE L'IMAGE
                //this.imgFileIcon.Source = _img;
     
                //Evenement de click et selection
                UCFile_DoubleClicked = _dclickevent;
                UCFile_Selected = _selectevent;
     
                ResizeAll();
    		}
    ...
    }
    Et bien, si on ne gère pas l'image... tout marche tres bien.. sauf qu'on a pas d'image qui s'affiche...

    Je ne comprend pas...

  4. #4
    Expert éminent sénior Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    Avril 2007
    Messages
    14 175
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 175
    Points : 25 116
    Points
    25 116
    Par défaut
    j'ai l'impression que tu codes en wpf comme en windows forms, ce qui n'est pas recommandé
    en windows forms on peut en effet remplir ses controles par le code
    mais en wpf, en général on charge les données dans des classes et on explique à l'interface comment trouver les données (bindings)
    ca permet de pouvoir travailler dans des thread pour le chargement des données, vu qu'on les charge dans des classes non graphiques (ca permet aussi d'avoir un code clair et plus indépendant

  5. #5
    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
    J'en suis arrivé à la même conclusion.

    Je suis en train d'essayer de faire un Binding dans mon UCFile.

    J'essaie de "Binder" mon this.imgFileIcon.Source sur la donnée membre ImageSource Thumbnail récupérée dans mon constructeur

    Mais je galère un peu.

    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
     
    		public UCFile(String _filepath, ImageSource _img, EventHandler<MessageEventArgs> _selectevent, EventHandler<MessageEventArgs> _dclickevent)
    		{
    			this.InitializeComponent();
                CompletePath = _filepath;
     
                //Affichage du libellé, affichage de la miniature
                this.lblFileName.Text = System.IO.Path.GetFileName(_filepath);
                //this.imgFileIcon.Source = _img;
                Thumbnail = _img;            
     
                //Evenement de click et selection
                UCFile_DoubleClicked = _dclickevent;
                UCFile_Selected = _selectevent;
     
                ResizeAll();
    		}
     
            private ImageSource _thumb;
            public ImageSource Thumbnail
            {
                set { _thumb = value; }
                get { return _thumb ; }
            }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    <Image x:Name="imgFileIcon" Margin="0" HorizontalAlignment="Center" VerticalAlignment="Center" Width="149" Height="149" >
            <Image.Source>
                <Binding Path="Thumbnail" />
            </Image.Source>

  6. #6
    Expert éminent sénior Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    Avril 2007
    Messages
    14 175
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 175
    Points : 25 116
    Points
    25 116
    Par défaut
    pour du binding, il faut soit des dependencyproperty soit implémenter inotifypropertychanged

    pour gérer les ajouts ou suppression d'une collection, il faut un system.collections.objectmodel.observablecollection

  7. #7
    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
    Ouais, c'est bien ce qui m'inquiète.. Je suis très nul en Binding.... C'est un principe qui a l'air simple, mais pour lequel je galère à caque fois.

    Tu me conseilles :
    - de "Binder" la liste des éléments de mon FileContainer ?
    et/ou
    - de "Binder" l'ImageSource de chacun de mes UCFile(s) ?

    Je n'arrive pas à voir par où partir dans le sens ou mes UCFile(s) sont générés à la volée.
    Lorsque je rentre dans un dossier, leur nombre et leur contenu peut varier d'un dossier à l'autre, mais une fois créé, il n'ont plus de raison d'être modifiés... juste supprimés pour en créer d'autres.

    Des tutos? des exemples ?

  8. #8
    Expert éminent sénior Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    Avril 2007
    Messages
    14 175
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 175
    Points : 25 116
    Points
    25 116
    Par défaut
    il ne faut pas focrément faire un UC
    en général on bind la collection au listbox et on utilise un datatemplate pour l'affichage
    en haut du site y a un lien vers les tutos

Discussions similaires

  1. Impossible de créer des fichiers dans un répertoire
    Par isabelle674 dans le forum Solaris
    Réponses: 11
    Dernier message: 24/01/2008, 00h04
  2. Créer des Section dans un Image JPG
    Par Charo dans le forum Imagerie
    Réponses: 2
    Dernier message: 31/01/2007, 09h56
  3. Réponses: 5
    Dernier message: 17/01/2007, 15h02
  4. Réponses: 1
    Dernier message: 22/12/2005, 09h03

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