Bonjour,

Dans uns liste de 50.000 éléments, je dois pouvoir sélectionner/désélectionner des éléments par le code.

J'ai d'abord tenté de le faire par l'UI. Par exemple, pour inverser une sélection:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
foreach (ListViewItem item in ListView_DB_Edit.Items)
        item.IsSelected = !item.IsSelected;
Pour ce faire, étant donné qu'évidemment j'utilisais la virtualisation, je devais passer par ItemContainerGenerator, cela donnait donc plutot:

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
foreach (DatabaseItems item in ListView_DB_Edit.Items) {
    ListViewItem listViewItem = TryCast(ListView_DB_Edit.ItemContainerGenerator.ContainerFromItem(item), ListViewItem);
    if (listViewItem != null) {
        listViewItem.IsSelected = !listViewItem.IsSelected;
    }   
}
Le problème c'est que quand on utilise la virtualisation, la méthode ItemContainerGenerator retourne 'null' pour les éléments qui ne sont pas visible...puisque dans ce cas le ListViewItem n'a pas encore été créé
(Ceci dit, je me demande quand même alors comment fonctionnent les méthodes SelectAll() et UnselectAll() du Framework...qui elles marchent parfaitement en virtualisation)

Je me suis dit alors que je devais plutôt gérer le IsSelected par une propriété de mes objets et binder le IsSelected du ListViewItem à cette propriété.
Cela marche parfaitement bien!

Le problème
Le problème arrive quand on veut mixer une sélection par le code avec une sélection manuelle.
Dans le clip suivant, on voit comment, après avoir fait une sélection par le code, puis ensuite y ajouter une sélection manuelle en utilisant les raccourcis de Windows (Combinaison de Ctrl et Shift pour ajouter à la sélection), puis tenter de faire une inversion de sélection, les éléments sélectionnés "manuellement"...le restent!

C'est ici que j'en suis...et je n'arrive pas à voir ce qui coince et comment je pourrais y remédier !?

Voici le code complet créer pour cet exemple
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
<Window x:Class="SelectionBinding.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:SelectionBinding"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <ListView  VirtualizingStackPanel.IsVirtualizing="True" VirtualizingStackPanel.VirtualizationMode="Recycling" IsSynchronizedWithCurrentItem="True" IsTextSearchEnabled="True" TextSearch.TextPath="Name" x:Name="ListView_DB_Edit" Margin="10,10,0,58" HorizontalAlignment="Left" SelectionChanged="ListView_DB_Edit_OnSelectionChanged">
            <ListView.ItemContainerStyle>
                <Style TargetType="{x:Type ListViewItem}">
                    <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
                    <EventSetter Event="UIElement.PreviewMouseLeftButtonDown" Handler="ListviewItem_Click" />
                </Style>
            </ListView.ItemContainerStyle>
            <ListView.View>
                <GridView x:Name="GridView1">
                    <GridViewColumn DisplayMemberBinding="{Binding Id}" Width="100" >
                        <GridViewColumnHeader Content="Id"/>
                    </GridViewColumn>
                    <GridViewColumn DisplayMemberBinding="{Binding Number}" Width="100" >
                        <GridViewColumnHeader Content="Number"/>
                    </GridViewColumn>
                </GridView>
            </ListView.View>
        </ListView>
        <Button HorizontalAlignment="Left" VerticalAlignment="Top" Width="140" Height="30" Margin="250,10,0,0" Content="Select All" Click="SelectAll_Click"></Button>
        <Button HorizontalAlignment="Left" VerticalAlignment="Top" Width="140" Height="30" Margin="250,50,0,0" Content="Unselect All" Click="UnselectAll_Click"></Button>
        <Button HorizontalAlignment="Left" VerticalAlignment="Top" Width="140" Height="30" Margin="250,90,0,0" Content="Invert Selection" Click="InvertSel_Click"></Button>
        <Button HorizontalAlignment="Left" VerticalAlignment="Top" Width="140" Height="30" Margin="250,130,0,0" Content="Select Range 2-9" Click="SelRange_Click"></Button>
        <Label x:Name="StatsLabel" Margin="10,0,10,30" FontSize="18" VerticalAlignment="Bottom" Padding="0"/>
        <Label x:Name="StatsLabel2" Margin="10,0,10,5" FontSize="18" VerticalAlignment="Bottom" Padding="0" />
    </Grid>
</Window>
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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
 
 
namespace SelectionBinding
{
    public partial class MainWindow : Window
    {
        private ObservableCollection<DBitem> db;
        Random rand = new Random();
 
        public MainWindow()
        {
            InitializeComponent();
 
            db = new ObservableCollection<DBitem>();
            for (int i = 0; i < 100; i++)
            {
                db.Add(new DBitem() { Id = i.ToString(), Number = rand.Next(101).ToString() });
            }
 
            ICollectionView icv = CollectionViewSource.GetDefaultView(db);
            //icv.SortDescriptions.Add(new SortDescription("Number", ListSortDirection.Ascending));
 
            ListView_DB_Edit.ItemsSource = icv;
            ListView_DB_Edit.SelectedItems.Clear();
        }
 
        public class DBitem : INotifyPropertyChanged
        {
            private string _id;
            public string Id
            {
                get { return _id; }
                set { _id = value; OnPropertyChanged("Id");}
            }
            public string _number;
            public string Number
            {
                get { return _number; }
                set { _number = value; OnPropertyChanged("Number");}
            }
            public bool _isselected;
            public bool IsSelected
            {
                get { return _isselected; }
                set { _isselected = value; OnPropertyChanged("IsSelected"); }
            }
 
            public event PropertyChangedEventHandler PropertyChanged;
            private void OnPropertyChanged(string nameProp)
            {
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameProp));
            }
        }
 
        private void SelectAll_Click(object sender, RoutedEventArgs e)
        {
            foreach (DBitem dbi in db)
            {
                dbi.IsSelected = true;
            }
            RefreshStats();
        }
 
        private void UnselectAll_Click(object sender, RoutedEventArgs e)
        {
            foreach (DBitem dbi in db)
            {
                dbi.IsSelected = false;
            }
            RefreshStats();
        }
 
        private void InvertSel_Click(object sender, RoutedEventArgs e)
        {
            foreach (DBitem dbi in db)
            {
                dbi.IsSelected = !dbi.IsSelected;
            }
            RefreshStats();
        }
 
        private void SelRange_Click(object sender, RoutedEventArgs e)
        {
            for (int i = 2; i < 10; i++)
            {
                db[i].IsSelected = true;
            }
            RefreshStats();
        }
 
        private void ListviewItem_Click(object sender, MouseButtonEventArgs e)
        {
            RefreshStats();
        }
 
        private void ListView_DB_Edit_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            RefreshStats();
        }
 
        private void RefreshStats()
        {
            string total = db.Count.ToString();
            int nbr = 0;
            foreach (DBitem item in db)
            {
                if (item.IsSelected) nbr += 1;
            }
            string selected = nbr.ToString();
            StatsLabel.Content = "Obects IsSelected: "+ selected + "|" + total;
            StatsLabel2.Content = "Listview selecteditems: " + ListView_DB_Edit.SelectedItems.Count.ToString();
        }
    }
}
Merci de m'avoir lu jusqu'ici...et de l'aide que vous voudrez bien m'apporter!!