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

Windows Presentation Foundation Discussion :

ListView : accéder au contrôle correspondant à un item


Sujet :

Windows Presentation Foundation

  1. #1
    Membre actif
    Profil pro
    Inscrit en
    Août 2006
    Messages
    582
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 582
    Points : 265
    Points
    265
    Par défaut ListView : accéder au contrôle correspondant à un item
    Bonjour,
    j'ai une listview, liée à un DataTemplate pour afficher ses éléments sous forme de checkboxes:
    Code xaml : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    <DataTemplate x:Key="GenreTemplate">
          <CheckBox Content="{Binding Path = Label}" />
    </DataTemplate>
     
    <ListView x:Name="lstGenres" ItemsSource="{Binding Source={StaticResource genreViewSource}}" ItemTemplate="{StaticResource GenreTemplate}">

    • 1er problème: je dois trouver un élément de la ListView par le Content de sa checkbox. Comment faire ?



    • 2e problème: une fois l'item trouvé en 1), j'aimerai accéder à sa checkbox pour pouvoir la cocher/décocher... Comment faire ?

  2. #2
    Membre actif
    Profil pro
    Inscrit en
    Août 2006
    Messages
    582
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 582
    Points : 265
    Points
    265
    Par défaut
    Bon, depuis hier, j'ai changé ma ListView pour un ItemControl, mais bon, ça ne change rien à mon problème.
    Code xaml : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    <ItemsControl VirtualizingPanel.IsVirtualizing="False" x:Name="icGenres" ItemsSource="{Binding Source={StaticResource genreViewSource}}">
         <ItemsControl.ItemTemplate>
             <DataTemplate>
                <CheckBox Content="{Binding Path = Label}" />
             </DataTemplate>
         </ItemsControl.ItemTemplate>
    </ItemsControl>
    J'ai glané ce 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
            public static T FindVisualChild<T>(DependencyObject depObj) where T : DependencyObject
            {
                if (depObj != null)
                {
                    for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
                    {
                        DependencyObject child = VisualTreeHelper.GetChild(depObj, i);
                        if (child != null && child is T)
                        {
                            return (T)child;
                        }
     
                        T childItem = FindVisualChild<T>(child);
                        if (childItem != null) return childItem;
                    }
                }
                return null;
            }
    Que j'utilise dans la boucle suivante:
    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
    foreach (var item in this.icGenres.Items)
                        {
                            Genre myGenre = (Genre)item;
                            foreach (var gen in this.Source.View.SourceCollection)
                            {
                                Genre gn = (Genre)gen;
                                if (gn.Label == myGenre.Label)
                                {
                                    ContentPresenter container = icGenres.ItemContainerGenerator.ContainerFromItem(item) as ContentPresenter;
                                    CheckBox myCheck = FindVisualChild<CheckBox>(container);
                                    if (myCheck != null) { myCheck.IsChecked = true; }
                                }
                            }
                        }
                    }
     
                }
     
            }
    Le problème: la fonction FindVisualChild renvoie null. Un VisualTreeHelper.GetChildrenCount(container) me retourne 0.
    Pourquoi ?

  3. #3
    Membre expert
    Avatar de Pragmateek
    Homme Profil pro
    Formateur expert .Net/C#
    Inscrit en
    Mars 2006
    Messages
    2 635
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Formateur expert .Net/C#
    Secteur : Conseil

    Informations forums :
    Inscription : Mars 2006
    Messages : 2 635
    Points : 3 958
    Points
    3 958
    Par défaut
    Si tu as le contrôle sur les éléments que tu affiches la bonne façon de faire est de data-binder l'état de la CheckBox à celui de l'objet :

    Code xaml : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    <DataTemplate>
        <CheckBox Content="{Binding Path = Label}" IsChecked="{Binding Path=IsSelected}" />
    </DataTemplate>
    Formateur expert .Net/C#/WPF/EF Certifié MCP disponible sur Paris, province et pays limitrophes (enseignement en français uniquement).
    Mon blog : pragmateek.com

  4. #4
    Membre actif
    Profil pro
    Inscrit en
    Août 2006
    Messages
    582
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 582
    Points : 265
    Points
    265
    Par défaut
    Ben, en fait, je dois comparer 2 collections. Je m'explique: mon projet est chargé de gérer une vidéothèque.
    genreViewSource est la CollectionViewSource qui contient tous les genres de film de ma base de données.

    Et j'ai créé une propriété Source sur mon UC qui reçoit elle, uniquement les genres correspondant à un film donné.

    Dans ma fenêtre, je souhaite présenter ces infos ainsi:
    afficher tous les genres, puis cocher ceux qui correspondent au film donné.

    Je souhaitais donc comparer ces 2 collections et cocher les checkboxes de la 1ère qui figurait dans la 2e collection. J'espère avoir été clair.

    Mais je ne vois pas comment mettre en place ce que tu me préconises dans mon cas précis. Si tu as une idée...

  5. #5
    Membre expert
    Avatar de Pragmateek
    Homme Profil pro
    Formateur expert .Net/C#
    Inscrit en
    Mars 2006
    Messages
    2 635
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Formateur expert .Net/C#
    Secteur : Conseil

    Informations forums :
    Inscription : Mars 2006
    Messages : 2 635
    Points : 3 958
    Points
    3 958
    Par défaut
    OK dans ce cas le plus "clean", et sans doute le plus simple, est de créer un petit type adapteur SelectableGenre qui en plus du label du genre exposera un booléen indiquant s'il est sélectionné :

    Code csharp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    class SelectableGenre
    {
        public string Label { get; set; }
        public bool IsSelected { get; set; }
    }

    Il suffit d'en créer une collection via du LINQ par exemple :

    Code csharp : Sélectionner tout - Visualiser dans une fenêtre à part
    IEnumerable<SelectableGenre> selectableGenres = genres.Select(g => new SelectableGenre{ Label = g.Label, IsSelected = movie.Genres.Contains(g) });
    Formateur expert .Net/C#/WPF/EF Certifié MCP disponible sur Paris, province et pays limitrophes (enseignement en français uniquement).
    Mon blog : pragmateek.com

  6. #6
    Membre actif
    Profil pro
    Inscrit en
    Août 2006
    Messages
    582
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 582
    Points : 265
    Points
    265
    Par défaut
    Hmmm... Je ne vois pas comment relier cet adapteur au reste...
    Cependant, à partir de là, j'ai créé dans mon modèle, une propriété booléenne ToCheck dans l'Entité Genre et j'ai bindé la propriété IsChecked de ma checkbox à cette propriété:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    <CheckBox Content="{Binding Path = Label}" IsChecked="{Binding Path=ToCheck}" />
    Ensuite, dans le UC_Loaded, j'effectue cette boucle:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    foreach (var item in this.icGenres.Items) //icGenres.Items contient la collection de tous les genres
                        {
                            Genre myGenre = (Genre)item;
                            if (this.Source.View.Contains(myGenre)) //la propriété Source contient les genres du film donné
                            {
                                myGenre.ToCheck = true;
                            }
                         }
    Je pense que c'est équivalent à la solution que tu me proposes (sinon, corrige-moi).
    Le problème:
    Rien n'est coché parce que this.Source.View.Contains(myGenre) renvoie toujours false même quand il arrive sur un Genre qui se trouve dans les 2 collections.
    Je ne vois pas pourquoi...

  7. #7
    Membre actif
    Profil pro
    Inscrit en
    Août 2006
    Messages
    582
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 582
    Points : 265
    Points
    265
    Par défaut
    Bon, déjà, j'ai interverti et mis dans la boucle la collection la plus petite et enlevé tout ce qui était redondant:
    Code csharp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    foreach (Genre item in this.Source.View.SourceCollection) // Source contient les genres du film 
    {
          if (icGenres.Items.Contains(item)) { item.ToCheck = true; } // IcGenres.Items contient TOUS les genres 
    }
    Mais bon, le problème est le même: la fonction Contains() renvoie toujours faux...

  8. #8
    Membre actif
    Profil pro
    Inscrit en
    Août 2006
    Messages
    582
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 582
    Points : 265
    Points
    265
    Par défaut
    J'ai fait afficher des informations de debuggage. En voici la sortie:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    icGenres.Items(0) = System.Data.Entity.DynamicProxies.Genre_310353021FE2724B595D5F69FE38B0BA28776AE490C5A1CC388B9F5F9103125F ; Drame
    icGenres.Items(1) = System.Data.Entity.DynamicProxies.Genre_310353021FE2724B595D5F69FE38B0BA28776AE490C5A1CC388B9F5F9103125F ; Comédie
    icGenres.Items(2) = System.Data.Entity.DynamicProxies.Genre_310353021FE2724B595D5F69FE38B0BA28776AE490C5A1CC388B9F5F9103125F ; Thriller
    icGenres.Items(3) = System.Data.Entity.DynamicProxies.Genre_310353021FE2724B595D5F69FE38B0BA28776AE490C5A1CC388B9F5F9103125F ; Aventures
    icGenres.Items(4) = System.Data.Entity.DynamicProxies.Genre_310353021FE2724B595D5F69FE38B0BA28776AE490C5A1CC388B9F5F9103125F ; Action
     
     
     
    item = System.Data.Entity.DynamicProxies.Genre_310353021FE2724B595D5F69FE38B0BA28776AE490C5A1CC388B9F5F9103125F ; Aventures
    Contains(Aventures) = False
     
    item = System.Data.Entity.DynamicProxies.Genre_310353021FE2724B595D5F69FE38B0BA28776AE490C5A1CC388B9F5F9103125F ; Action
    Contains(Action) = False

  9. #9
    Membre actif
    Profil pro
    Inscrit en
    Août 2006
    Messages
    582
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 582
    Points : 265
    Points
    265
    Par défaut
    Citation Envoyé par jacquesprogram Voir le message
    Mais bon, le problème est le même: la fonction Contains() renvoie toujours faux...
    Ne serait-ce pas dû au fait que la comparaison s'effectue au niveau objet et, vu que les 2 objets comparés appartiennent à 2 collections différentes, ils ne sont pas égaux (l'égalité n'implique-t-elle pas que ce soit la même instance des 2 côtés) ?
    Ce que je dois comparer, c'est les propriétés Label de chacun des 2 objets.

    J'ai donc modifier le code et imbriqué une 2de boucle à la 1ère pour comparer les Labels cette fois:
    Code csharp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
                        foreach (Genre item in this.Source.View.SourceCollection) // Source contient les genres du film 
                        {
                            foreach (Genre gn in icGenres.Items) //icGenres contient TOUS les genres
                            {
                                if (item.Label == gn.Label) { item.ToCheck = true; }
                             }  
                         }
    Cette fois, ça marche: les 2 genres du film ont bien leur propriété ToCheck qui passe à true. Mais au niveau IHM, rien n'est répercuté...

  10. #10
    Membre actif
    Profil pro
    Inscrit en
    Août 2006
    Messages
    582
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 582
    Points : 265
    Points
    265
    Par défaut
    Oops! Je me suis trompé de collection. Mon UC est bindé à la collection de tous les genres, c'est donc au genre de icGenres.Items qu'il faut mettre ToCheck à true et non à celui de Source.View.SourceCollection:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
                        foreach (Genre item in this.Source.View.SourceCollection) // Source contient les genres du film 
                        {
                            foreach (Genre gn in icGenres.Items) //icGenres contient TOUS les genres
                            {
                                if (item.Label == gn.Label) { gn.ToCheck = true; } // et non item.ToCheck !!!
                             }  
                         }
    Merci Pragmateek, je n'aurais pas pensé à la solution sans toi.

  11. #11
    Membre expert
    Avatar de Pragmateek
    Homme Profil pro
    Formateur expert .Net/C#
    Inscrit en
    Mars 2006
    Messages
    2 635
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Formateur expert .Net/C#
    Secteur : Conseil

    Informations forums :
    Inscription : Mars 2006
    Messages : 2 635
    Points : 3 958
    Points
    3 958
    Par défaut
    Oui c'est exactement le même principe que ma solution (qui aurait aussi pu se faire par héritage au passage), sauf qu'ajouter une propriété graphique au modèle c'est "caca".
    Déjà d'un point vue conceptuel ça crée un couplage entre vue et modèle ce qui est à éviter.
    De plus si tu as plusieurs vues qui ont des besoins différents pour le rendu de Genre tu vas vite te retrouver à polluer ton entité métier avec 36 propriétés ayant une sémantique visuelle.
    Après du point de vue tuyauterie c'est sûr c'est le plus simple.

    Pour être conceptuellement plus clean l'idée est de créer une entité intermédiaire qui portera des caractéristiques visuelles (le booléen).
    Du point de vue tuyauterie c'est plus compliqué.

    Perso je ne suis pas dogmatique mais pragmatique (enfin j'essaye) donc ta version directe ne me choque pas plus que ça.
    Sache juste que certains fanatiques te lapideront pour pêché de "non découplage" (c'est très très grave ) et qu'au delà du dogme il y a parfois de vraies justifications techniques qui te concerneront ou pas, maintenant ou jamais.
    Formateur expert .Net/C#/WPF/EF Certifié MCP disponible sur Paris, province et pays limitrophes (enseignement en français uniquement).
    Mon blog : pragmateek.com

  12. #12
    Membre actif
    Profil pro
    Inscrit en
    Août 2006
    Messages
    582
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 582
    Points : 265
    Points
    265
    Par défaut
    Citation Envoyé par Pragmateek Voir le message
    sauf qu'ajouter une propriété graphique au modèle c'est "caca".
    Déjà d'un point vue conceptuel ça crée un couplage entre vue et modèle ce qui est à éviter.
    De plus si tu as plusieurs vues qui ont des besoins différents pour le rendu de Genre tu vas vite te retrouver à polluer ton entité métier avec 36 propriétés ayant une sémantique visuelle.
    Je n'utilise pas le MVVM (une hérésie de plus, peut-être ) ; je me fais la main sur ce projet mais je prends note pour la prochaine fois.
    Merci pour ces précisions.

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

Discussions similaires

  1. Double click Item ListView: accéder à une cellule particulière.
    Par c.piette dans le forum Macros et VBA Excel
    Réponses: 1
    Dernier message: 11/08/2016, 08h44
  2. Accéder à un contrôle avec son numéro
    Par nattyman dans le forum Access
    Réponses: 2
    Dernier message: 23/09/2006, 06h47
  3. Réponses: 2
    Dernier message: 31/08/2006, 11h20
  4. accéder à un contrôle de formulaire avec un nom de tableau
    Par jibouze dans le forum Général JavaScript
    Réponses: 5
    Dernier message: 30/06/2005, 23h57
  5. Réponses: 2
    Dernier message: 10/05/2005, 14h20

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