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 :

ListBox, selection multiple


Sujet :

Windows Presentation Foundation

  1. #1
    Membre émérite
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Avril 2006
    Messages
    1 627
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2006
    Messages : 1 627
    Points : 2 331
    Points
    2 331
    Par défaut ListBox, selection multiple
    Bonsoir,

    sur une listBox je bind une List<Selection>

    Selection est une petite classe qui expose un objet sous-jacent pour gérer la sélection, de la forme
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    public class Selection<T>
    {
      public bool IsSelect {get; set;}
      public String Designation {get;} //En interne utilise une Func<T, String> pour générer la String à renvoyer
      public T Item { get; set }
    }
    et j'ai mon ptit code XAML qui décrit ma listBox :
    Code xml : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    <ListBox SelectionMode="Multiple" Name="ExportSelectZone" Grid.Row="0" Grid.Column="0">
                            <ListBox.ItemTemplate>
                                <DataTemplate>
                                    <ListBoxItem IsSelected="{Binding Path=IsSelect, Mode=TwoWay}" Content="{Binding Path=Designation}" />
                                </DataTemplate>
                            </ListBox.ItemTemplate>
                        </ListBox>

    J'affecte ma List à ExportSelectZone.ItemsSource après une requête Linq en code behind.

    Ca marche très bien, j'ai ma liste, la sélection fonctionne à un détail près : si je clique sur le text de la ListBoxItem, la sélection ne se fait pas, si je clique sur la partie vide entre la désignation et le bord de la ListBox, la sélection se fait... Et j'avoue que là comme ça je suis perplexe...

    Donc merci aux bonnes âmes qui viendront à mon aide

  2. #2
    Membre expert
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    2 210
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 2 210
    Points : 3 015
    Points
    3 015
    Par défaut
    Salut,

    C'est un peu bizarre ce que tu fais. Tu ajoutes un ListBoxItem dans le template du ListBoxItem... donc j'ai envie de dire c'est normal...

    Essaie avec ça :
    Code xml : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
                        <ListBox SelectionMode="Multiple" Name="ExportSelectZone" Grid.Row="0" Grid.Column="0">
                          <ListBox.ItemContainerStyle>
                            <Style TargetType="{x:Type ListBoxItem}">
                              <Setter Property="IsSelected" Value="{Binding IsSelect, Mode=TwoWay}" />
                            </Style>
                          </ListBox.ItemContainerStyle>
                            <ListBox.ItemTemplate>
                                <DataTemplate>
                                    <Label Content="{Binding Path=Designation}" />
                                </DataTemplate>
                            </ListBox.ItemTemplate>
                        </ListBox>

  3. #3
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Points : 39 753
    Points
    39 753
    Par défaut
    Il n'y a pas vraiment besoin du ItemTemplate d'ailleurs, il suffit d'utiliser DisplayMemberPath="Designation"

    Pour élaborer un peu sur la réponse de binoo : un ListBoxItem n'a rien à faire dans un DataTemplate. Les ListBoxItems sont automatiquement générés par la ListBox pour contenir chaque élément, donc en faisant comme tu fais, tu te retrouves avec un ListBoxItem dans un ListBoxItem...

    En fait, quand tu as besoin d'appliquer une propriété ou un binding aux conteneurs des items (en l'occurrence des ListBoxItem pour une ListBox), tu le fais toujours via le ItemContainerStyle

  4. #4
    Membre émérite
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Avril 2006
    Messages
    1 627
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2006
    Messages : 1 627
    Points : 2 331
    Points
    2 331
    Par défaut
    Oki, j'ai compris mon erreur, et merci pour l'éclaircissement sur le ItemContainerStyle

    Ca fonctionne nickel, encore merci

  5. #5
    Membre émérite
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Avril 2006
    Messages
    1 627
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2006
    Messages : 1 627
    Points : 2 331
    Points
    2 331
    Par défaut
    Retour sur le sujet.

    Rappel : une listbox qui affiche des éléments, paramétrée pour une sélection multiple, l'état IsSelected de la ligne de la listBox étant bindée sur la propriété IsSelect de ma classe Selection.

    2 moyens pour (dé)sélectionner : on clique sur la ligne, ou on utilise les boutons Tout/Aucun (qui, respectivement, affecte à tous les éléments de la collection àa valeur true/false sur la propriété IsSelect, et donc par binding, fait que la liste affiche les éléments comme sélectionnés ou non).

    Pas de problème quand ma liste assez restreinte, mais quand je dépasse quelques dizaines d'éléments (la listbox a une height permettant l'affichage d'une dizaine d'éléments), j'ai le fonctionnel suivant :
    - Tout sélectionner avec le bouton : OK
    - Tout dé-sélectionner avec le bouton : les éléments visibles dans la listbox sont dé-sélectionnés, mais pas ceux en dessous/dessus. Si je scroll, les autres m'apparaissent visibles ET sélectionnés. Pas fun quoi, un bouton qui fait pas son taff.

    Selection.cs
    Code c# : 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
    internal class Selection<T> : INotifyPropertyChanged
        {
            private Func<T, String> getDesignation;
            private bool isSelect = false;
     
            public bool IsSelect 
            { 
                get { return isSelect;  }
                set 
                {
                    //if (value == isSelect)
                    //    return;
     
                    isSelect = value;
                    ReportPropertyChanged("IsSelect"); 
                } 
            }
     
     
            public T Item { get; private set; }
     
            public String Designation
            {
                get
                {
                    return getDesignation(Item);
                }
            }
     
            public Selection(T item, Func<T, String> DesignationGetter)
            {
                getDesignation = DesignationGetter;
                Item = item;
            }
     
            private void ReportPropertyChanged(String propertyName)
            {
                if (PropertyChanged != null)
                    PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
     
            public event PropertyChangedEventHandler PropertyChanged;
        }

    UserControl.cs
    Code c# : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    if (btNoZone == sender)
                {
                    List<Selection<Zone>> zones = (ExportSelectZone.ItemsSource as List<Selection<Zone>>);
                   zones.ForEach(z => z.IsSelect = false);
     
                    ExportSelectZone.Focus();
                }
                else if (btFullZone == sender)
                {
                    List<Selection<Zone>> zones = (ExportSelectZone.ItemsSource as List<Selection<Zone>>)
                   zones.ForEach(z => z.IsSelect = true);
     
                    ExportSelectZone.Focus();
                }

    Code xml : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    <ListBox SelectionMode="Multiple" Name="ExportSelectZone" Grid.Row="1" Grid.Column="0">
                            <ListBox.ItemContainerStyle>
                                <Style TargetType="{x:Type ListBoxItem}">
                                    <Setter Property="IsSelected" Value="{Binding IsSelect, Mode=TwoWay}" />
                                </Style>
                            </ListBox.ItemContainerStyle>
                            <ListBox.ItemTemplate>
                                <DataTemplate>
                                    <Label Content="{Binding Path=Designation}" />
                                </DataTemplate>
                            </ListBox.ItemTemplate>
                        </ListBox>

    Question bonus : quand la listbox a le focus, les lignes IsSelected apparaissent avec un fond bleu, mais quand il perdent le focus, ce fond devient gris clair, assez difficile à différencier du gris très clair du fond de l'appli, je voudrais que focus ou non, ce soit toujours fond bleu, une idée ?

    Merci pour votre attention !

  6. #6
    Membre averti
    Profil pro
    Inscrit en
    Janvier 2008
    Messages
    537
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2008
    Messages : 537
    Points : 369
    Points
    369
    Par défaut
    Place ça dans les ressources de ta listbox :

    Code XAML : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    <SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" Color="{x:Static SystemColors.HighlightColor}"/>

  7. #7
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Points : 39 753
    Points
    39 753
    Par défaut
    Citation Envoyé par Arnard Voir le message
    - Tout dé-sélectionner avec le bouton : les éléments visibles dans la listbox sont dé-sélectionnés, mais pas ceux en dessous/dessus. Si je scroll, les autres m'apparaissent visibles ET sélectionnés. Pas fun quoi, un bouton qui fait pas son taff.
    Je pense que c'est à cause de la virtualisation... Par défaut la ListBox ne crée des ListBoxItem que pour les éléments qui sont visibles, et en crée de nouveaux (ou réutilise ceux qui existent, selon le mode) quand tu scrolles. Ce qui est bizarre c'est qu'il ne rafraichisse pas le binding sur les nouveaux ListBoxItems...

    Essaie de désactiver la virtualisation (VirtualizingStackPanel.IsVirtualizing="False" sur la ListBox), ou de changer le mode de virtualisation (VirtualizingStackPanel.VirtualizationMode). Si c'est bien ce que je crois ça devrait régler le problème... Par contre je trouve quand même bizarre que ça marche pas avec la virtualisation, je ferai le test de mon côté ce soir

  8. #8
    Membre émérite
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Avril 2006
    Messages
    1 627
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2006
    Messages : 1 627
    Points : 2 331
    Points
    2 331
    Par défaut
    1min, 2 réponses, 2 soucis en moins

    @TomLev : me doutais que la virtualisation devait jouer vu que c'était que ce qui est affiché qui est traité, mais ça paraissait quand même folklo, je n'ai jamais touché à ce genre de traitements, donc qu'il le fasse tout seul comme un gros, mouarf
    Si tu identifies le pourquoi du comment, je prends

    Encore merci.

  9. #9
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Points : 39 753
    Points
    39 753
    Par défaut
    Bon, j'ai testé, c'est effectivement assez bizarre...

    Je comprends pourquoi quand tu fais "Ctrl-A" ça ne met pas à jour la propriété sur les items non visibles, puisque ceux-ci n'ont pas de ListBoxItem associé qui pourrait mettre à jour le binding. Mais le fait que ça ne marche pas dans l'autre sens, c'est plus bizarre...

    En fait j'ai ajouté des traces pour voir ce qui se passait, et voilà ce que ça donne quand un élément déselectionné par le code réapparait :

    1. Target updated - {Item 95, False}
    2. Source updated - {Item 95, True}
    Tentative d'explication :
    • la ListBox stocke les index des éléments sélectionnés
    • si l'élément à la position x était sélectionné, mais pas visible, et que tu l'as déselectionné par le code, au moment où il devient visible voilà ce qu'il se passe :
      • le binding se rafraichit, donc il relit la propriété de la source et le IsSelected du ListBoxItem passe bien à false (trace 1)
      • la ListBox sait que l'élément à cette position était sélectionné, et remet donc le IsSelected du ListBoxItem à true
      • le binding, qui est TwoWay, met à jour la source en conséquence, et passe donc à true la propriété IsSelect de ton objet Selection<T>, ce qui écrase la valeur précédente (trace 2)


    Bref, c'est un bug, mais pas vraiment dans le sens où il y a une explication logique. En fait, il faudrait qu'avant de changer le IsSelected d'un ListBoxItem qui "apparait", ça vérifie si la propriété est bindée, et si oui, que ça prenne en compte la valeur de la source. Mais bon, ça m'étonnerait un peu que MS corrige ça un jour, vu que ce n'est pas un scénario très courant...

    J'ai cherché des bidouilles pour régler le problème, mais j'ai rien trouvé de probant (à part bien sûr désactiver la virtualisation)

    Il y a une discussion à ce sujet sur StackOverflow

  10. #10
    Membre émérite
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Avril 2006
    Messages
    1 627
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2006
    Messages : 1 627
    Points : 2 331
    Points
    2 331
    Par défaut
    Merci pour l'explication, en effet ça fait un peu retors

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

Discussions similaires

  1. Listbox selection multiple filtre
    Par Lionhart dans le forum C#
    Réponses: 2
    Dernier message: 08/01/2015, 16h02
  2. listbox selection multiple
    Par Chris171717 dans le forum Macros et VBA Excel
    Réponses: 4
    Dernier message: 15/03/2013, 13h09
  3. listbox selection multiple VB
    Par jcl49 dans le forum VB.NET
    Réponses: 11
    Dernier message: 19/05/2011, 09h51
  4. récupérer valeur listbox selection multiple
    Par titou624 dans le forum C#
    Réponses: 9
    Dernier message: 18/05/2010, 09h09
  5. Problème entre 2 listbox à selection multiple
    Par SoaB dans le forum Général JavaScript
    Réponses: 24
    Dernier message: 24/10/2005, 16h05

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