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 :

Multiselection dans une treeview


Sujet :

Windows Presentation Foundation

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Modérateur
    Avatar de Flaburgan
    Homme Profil pro
    Développeur Web
    Inscrit en
    Avril 2010
    Messages
    1 229
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Avril 2010
    Messages : 1 229
    Par défaut Multiselection dans une treeview
    Bonjour à tous,

    J'ai besoin de pouvoir sélectionner plusieurs éléments en même temps dans une treeview (par exemple, avec ctrl appuyé). J'ai trouvé le code suivant qui marche très bien (je l'ai testé séparément).

    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
    44
    45
    46
    private static readonly PropertyInfo IsSelectionChangeActiveProperty = typeof(TreeView).GetProperty (
                "IsSelectionChangeActive",
                BindingFlags.NonPublic | BindingFlags.Instance
            );
     
            public static void AllowMultiSelection(TreeView treeView)
            {
                if (IsSelectionChangeActiveProperty == null) return;
     
                var selectedItems = new List<TreeViewItem>();
                treeView.SelectedItemChanged += (a, b) => {
                    var treeViewItem = treeView.SelectedItem as TreeViewItem;
                    if (treeViewItem == null) return;
     
                    // allow multiple selection
                    // when control key is pressed
                    if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)) {
                        // suppress selection change notification
                        // select all selected items
                        // then restore selection change notifications
                        var isSelectionChangeActive = IsSelectionChangeActiveProperty.GetValue(treeView, null);
     
                        IsSelectionChangeActiveProperty.SetValue(treeView, true, null);
                        selectedItems.ForEach(item => item.IsSelected = true);
     
                        IsSelectionChangeActiveProperty.SetValue
                        (
                          treeView,
                          isSelectionChangeActive,
                          null
                        );
                    } else {
                        // deselect all selected items except the current one
                        selectedItems.ForEach(item => item.IsSelected = (item == treeViewItem));
                        selectedItems.Clear();
                    }
     
                    if (!selectedItems.Contains(treeViewItem)) {
                        selectedItems.Add(treeViewItem);
                    } else {
                        // deselect if already selected
                        treeViewItem.IsSelected = false;
                        selectedItems.Remove(treeViewItem);
                    }
                };
            }

    Cependant, dans mon application, ma treeview ne contient pas des treeview item mais est bindée sur une classe perso :

    Code XML : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    <TreeView Name="TreeViewSelectedData" ItemsSource="{Binding SelectedData}" DockPanel.Dock="Right">
                    <TreeView.ItemTemplate>
                        <HierarchicalDataTemplate ItemsSource="{Binding ChildItems}">
                            <TextBlock Text="{Binding Display}" Margin="0 3" FontStyle="{Binding FontStyle}" />
                        </HierarchicalDataTemplate>
                    </TreeView.ItemTemplate>
                </TreeView>

    Et par conséquent, le code ci-dessus ne marche pas. Lorsque je remplace TreeViewItem par ma classe perso, il me dit très logiquement que ma classe perso ne contient pas l'attribut "isSelected".

    Comment puis-je faire ?

  2. #2
    Membre extrêmement actif
    Inscrit en
    Avril 2008
    Messages
    2 573
    Détails du profil
    Informations personnelles :
    Âge : 65

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 573
    Par défaut
    Bonjour Flaburgan.

    Le treeview WPF est particulierement versatile entre nous.
    Pourquoi? Juges-en par toi-meme.
    -si SelectedValuePath n'est pas specifie il renvoie dans selecteditem le ....controle TreeViewItem clique oui....
    -si SelectedValuePath specifie une prop "data" ou un "class data" il renvoie dans selecteditem ce qui est specifie....bien sur.

    Maintenant pour revenir aux items selectionnes ,en WPF il est vivement recommende- comme l'ont souligne à maintes fois les mentors du forums TomLev et Pol63 (voir ci-dessus le post de gritfou) -d'utliser le modele "data" pour piloter l'interface c.à.d les controles....
    Les "hack" qui consistent à manipuler les controles par code (du genre itemcontainergenerator,etc....) sont à eviter absolument sauf si on veut changer completement "la logique interne de fonctionnement du controle" et non pas son apparence pour laquelle l'arsenal Style et DataTemplate suffisement amplement.....
    Pour ce qui est de la liste des "selelectedItems" il suffit de
    - rajouter une prop "IsSelected" dans ton class data et d'implementer la simpliste interface INotifyPropertyChanged.
    - de specifier SelectedValuePath
    - de "piquer le controle TreeViewItem clique" (c'est ici l'astuce dans l'event TreeViewItem_Selected ) et de le marquer selectionne ou non suivant l'appui de tes touches souhaites et le "tracker" dans l'event TreeView_SelectedItemChanged
    -dans la gestion de TreeView_SelectedItemChanged tu remplis ta liste recipiendiaire des selectedItems poir faire ton traitement ......

    Un Trigger.Data dans le DataTemplate de la class data permet en plus de donner un ""feedback" user....
    le code behind du class data tire de la "sdk":
    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
    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
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
     
    using System;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Media;
    using System.Windows.Shapes;
    using System.Collections.ObjectModel;
    using System.Collections.Generic;
    using System.ComponentModel;
     
    namespace WpfTreeViewMultipleSelection
    {
            public class League
            {
                public League(string name)
                {
                    _name = name;
                    _divisions = new List<Division>();
                }
     
     
                string _name;
     
                public string Name { get { return _name; } }
     
                List<Division> _divisions;
                public List<Division> Divisions { get { return _divisions; } }
     
            }
            public class Division
            {
                public Division(string name)
                {
                    _name = name;
                    _teams = new List<Team>();
     
                }
     
                string _name;
     
                public string Name { get { return _name; } }
     
                List<Team> _teams;
     
                public List<Team> Teams { get { return _teams; } }
     
            }
     
            /* prop à rajouter dans le model "data" MVVM*/
            /* plus la notification de changement de prop */
            /* pour le bon fonctionnement du binding */
            public class Team : INotifyPropertyChanged
            {
                public Team(string name)
                {
                    _name = name;
                    _IsSelected = false;
                }
     
                string _name;
     
                public string Name { get { return _name; } }
     
                /* prop à rajouter */
                bool _IsSelected;
                public bool  IsSelected 
                { 
                    get { return _IsSelected; } 
                    set { 
                        _IsSelected = value ;
                        NotifyPropertyChanged("IsSelected");
                    } 
                }
     
                #region INotifyPropertyChanged Membres
     
                public event PropertyChangedEventHandler PropertyChanged;
                private void NotifyPropertyChanged(string propName )
                 {
                   if(PropertyChanged !=null)
                   {
                     PropertyChanged(this,new PropertyChangedEventArgs (propName));
                   }
     
                 }
     
                #endregion
            }
     
            public class ListLeagueList : List<League>
            {
                public ListLeagueList()
                {
                    League l;
                    Division d;
     
                    Add(l = new League("League A"));
                    l.Divisions.Add((d = new Division("Division A")));
                    d.Teams.Add(new Team("Team I"));
                    d.Teams.Add(new Team("Team II"));
                    d.Teams.Add(new Team("Team III"));
                    d.Teams.Add(new Team("Team IV"));
                    d.Teams.Add(new Team("Team V"));
                    l.Divisions.Add((d = new Division("Division B")));
                    d.Teams.Add(new Team("Team Blue"));
                    d.Teams.Add(new Team("Team Red"));
                    d.Teams.Add(new Team("Team Yellow"));
                    d.Teams.Add(new Team("Team Green"));
                    d.Teams.Add(new Team("Team Orange"));
                    l.Divisions.Add((d = new Division("Division C")));
                    d.Teams.Add(new Team("Team East"));
                    d.Teams.Add(new Team("Team West"));
                    d.Teams.Add(new Team("Team North"));
                    d.Teams.Add(new Team("Team South"));
                    Add(l = new League("League B"));
                    l.Divisions.Add((d = new Division("Division A")));
                    d.Teams.Add(new Team("Team 1"));
                    d.Teams.Add(new Team("Team 2"));
                    d.Teams.Add(new Team("Team 3"));
                    d.Teams.Add(new Team("Team 4"));
                    d.Teams.Add(new Team("Team 5"));
                    l.Divisions.Add((d = new Division("Division B")));
                    d.Teams.Add(new Team("Team Diamond"));
                    d.Teams.Add(new Team("Team Heart"));
                    d.Teams.Add(new Team("Team Club"));
                    d.Teams.Add(new Team("Team Spade"));
                    l.Divisions.Add((d = new Division("Division C")));
                    d.Teams.Add(new Team("Team Alpha"));
                    d.Teams.Add(new Team("Team Beta"));
                    d.Teams.Add(new Team("Team Gamma"));
                    d.Teams.Add(new Team("Team Delta"));
                    d.Teams.Add(new Team("Team Epsilon"));
                }
     
                public League this[string name]
                {
                    get
                    {
                        foreach (League l in this)
                            if (l.Name == name)
                                return l;
     
                        return null;
                    }
                }
     
     
        }
    }
    code xaml winform:
    Code xaml : 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
     
    <Window x:Class="WpfTreeViewMultipleSelection.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:local="clr-namespace:WpfTreeViewMultipleSelection"
            Title="MainWindow" Height="350" Width="525">
        <Window.Resources>
            <local:ListLeagueList x:Key="MyList"></local:ListLeagueList>
     
            <HierarchicalDataTemplate 
                    DataType="{x:Type local:League}"
                    ItemsSource="{Binding Path=Divisions}">
                <TextBlock 
                        Text="{Binding Path=Name}"/>
            </HierarchicalDataTemplate>
     
            <HierarchicalDataTemplate 
                        DataType="{x:Type local:Division}"
                        ItemsSource="{Binding Path=Teams}">
                <TextBlock Text="{Binding Path=Name}"/>
            </HierarchicalDataTemplate>
     
            <DataTemplate 
                DataType="{x:Type local:Team}">
                <StackPanel Orientation="Horizontal"
                            Margin="10">
                    <TextBlock  
                        x:Name="tbTeam"
                        Foreground="CornflowerBlue"
                        FontFamily="Arial"
                        FontSize="14"
                        Text="{Binding Path=Name}"/>
                    <TextBlock 
                        Margin="10,0,0,0"
                        Foreground="CornflowerBlue"
                        FontFamily="Arial"
                        FontSize="14"
                        Text="{Binding Path=IsSelected}"/>
                </StackPanel>
                <!--ici des DataTrigger  "feedback user" pour suivre les items selectionnes--> 
                <DataTemplate.Triggers>
                    <DataTrigger 
                        Binding="{Binding Path=IsSelected}" 
                        Value="true">
                        <Setter 
                            Property="Foreground" 
                            Value="Red" 
                            TargetName="tbTeam"/>
                        <Setter 
                            Property="FontFamily" 
                            Value="Times New Roman"
                            TargetName="tbTeam"/>
                    </DataTrigger>
                </DataTemplate.Triggers>
            </DataTemplate>
        </Window.Resources>
        <!--preciser la prop à selectionner avec SelectedValuePath-->
        <!--ici :class Team-->
        <DockPanel>
            <TreeView 
                DockPanel.Dock="Left"
                Name="TreeView1" 
                SelectedValuePath="Team"
                SelectedItemChanged="TreeView1_SelectedItemChanged">
                <!--gerer event TreeViewItem_Selected-->
                <!--declencher  event TreeViewItem_Selected <=> mettre TreeViewItem.IsSelected=true-->
                <TreeViewItem 
                    HorizontalAlignment="Stretch"
                    VerticalAlignment="Stretch"
                    IsExpanded="True"
                    ItemsSource="{Binding Source={StaticResource MyList}}"
                    Header="My Soccer Leagues" 
                    Selected="TreeViewItem_Selected"
                   />
            </TreeView>
            <!--listbox  suit la liste des  elements selectionnes 
            pour traitement eventuel......-->
            <ListBox
                DockPanel.Dock="Right"
                x:Name="AfficheSelectionLB"
                Background="BlanchedAlmond"
                ScrollViewer.VerticalScrollBarVisibility="Visible"
                HorizontalAlignment="Stretch"
                VerticalAlignment="Stretch"
                ItemsSource="{Binding}">
                <ListBox.ItemTemplate>
                    <DataTemplate  DataType="{x:Type local:Team}" >
                        <StackPanel>
                            <TextBlock Text="{Binding Path=Name}"/>
                        </StackPanel>
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>
        </DockPanel>
    </Window>
    le simple code behind du winform:
    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
    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
     
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    using System.Collections.ObjectModel;
     
    namespace WpfTreeViewMultipleSelection
    {
        /// <summary>
        /// Logique d'interaction pour MainWindow.xaml
        /// </summary>
        public partial class MainWindow : Window
        {
            /* liste des items selectionnes */
            private ObservableCollection<Team> selectedItems = new ObservableCollection<Team>();
            public MainWindow()
            {
                InitializeComponent();
                this.AfficheSelectionLB.ItemsSource = selectedItems;
            }
     
            /* le controle  TreeViewItem selectionne on le "pique ici" */
            private TreeViewItem currentTreeViewItem;
            private void TreeViewItem_Selected(object sender, RoutedEventArgs e)
            {
                currentTreeViewItem = (TreeViewItem)e.Source;
                if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl))
                {
                    currentTreeViewItem.IsSelected = true; /* on le releselectionne  seulement si on veut*/
                }
                else
                {
                    currentTreeViewItem.IsSelected = false; /* sinon on le deselectionne */
                }
     
            }
     
            private void TreeView1_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
            {
     
                TreeView myTreeView = (TreeView)e.Source;
                Team itemTeam = (Team)myTreeView.SelectedItem;
                if (currentTreeViewItem != null && currentTreeViewItem.IsSelected)
                {
                    if (!itemTeam.IsSelected)
                    {
                        itemTeam.IsSelected = currentTreeViewItem.IsSelected;
                        selectedItems.Add(itemTeam);
                    }
                    else
                    {
                        itemTeam.IsSelected = false;
                        selectedItems.Remove(itemTeam);
                    }
     
                }
     
            }
     
     
        }
    }
    A toi de voir comment adapter ce pattern à ton cas...........
    Bon code......

  3. #3
    Modérateur
    Avatar de Flaburgan
    Homme Profil pro
    Développeur Web
    Inscrit en
    Avril 2010
    Messages
    1 229
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Avril 2010
    Messages : 1 229
    Par défaut
    Salut Mabrouki et merci pour ta réponse.

    Je n'ai pas tout compris de ce que tu m'as expliqué (je débute) mais merci pour ton exemple. As-tu le lien duquel il est tiré ?

    Tu dis aussi "voir le post de gritfou", peux-tu me donner un lien vers ce post ?

    Et dernière question, qu'est-ce que selectedvaluepath ?

  4. #4
    Modérateur
    Avatar de Flaburgan
    Homme Profil pro
    Développeur Web
    Inscrit en
    Avril 2010
    Messages
    1 229
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Avril 2010
    Messages : 1 229
    Par défaut
    J'ai résolu mon souci en me basant sur l'exemple ci-dessus mais de manière plus simple (mon problème étant justement que mes données n'étaient pas des TreeViewItem donc que je ne pouvais pas lancé d'event quand ils étaient sélectionnés).

    Donc avec seulement un event sur la treeview avec SelectedItemChanged et une liste, on s'en sort ! (en rajoutant bien sûr la propriété IsSelected dans la classe perso, ici TreeItemDisplay)

    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
    private List<TreeItemDisplay> itemsSelected = new List<TreeItemDisplay>();
     
    private void DataSelectorItemSelected(object sender, RoutedEventArgs e)
            {
                TreeView treeView = (TreeView)e.Source;
                TreeItemDisplay tidSelected = (TreeItemDisplay)treeView.SelectedItem;
     
                if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)) {
                    if (!tidSelected.IsSelected) {
                        tidSelected.IsSelected = true;
                        itemsSelected.Add(tidSelected);
                    } else {
                        tidSelected.IsSelected = false;
                        itemsSelected.Remove(tidSelected);
                    }
                } else {
                    foreach (TreeItemDisplay tid in itemsSelected) {
                        tid.IsSelected = false;
                    }
                    itemsSelected.Clear();
                    //Si on avait sélectionné un tid (et non pas vider la treeview)
                    if (tidSelected != null) {
                        tidSelected.IsSelected = true;
                        itemsSelected.Add(tidSelected);
                    }
                }
    }

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

Discussions similaires

  1. multiselection dans un treeview
    Par new_wave dans le forum Windows Forms
    Réponses: 4
    Dernier message: 13/04/2007, 14h34
  2. [VB.net] Drag and drop dans une Treeview
    Par gégécap dans le forum Windows Forms
    Réponses: 2
    Dernier message: 19/10/2006, 10h05
  3. [VB.NET] Faire une recherche dans une treeview
    Par Aspic dans le forum VB.NET
    Réponses: 3
    Dernier message: 15/11/2005, 19h10
  4. Supprimer des éléments dans une TreeView ?
    Par souch dans le forum Composants VCL
    Réponses: 4
    Dernier message: 16/09/2005, 12h20

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