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 :

datagrid group expand et ICollectionView.refresh()


Sujet :

Windows Presentation Foundation

  1. #1
    Membre régulier
    Homme Profil pro
    Inscrit en
    Mars 2007
    Messages
    244
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations forums :
    Inscription : Mars 2007
    Messages : 244
    Points : 122
    Points
    122
    Par défaut datagrid group expand et ICollectionView.refresh()
    Salut à toutes et à tous,

    Je cherche depuis pas mal de temps et je ne trouve pas, or je suis sûr que je ne suis pas le premier à avoir besoin de cela.

    Soit un daragrid liée par son ItemsSource à une ICollectionView triée.

    Soit certains groupes étendus et d'autres refermés.

    Si je modifie une données via le code, le ICollectionView ne reste pas trié.

    Je dois donc faire un ICollectionView.refresh(), ce qui a pour effet de refermer (ou de rouvrir, selon comment ils sont défini par défaut) tous les groupes. Or j'ai besoin que les groupes resent comme ils étaient au moment du refresh (ou mieux, d'éviter de devoir faire le refresh parce que le ICollectionView resterait trié, mais à ce que j'ai lu ça n'a pas l'air possible).

    Merci de vos z'avis z'avisés,
    JM
    Il n'y a pas de problèmes. Il n'y a que des solutions.
    Malheureusement, elles sont parfois un peu dur à trouver ...


    Aucune touche n'a été maltraitée pour réaliser ce texte.

  2. #2
    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 : 42
    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 749
    Points
    39 749
    Par défaut
    Quelle version de .NET ? Depuis 4.5, WPF supporte le "live shaping", c'est à dire que le tri, les filtres et le groupement sont maintenus quand les données changent :
    http://msdn.microsoft.com/en-us/libr...x#live_shaping

    Par contre il faut l'activer explicitement

  3. #3
    Membre régulier
    Homme Profil pro
    Inscrit en
    Mars 2007
    Messages
    244
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations forums :
    Inscription : Mars 2007
    Messages : 244
    Points : 122
    Points
    122
    Par défaut
    Merci tomlev,

    Ça fonctionne bien en général, mais dans un cas la mise à jour ne se fait pas.
    Il doit me manquer qqch mais je ne comprend pas ce qu'il me manque.

    Le datagrid est lié à une ObservableCollection de Matériel (dont la classe est écrite ci-dessous) à laquelle j'ai ajouté un LiveShaping.
    Le datagrid se précente comme suit :
    groupement de premier niveau sur la catégorie, et de second niveau sur la description
    les lignes standards montrent le détail, le dernier lieu et la date de dernier lieu de chaque matériel

    Quand il y a plusieurs matériels identiques, ils se classent donc dans le datagrid par LocalisationDate


    Si j'ajoute du matériel le live shaping fonctionne bien.

    Par contre, chaque matériel contient une autre ObservableCollection contenant un historique de lieu ainsi qu'une propriété LocalisationLieu (qui dit le dernier endroit où le matériel a été envoyé) et une popriété LocalisationDate (qui dit quand le matériel a été envoyé à LocalisationLieu). Si j'ajoute un élément dans cette liste, la datagrid ne se met pas à jour.
    Vu le codage de la classe Matériel, il me semble que lorsque j'ajouter une nouvelle localisation dans HistoriqueLocalisation, l'objet Matériel retourne une notification de modification, donc l'ObservableCollection ListeMatériel doit se mettre à jour via le live shaping.

    J'ai fais comme ceci :

    MainWindow.cs
    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
     
    ListeMatériel listeMatériel = new ListeMatériel();
    MatérielDataGrid.ItemsSource = listeMatériel;
     
     
    ICollectionView icvMatériels = CollectionViewSource.GetDefaultView(listeMatériel);
    icvMatériels.Culture = System.Globalization.CultureInfo.GetCultureInfo("fr-FR");
    if (icvMatériels != null && icvMatériels.CanGroup == true)
    {
        icvMatériels.GroupDescriptions.Clear();
        icvMatériels.GroupDescriptions.Add(new PropertyGroupDescription("Catégorie"));
        icvMatériels.GroupDescriptions.Add(new PropertyGroupDescription("Description"));
    }
    if (icvMatériels != null && icvMatériels.CanSort == true)
    {
        icvMatériels.SortDescriptions.Clear();
        icvMatériels.SortDescriptions.Add(new SortDescription("Catégorie", ListSortDirection.Ascending));
        icvMatériels.SortDescriptions.Add(new SortDescription("Description", ListSortDirection.Ascending));
        icvMatériels.SortDescriptions.Add(new SortDescription("Détails", ListSortDirection.Ascending));
        icvMatériels.SortDescriptions.Add(new SortDescription("LocalisationDate", ListSortDirection.Ascending));
    }
    ICollectionViewLiveShaping icvMatérielsLiveShaping = (ICollectionViewLiveShaping)CollectionViewSource.GetDefaultView(listeMatériel);
    icvMatérielsLiveShaping.IsLiveGrouping = true;
    icvMatérielsLiveShaping.IsLiveSorting=true;
    Classe Matériel
    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
    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
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
    334
    335
    336
    337
    338
    339
    340
    341
    342
    343
    344
    345
    346
    347
    348
    349
    350
    351
    352
    353
    354
    355
    356
    357
    358
    359
    360
    361
    362
    363
    364
    365
    366
    367
    368
    369
    370
    371
    372
    373
    374
    375
    376
    377
    378
    379
    380
    381
    382
    383
    384
    385
    386
     
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.IO;
    using System.Linq;
    using System.Runtime.Serialization.Formatters.Binary;
    using System.Text;
    using System.Threading.Tasks;
     
     
    namespace ApplicationQM
    {
        public class ListeMatériel : MatérielObservableCollection<Matériel>
        {
        }
     
     
        public class Catégories : CatégoriesObservableCollection<string>
        {
        }
     
     
        [Serializable]
        public class Matériel : INotifyPropertyChanged
        {
            private string catégorie;
            private string description;
            private string codeBarre;
            private string détails;
            private ObservableCollection<Localisation> historiqueLocalisation;
     
     
            public event PropertyChangedEventHandler PropertyChanged;
     
     
            /// <summary>
            /// Catégorie dans laquelle se trouve le matériel
            /// </summary>
            public string Catégorie
            {
                get { return catégorie; }
                set
                {
                    //Valeur par défaut
                    if (string.IsNullOrEmpty(value))
                        catégorie = "Autre";
                    else
                        catégorie = value;
                    OnPropertyChanged("Catégorie");
                }
            }
     
     
            /// <summary>
            /// Descritpion du matériel
            /// </summary>
            public string Description
            {
                get { return description; }
                set
                {
                    description = value;
                    OnPropertyChanged("Description");
                }
            }
     
     
            /// <summary>
            /// Code Barre du matériel
            /// </summary>
            public string CodeBarre
            {
                get { return codeBarre; }
                set
                {
                    codeBarre = value;
                    OnPropertyChanged("CodeBarre");
                }
            }
     
     
            /// <summary>
            /// Détails du matériel
            /// </summary>
            public string Détails
            {
                get { return détails; }
                set
                {
                    détails = value;
                    OnPropertyChanged("Dtails");
                }
            }
     
     
            /// <summary>
            /// Liste des mouvements du matériel
            /// </summary>
            public ObservableCollection<Localisation> HistoriqueLocalisation
            {
                get { return historiqueLocalisation; }
                set
                {
                    historiqueLocalisation = value;
                    ICollectionView hView = System.Windows.Data.CollectionViewSource.GetDefaultView(this);
                    OnPropertyChanged("HistoriqueLocalisation");
                    OnPropertyChanged("Localisation");
                    OnPropertyChanged("LocalisationDate");
                }
            }
     
     
            public object Localisation
            {
                get
                {
                    List<Localisation> sortedLst = this.HistoriqueLocalisation.OrderBy(x => x.DateMouvement).ToList();
                    Localisation dernièreLocalisation = sortedLst[sortedLst.Count - 1];
                    if (dernièreLocalisation.Endroit.GetType() == typeof(string))
                        return dernièreLocalisation.Endroit as string;
                    else
                        return dernièreLocalisation.Endroit as Personne;
                }
            }
     
     
            public DateTime LocalisationDate
            {
                get
                {
                    List<Localisation> sortedLst = this.HistoriqueLocalisation.OrderBy(x => x.DateMouvement).ToList();
                    return sortedLst[sortedLst.Count - 1].DateMouvement;
                }
            }
     
     
            #region Constructeurs
            /// <summary>
            /// Création d'un matériel vide. L'objet sera placé au QM avec de DateTime actuel
            /// </summary>
            public Matériel()
            {
                this.HistoriqueLocalisation = new ObservableCollection<Localisation> { new Localisation(DateTime.Now, "QM") };
            }
     
     
            /// <summary>
            /// Création d'un objet. L'objet sera placé au QM avec de DateTime actuel
            /// </summary>
            /// <param name="description">description du matériel</param>
            /// <param name="description">détails du matériel</param>
            /// <param name="catégorie">catégorie dans laquelle se trouve le matériel</param>
            /// <param name="codeBarre">code barre du matériel</param>
            public Matériel(string description, string détails = null, string catégorie = "Autre", string codeBarre = null)
            {
                this.Description = description;
                this.CodeBarre = codeBarre;
                this.Catégorie = catégorie;
                this.Détails = détails;
                this.HistoriqueLocalisation = new ObservableCollection<Localisation> { new Localisation(DateTime.Now, "QM") };
            }
     
     
            /// <summary>
            /// Création d'un objet
            /// </summary>
            /// <param name="description">description du matériel</param>
            /// <param name="dateMouvement">date à laquelle le matériel a été placé à sa localiation</param>
            /// <param name="description">détails du matériel</param>
            /// <param name="catégorie">catégorie dans laquelle se trouve le matériel</param>
            /// <param name="localisation">Endroit où est le matériel</param>
            /// <param name="codeBarre">code barre du matériel</param>
            public Matériel(string description, DateTime dateMouvement, string détails = null, string catégorie = "Autre", string localisation = "QM", string codeBarre = null)
            {
                this.Description = description;
                this.CodeBarre = codeBarre;
                this.Catégorie = catégorie;
                this.Détails = détails;
                this.HistoriqueLocalisation = new ObservableCollection<Localisation> { new Localisation(dateMouvement, localisation) };
            }
     
     
            /// <summary>
            /// Création d'un objet
            /// </summary>
            /// <param name="description">description du matériel</param>
            /// <param name="dateMouvement">date à laquelle le matériel a été attribué au Personne</param>
            /// <param name="description">détails du matériel</param>
            /// <param name="catégorie">catégorie dans laquelle se trouve le matériel</param>
            /// <param name="localisation">Personne chez qui est le matériel</param>
            /// <param name="codeBarre">code barre du matériel</param>
            public Matériel(string description, DateTime dateMouvement, Personne Personne, string détails = null, string catégorie = "Autre", string localisation = "QM", string codeBarre = null)
            {
                this.Description = description;
                this.CodeBarre = codeBarre;
                this.Catégorie = catégorie;
                this.Détails = détails;
                this.HistoriqueLocalisation = new ObservableCollection<Localisation> { new Localisation(dateMouvement, Personne) };
                Personne.Matériel.Add(this);
            }
            #endregion
     
     
            public void MouvementMatériel(DateTime dateMouvement, Personne personne)
            {
                List<Localisation> sortedLst = this.HistoriqueLocalisation.OrderBy(x => x.DateMouvement).ToList();
                Localisation dernièreLocalisation = this.HistoriqueLocalisation[sortedLst.Count - 1];
                if (this.Localisation.GetType() == typeof(Personne) && this.Localisation == personne)
                    throw new Exception(string.Format("Ce matériel est déjà détenu par cette Personne depuis le {0:dd MMM yyyy}", dernièreLocalisation.DateMouvement));
                this.HistoriqueLocalisation.Add(new Localisation(dateMouvement, personne));
                personne.Matériel.Add(this);
            }
     
     
            public void MouvementMatériel(DateTime dateMouvement, string localisation = "QM")
            {
                if (this.Localisation.GetType() == typeof(string) && this.Localisation.ToString() == localisation)
                    throw new Exception(string.Format("Ce matériel se trouve déjà à cet emplacement depuis le {0:dd MMM yyyy}", this.LocalisationDate));
                else if (this.Localisation.GetType() == typeof(Personne))
                    (this.Localisation as Personne).Matériel.Remove(this);
                this.HistoriqueLocalisation.Add(new Localisation(dateMouvement, localisation));
            }
     
     
            protected void OnPropertyChanged(string name)
            {
                PropertyChangedEventHandler handler = PropertyChanged;
                if (handler != null)
                {
                    handler(this, new PropertyChangedEventArgs(name));
                }
            }
       }
     
     
        [Serializable]
        public class Localisation : IComparable
        {
            public Object Endroit { get; set; }
            public DateTime DateMouvement { get; set; }
     
            public Localisation(DateTime dateMouvement, string localisation)
            {
                this.DateMouvement = dateMouvement;
                this.Endroit = localisation;
            }
     
     
            public Localisation(DateTime dateMouvement, Personne personne)
            {
                this.DateMouvement = dateMouvement;
                this.Endroit = personne;
            }
     
     
            public override bool Equals(object obj)
            {
                if (obj == null) return false;
                Localisation localisation = obj as Localisation;
                if (localisation == null) return false;
                else return this.DateMouvement.Equals(localisation.DateMouvement);
            }
     
     
            public override int GetHashCode()
            {
                return base.GetHashCode();
            }
     
     
            public int SortByDateMouvementAscending(DateTime dateMouvement1, DateTime dateMouvement2)
            {
     
     
                return dateMouvement1.CompareTo(dateMouvement2);
            }
     
     
            public int SortByDateMouvementDescending(DateTime dateMouvement1, DateTime dateMouvement2)
            {
     
     
                return dateMouvement2.CompareTo(dateMouvement1);
            }
     
     
            // Comparaison par défaut.
            public int CompareTo(object compareLocalisation)
            {
                if (compareLocalisation.GetType() != typeof(Localisation))
                    throw new TypeAccessException("Le type ne correspond pas à Localisation");
                Localisation localisationAComprer = compareLocalisation as Localisation;
                return this.DateMouvement.CompareTo(localisationAComprer.DateMouvement);
            }
        }
     
     
        public class MatérielObservableCollection<T> : ObservableCollection<Matériel>
        {
            private static BinaryFormatter formatter = null;
     
     
            public void Save(string filePath)
            {
                List<Matériel> lstMatériel = this.ToList<Matériel>();
                System.Byte[] serialisedList;
                if (formatter == null) formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
                using (MemoryStream stream = new MemoryStream())
                {
                    formatter.Serialize(stream, lstMatériel);
                    serialisedList = stream.ToArray();
                }
                File.WriteAllBytes(filePath, serialisedList);
            }
     
     
            public void LoadFromSavedFile(string filePath)
            {
                this.Clear();
                this.AddFromSavedFile(filePath);
            }
     
     
            public void AddFromSavedFile(string filePath)
            {
                if (File.Exists(filePath))
                {
                    System.Byte[] dbByte = File.ReadAllBytes(filePath);
                    List<Matériel> lstMatériel = new List<Matériel>();
                    if (formatter == null) formatter = new BinaryFormatter();
                    using (MemoryStream stream = new MemoryStream(dbByte))
                    {
                        lstMatériel = (List<Matériel>)formatter.Deserialize(stream);
                    }
                    foreach (Matériel matériel in lstMatériel)
                        this.Add(matériel);
                }
            }
        }
     
     
        public class CatégoriesObservableCollection<T> : ObservableCollection<string>
        {
            private static BinaryFormatter formatter = null;
     
     
            public new void Add(string catégorie)
            {
                if (this.Contains(catégorie))
                    throw new TypeAccessException("Cette catégorie est déjà existante.");
                base.Add(catégorie);
            }
     
            public void Save(string filePath)
            {
                List<string> lstCatégories = this.ToList<string>();
                System.Byte[] serialisedList;
                if (formatter == null) formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
                using (MemoryStream stream = new MemoryStream())
                {
                    formatter.Serialize(stream, lstCatégories);
                    serialisedList = stream.ToArray();
                }
                File.WriteAllBytes(filePath, serialisedList);
            }
     
     
            public void AddFromSavedFile(string filePath)
            {
                if (File.Exists(filePath))
                {
                    System.Byte[] dbByte = File.ReadAllBytes(filePath);
                    List<string> lstCatégories = new List<string>();
                    if (formatter == null) formatter = new BinaryFormatter();
                    using (MemoryStream stream = new MemoryStream(dbByte))
                    {
                        lstCatégories = (List<string>)formatter.Deserialize(stream);
                    }
                    foreach (string catégorie in lstCatégories)
                        this.Add(catégorie);
                }
            }
        }
    }
    Il n'y a pas de problèmes. Il n'y a que des solutions.
    Malheureusement, elles sont parfois un peu dur à trouver ...


    Aucune touche n'a été maltraitée pour réaliser ce texte.

  4. #4
    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 : 42
    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 749
    Points
    39 749
    Par défaut
    Citation Envoyé par Jean-Marc68 Voir le message
    Vu le codage de la classe Matériel, il me semble que lorsque j'ajouter une nouvelle localisation dans HistoriqueLocalisation, l'objet Matériel retourne une notification de modification, donc l'ObservableCollection ListeMatériel doit se mettre à jour via le live shaping.
    Non, tu déclenches bien la notification quand on remplace HistoriqueLocalisation (dans le set de la propriété), mais pas quand on ajoute à la collection existante. Pour ça il faudrait que tu t'abonnes à l'évènement CollectionChanged de HistoriqueLocalisation, et que tu déclenches la notification pour les propriétés associées.

    De plus, il me semble (pas sûr) qu'il faut spécifier explicitement les propriétés prises en compte dans le live shaping (LiveSortingProperties, LiveFilteringProperties, LiveGroupingProperties).

  5. #5
    Membre régulier
    Homme Profil pro
    Inscrit en
    Mars 2007
    Messages
    244
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations forums :
    Inscription : Mars 2007
    Messages : 244
    Points : 122
    Points
    122
    Par défaut
    Grrrr je n'y arrive pas.

    En cherchant j'ai trouvé ta classe PropertyChangedObservableCollection que j'ai utilisée à la place de ObservableCollection dans les cas suivants

    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
     
           private PropertyChangedObservableCollection<Localisation> historiqueLocalisation;
     
           public PropertyChangedObservableCollection<Localisation> HistoriqueLocalisation
            {
                get { return historiqueLocalisation; }
                set
                {
                    historiqueLocalisation = value;
                    ICollectionView hView = System.Windows.Data.CollectionViewSource.GetDefaultView(this);
                    OnPropertyChanged("HistoriqueLocalisation");
                    OnPropertyChanged("Localisation");
                    OnPropertyChanged("LocalisationDate");
                }
            }
    et j'ai modifié la classe Localisation pour la rendre notifiable
    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
    [Serializable]    
    public class Localisation : IComparable, INotifyPropertyChanged
        {
            private object endroit;
            private DateTime dateMouvement;
     
     
            public event PropertyChangedEventHandler PropertyChanged;
     
     
            public Object Endroit
            {
                get
                {
                    return endroit;
                }
                set
                {
                    endroit = value;
                    OnPropertyChanged("Endroit");
                }
            }
     
     
            public DateTime DateMouvement
            {
                get
                {
                    return dateMouvement;
                }
                set
                {
                    dateMouvement = value;
                    OnPropertyChanged("DateMouvement");
                }
            }
    ...
    J'admet avoir du mal à comprendre comment je devrais m'abonner à CollectionChanged pour que les modifs dans HistoriqueLocalisation notifier le parent (Matériel).

    il me semble (pas sûr) qu'il faut spécifier explicitement les propriétés prises en compte dans le live shaping (LiveSortingProperties, LiveFilteringProperties, LiveGroupingProperties).

    Je ne pense pas, parce que si j'ajoute un Matériel, le datagrid se met à jour "en live".

    Comme une image vaut 1000 mots, je joins un petit visu :
    Nom : ObservableCollectionQuestion.jpg
Affichages : 226
Taille : 30,3 Ko
    Comme je disais, si j'ajoute un matériel, le datagrid se met à jour. Par contre, si j'ajoute une localisation à une des boussoles, le datagrid ne se met pas à jour.
    J'ai remarqué aussi que lors de l'ajout d'
    une localisation à une des boussoles, on ne passe pas par le convertisseur qui compte le nombre d'éléments au QM. Le groupe reste notifié à "boussole (15 dont 15 au QM)" alors qu'elle aurait du passer à "boussole (15 dont 14 au QM)" et la boussole déplacée devrait avoir son lieu au nouveau lieu et sa date à la nouvelle date.

    Le convertisseur:
    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
    public class GroupsToTotalQMConverter : IValueConverter    {
            public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                //System.Diagnostics.Debugger.Break();
                Type test = value.GetType();
                if (value is System.Windows.Data.CollectionViewGroup && parameter is string)
                {
     
     
                    System.Windows.Data.CollectionViewGroup group = value as System.Windows.Data.CollectionViewGroup;
                    //return (value as MatérielObservableCollection<Matériel>).Count(x => x.Description == parameter.ToString() && x.Localisation.ToString() == "QM");
     
     
                    var items = (value as System.Windows.Data.CollectionViewGroup).Items;
                    Decimal totalQM = 0;
                    foreach (var item in items)
                    {
                        if (item is Matériel)
                        {
                            if (item != null && (item as Matériel).LocalisationLieu.ToString() == "QM")
                                totalQM++;
                            continue;
                        }
     
     
                        var lastLevel = item;
                        while (!(lastLevel as System.Windows.Data.CollectionViewGroup).IsBottomLevel)
                        {
                            lastLevel = (lastLevel as System.Windows.Data.CollectionViewGroup).Items;
                        }
                        ReadOnlyObservableCollection<Object> elements = (lastLevel as System.Windows.Data.CollectionViewGroup).Items;
                        foreach (var element in elements)
                        {
                            Matériel materiel = element as Matériel;
                            if (materiel != null && materiel.LocalisationLieu.ToString() == "QM")
                                totalQM++;
                        }
                    }
                    return totalQM.ToString();
     
     
                }
                return "0";
     
            }


    Par contre, tout fonctionne correctement si je fais un refresh sur le
    ICollectionView.
    Il n'y a pas de problèmes. Il n'y a que des solutions.
    Malheureusement, elles sont parfois un peu dur à trouver ...


    Aucune touche n'a été maltraitée pour réaliser ce texte.

  6. #6
    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 : 42
    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 749
    Points
    39 749
    Par défaut
    Citation Envoyé par Jean-Marc68 Voir le message
    En cherchant j'ai trouvé ta classe PropertyChangedObservableCollection que j'ai utilisée à la place de ObservableCollection dans les cas suivants
    Ma classe ? Ca me rappelle rien... tu as trouvé ça où ?

    Citation Envoyé par Jean-Marc68 Voir le message
    J'admet avoir du mal à comprendre comment je devrais m'abonner à CollectionChanged pour que les modifs dans HistoriqueLocalisation notifier le parent (Matériel).
    Abonne toi dans le setter (et n'oublie pas de te désabonner de l'ancienne collection) :

    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 ObservableCollection<Localisation> HistoriqueLocalisation
            {
                get { return historiqueLocalisation; }
                set
                {
                    if (historiqueLocalisation != null)
                        historiqueLocalization.CollectionChanged -= HistoriqueLocalizationCollectionChanged;
     
     
                    historiqueLocalisation = value;
                    historiqueLocalization.CollectionChanged += HistoriqueLocalizationCollectionChanged;
                    ICollectionView hView = System.Windows.Data.CollectionViewSource.GetDefaultView(this);
                    OnPropertyChanged("HistoriqueLocalisation");
                    OnPropertyChanged("Localisation");
                    OnPropertyChanged("LocalisationDate");
                }
            }
     
            private void HistoriqueLocalizationCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
            {
                // Notifier les propriétés qui dépendent du contenu de HistoriqueLocalisation
                OnPropertyChanged("Localisation");
                OnPropertyChanged("LocalisationDate");
            }

    Citation Envoyé par Jean-Marc68 Voir le message
    Je ne pense pas, parce que si j'ajoute un Matériel, le datagrid se met à jour "en live".
    Pour un nouvel élément oui, mais peut-être pas si tu modifies une propriété d'un élément existant

  7. #7
    Membre régulier
    Homme Profil pro
    Inscrit en
    Mars 2007
    Messages
    244
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations forums :
    Inscription : Mars 2007
    Messages : 244
    Points : 122
    Points
    122
    Par défaut
    Merci tomlev.

    J'en ai ramé un coup, or quand on te lit ça a l'air si simple. En en plus je comprend.

    Concernant la classe PropertyChangedObservableCollection<T>, J'ai trouvé ça ici : http://www.developpez.net/forums/d11...ectionchanged/ où Koyot3 dit
    Après tu peux générer une classe héritant de ObservableCollection pour le faire.
    tomlev (membre du forum) a fait un super truc pour ça, voici son code :


    Il me reste juste le converter par lequel je ne passe toujours pas.
    Vu ta remarque
    Pour un nouvel élément oui, mais peut-être pas si tu modifies une propriété d'un élément existant

    Je me suis dis que c'était à cause de cela.
    J'ai modifié comme ceci
    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
     
                ICollectionView icvMatériels = CollectionViewSource.GetDefaultView(listeMatériel);
                icvMatériels.Culture = System.Globalization.CultureInfo.GetCultureInfo("fr-FR");
                if (icvMatériels != null && icvMatériels.CanGroup == true)
                {
                    icvMatériels.GroupDescriptions.Clear();
                    icvMatériels.GroupDescriptions.Add(new PropertyGroupDescription("Catégorie"));
                    icvMatériels.GroupDescriptions.Add(new PropertyGroupDescription("Description"));
                }
                if (icvMatériels != null && icvMatériels.CanSort == true)
                {
                    icvMatériels.SortDescriptions.Clear();
                    icvMatériels.SortDescriptions.Add(new SortDescription("Catégorie", ListSortDirection.Ascending));
                    icvMatériels.SortDescriptions.Add(new SortDescription("Description", ListSortDirection.Ascending));
                    icvMatériels.SortDescriptions.Add(new SortDescription("Détails", ListSortDirection.Ascending));
                    icvMatériels.SortDescriptions.Add(new SortDescription("LocalisationDate", ListSortDirection.Ascending));
                }
                ICollectionViewLiveShaping icvMatérielsLiveShaping = (ICollectionViewLiveShaping)CollectionViewSource.GetDefaultView(listeMatériel);
                if (icvMatérielsLiveShaping.CanChangeLiveSorting)
                {
                    icvMatérielsLiveShaping.LiveGroupingProperties.Add("Catégorie");
                    icvMatérielsLiveShaping.LiveGroupingProperties.Add("Description");
                    icvMatérielsLiveShaping.LiveGroupingProperties.Add("Détails");
                    icvMatérielsLiveShaping.LiveGroupingProperties.Add("LocalisationDate");
                    icvMatérielsLiveShaping.IsLiveGrouping = true;
                }
                if (icvMatérielsLiveShaping.CanChangeLiveGrouping)
                {
                    icvMatérielsLiveShaping.LiveSortingProperties.Add("Catégorie");
                    icvMatérielsLiveShaping.LiveSortingProperties.Add("Description");
                    icvMatérielsLiveShaping.LiveSortingProperties.Add("Détails");
                    icvMatérielsLiveShaping.LiveSortingProperties.Add("LocalisationDate");
                    icvMatérielsLiveShaping.IsLiveSorting = true;
                }
    Vu que dans les 2 cas le CanChange me retourne true, donc je pensais que vu le live shaping j'allais y repasser, mais là encore je suis dans le champs. Serait-ce parce que le groupement n'est pas modifié, seulement les items en dessous ?

    A moins que la raison en soit toute autre, auquel cas je pense ouvrir une autre discussion, pour que quelqu'un qui aurait le même pbl plus tard, ait plus facile de trouver la réponse à sa question.
    Il n'y a pas de problèmes. Il n'y a que des solutions.
    Malheureusement, elles sont parfois un peu dur à trouver ...


    Aucune touche n'a été maltraitée pour réaliser ce texte.

  8. #8
    Membre régulier
    Homme Profil pro
    Inscrit en
    Mars 2007
    Messages
    244
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations forums :
    Inscription : Mars 2007
    Messages : 244
    Points : 122
    Points
    122
    Par défaut
    J'ai trouvé une classe que j'ai modifiée un peu pour que le ViewModel notifie la modification.
    Cela fonctionne et mon converter passe bien à chaque modification.

    Mais vu le NotifyCollectionChangedAction.Reset, tous les expander du datagrid reviennent à leur IsExpanded d'origine.
    Je voudrais arriver à ce que les expander déjà existants restent à leur IsExpanded au moment du reset. Je cherche depuis une semaine et je ne trouve pas.

    Quelqu'un aurait-il une idée ?

    Voici la classe de l'ObservableCollection modifiée
    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
    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
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
    334
    335
    336
    337
    338
    339
    340
    341
    342
    343
    344
    345
    346
    347
    348
    349
    350
    351
    352
    353
    354
    355
    356
    357
    358
    359
    360
    361
    362
    363
    364
    365
    366
    367
    368
    369
    370
    371
    372
    373
    374
    375
    376
    377
    378
    379
    380
    381
    382
    383
    384
    385
    386
    387
    388
    389
    390
    391
    392
    393
    394
    395
    396
    397
    398
    399
    400
    401
    402
    403
    404
    405
    406
    407
    408
    409
    410
    411
    412
    413
    414
    415
    416
    417
    418
    419
    420
    421
    422
    423
    424
    425
    426
    427
    428
    429
    430
    431
    432
    433
    434
    435
    436
    437
    438
    439
    440
    441
    442
    443
    444
    445
    446
    447
    448
    449
    450
    451
    452
    453
    454
    455
    456
    457
    458
    459
    460
    461
    462
    463
    464
    465
    466
    467
    468
    469
    470
    471
    472
    473
    474
    475
    476
    477
    478
    479
    480
    481
    482
    483
    484
    485
    486
    487
    488
    489
    490
    491
    492
    493
    494
    495
    496
    497
    498
    499
    500
    501
    502
    503
    504
    505
    506
    507
    508
    509
    510
    511
    512
    513
    514
    515
    516
    517
    518
    519
    520
    521
    522
    523
    524
    525
    526
    527
    528
    529
    530
    531
    532
    533
    534
    535
    536
    537
    538
    539
    540
    541
    542
    543
    544
    545
    546
    547
    548
    549
    550
    551
    552
    553
    554
    555
    556
    557
    558
    559
    560
    561
    562
    563
    564
    565
    566
    567
    568
    569
    570
    571
    572
    573
    574
    575
    576
    577
    578
    579
    580
    581
    582
    583
    584
    585
    586
    587
    588
    589
    590
    591
    592
    593
    594
    595
    596
    597
    598
    599
    600
    601
    602
    603
    604
    605
    606
    607
    608
    609
    610
    611
    612
    613
    614
    615
    616
    617
    618
    619
    620
    621
    622
    623
    624
    625
    626
    627
    628
    629
    630
    631
    632
    633
    634
    635
    636
    637
    638
    639
    640
    641
    642
    643
    644
    645
    646
    647
    648
    649
    650
    651
    652
    653
    654
    655
    656
    657
    658
    659
    660
    661
    662
    663
    664
    665
    666
    667
    668
    669
    670
    671
    672
    673
    674
    675
    676
    677
    678
    679
    680
    681
    682
    683
    684
    685
    686
    687
    688
    689
    690
    691
    692
    693
    694
    695
    696
    697
    698
    699
    700
    701
    702
    703
    704
    705
    706
    707
    708
    709
    710
    711
    712
    713
    714
    715
    716
    717
    718
    719
    720
    721
    722
    723
    724
    725
    726
    727
    728
    729
    730
    731
    732
    733
    734
    735
    736
    737
    738
    739
    740
    741
    742
    743
    744
    745
    746
    747
    748
    749
    750
    751
    752
    753
    754
    755
    756
     
    using System.Collections.Generic;
    using System.Collections.Specialized;
    using System.ComponentModel;
    using System.Linq;
    using System.Linq.Expressions;
    using System.Threading;
    using System.Windows.Threading;
     
     
    namespace System.Collections.ObjectModel
    {
        public class ObservableCollectionEx<T>
            : IList<T>, IList
            , INotifyCollectionChanged
            , INotifyPropertyChanged
              where T : INotifyPropertyChanged
        {
            #region Fields
     
     
            private readonly IList<T> collection = new List<T>();
            private readonly Dispatcher dispatcher;
            private readonly ReaderWriterLock sync = new ReaderWriterLock();
            private readonly List<T> _InternalList = new List<T>();
     
            [NonSerialized]
            private object _syncRoot;
     
     
            #endregion
     
     
            #region Constructors
     
     
            public ObservableCollectionEx()
            {
                dispatcher = Dispatcher.CurrentDispatcher;
            }
     
     
            public ObservableCollectionEx(IEnumerable<T> createFrom)
                : this()
            {
                Source = createFrom;
            }
     
     
            #endregion
     
     
            #region Properties
     
     
            #region Filter
     
     
            private Func<T, bool> _Filter;
     
     
            public Func<T, bool> Filter
            {
                get { return _Filter; }
                set
                {
                    //ignore if values are equal
                    if (value == _Filter) return;
     
     
                    _Filter = value;
     
     
                    ApplyFilter();
     
     
                    RaisePropertyChanged(() => Filter);
                }
            }
     
     
            #endregion
     
     
            #region Source
     
     
            private IEnumerable<T> _Source;
     
     
            public IEnumerable<T> Source
            {
                get
                {
                    return _Source;
                }
                set
                {
                    //ignore if values are equal
                    if (value == _Source) return;
     
     
                    if (_Source is INotifyCollectionChanged)
                        (_Source as INotifyCollectionChanged).CollectionChanged -= Source_CollectionChanged;
     
     
                    _Source = value;
     
     
                    InitFrom(_Source);
     
     
                    if (_Source is INotifyCollectionChanged)
                        (_Source as INotifyCollectionChanged).CollectionChanged += Source_CollectionChanged;
     
     
                    RaisePropertyChanged(() => Source);
                }
            }
     
     
            #endregion
     
     
            #endregion
     
     
            #region Methods
     
     
            public void Add(T item)
            {
                if (Thread.CurrentThread == dispatcher.Thread)
                    DoAdd(item);
                else
                    dispatcher.BeginInvoke((Action)(() => DoAdd(item)));
            }
     
     
            private int DoAdd(T item)
            {
                sync.AcquireWriterLock(Timeout.Infinite);
     
     
                var index = DoAddInternal(item, true);
     
     
                sync.ReleaseWriterLock();
     
     
                return index;
            }
     
     
            private int DoAddInternal(T item, bool attachMonitorChanges)
            {
                // Attach to PropertyChanged event for monitoring future properties' changes
                if (attachMonitorChanges)
                    AttachPropertyChanged(item);
     
     
                // Check if it should be here
                if (!ShouldBeHere(item))
                    return -1;
     
     
                // Add item to collection
                var index = collection.Count;
                collection.Add(item);
     
     
                // Notify about collection's changes
                RaisePropertyChanged(() => Count);
                RaisePropertyChanged("Item[]");
                RaiseCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, index));
     
     
                return index;
            }
     
     
            public int Add(object item)
            {
                if (Thread.CurrentThread == dispatcher.Thread)
                    return DoAdd((T)item);
                else
                {
                    var op = dispatcher.BeginInvoke(new Func<T, int>(DoAdd), item);
                    if (op == null || op.Result == null)
                        return -1;
                    return (int)op.Result;
                }
            }
     
     
            public bool Contains(object value)
            {
                return Contains((T) value);
            }
     
     
            public void Clear()
            {
                if (Thread.CurrentThread == dispatcher.Thread)
                    DoClear();
                else
                    dispatcher.BeginInvoke((Action)(DoClear));
            }
     
     
            public int IndexOf(object value)
            {
                return IndexOf((T) value);
            }
     
     
            public void Insert(int index, object value)
            {
                Insert(index, (T)value);
            }
     
     
            public void Remove(object value)
            {
                Remove((T) value);
            }
     
     
            private void DoClear()
            {
                sync.AcquireWriterLock(Timeout.Infinite);
     
     
                DoClearInternal();
     
     
                sync.ReleaseWriterLock();
            }
     
     
            private void DoClearInternal()
            {
                // Detach from PropertyChanged events
                foreach (var item in _InternalList.ToArray())
                    DetachPropertyChanged(item);
     
     
                // Clear collection
                collection.Clear();
     
     
                // Notify about collection's changes
                RaisePropertyChanged(() => Count);
                RaisePropertyChanged("Item[]");
                RaiseCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
            }
     
     
            public bool Contains(T item)
            {
                sync.AcquireReaderLock(Timeout.Infinite);
                var result = ContainsInternal(item);
                sync.ReleaseReaderLock();
                return result;
            }
     
     
            private bool ContainsInternal(T item)
            {
                return collection.Contains(item);
            }
     
     
            public void CopyTo(T[] array, int arrayIndex)
            {
                sync.AcquireWriterLock(Timeout.Infinite);
                collection.CopyTo(array, arrayIndex);
                sync.ReleaseWriterLock();
            }
     
     
            public void CopyTo(Array array, int index)
            {
                sync.AcquireWriterLock(Timeout.Infinite);
                for (var i = 0; i < collection.Count; i ++)
                {
                    array.SetValue(collection[i], index + i);
                }
                sync.ReleaseWriterLock();
            }
     
     
            public int Count
            {
                get
                {
                    sync.AcquireReaderLock(Timeout.Infinite);
                    var result = collection.Count;
                    sync.ReleaseReaderLock();
                    return result;
                }
            }
     
     
            public object SyncRoot
            {
                get
                {
                    if (_syncRoot == null)
                    {
                        var c = collection as ICollection;
                        if (c != null)
                            _syncRoot = c.SyncRoot;
                        else
                            Interlocked.CompareExchange<object>(ref _syncRoot, new object(), null);
                    }
                    return _syncRoot;
                }
            }
     
     
            public bool IsSynchronized
            {
                get { return false; }
            }
     
     
            public bool IsReadOnly
            {
                get
                {
                    return false;
                }
            }
     
     
            public bool IsFixedSize
            {
                get { return false; }
            }
     
     
            public bool Remove(T item)
            {
                if (Thread.CurrentThread == dispatcher.Thread)
                    return DoRemove(item);
                else
                {
                    var op = dispatcher.BeginInvoke(new Func<T, bool>(DoRemove), item);
                    if (op == null || op.Result == null)
                        return false;
                    return (bool)op.Result;
                }
            }
     
     
            private bool DoRemove(T item)
            {
                sync.AcquireWriterLock(Timeout.Infinite);
     
     
                var result = DoRemoveInternal(item, true);
     
     
                sync.ReleaseWriterLock();
     
     
                return result;
            }
     
     
            private bool DoRemoveInternal(T item, bool detachMonitorChanges)
            {
                // Check if item is still at collection
                var index = collection.IndexOf(item);
                if (index == -1)
                    return false;
     
     
                // Detach from PropertyChanged event
                if (detachMonitorChanges)
                    DetachPropertyChanged(item);
     
     
                // Remove item from collection
                var result = collection.Remove(item);
     
     
                // Notify about collection's changes
                if (result)
                {
                    RaisePropertyChanged(() => Count);
                    RaisePropertyChanged("Item[]");
                    RaiseCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item,
                                                                                index));
                }
     
     
                return result;
            }
     
     
            public IEnumerator<T> GetEnumerator()
            {
                return collection.GetEnumerator();
            }
     
     
            System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
            {
                return collection.GetEnumerator();
            }
     
     
            public int IndexOf(T item)
            {
                sync.AcquireReaderLock(Timeout.Infinite);
                var result = collection.IndexOf(item);
                sync.ReleaseReaderLock();
                return result;
            }
     
     
            public void Insert(int index, T item)
            {
                if (Thread.CurrentThread == dispatcher.Thread)
                    DoInsert(index, item);
                else
                    dispatcher.BeginInvoke((Action)(() => DoInsert(index, item)));
            }
     
     
            private void DoInsert(int index, T item)
            {
                sync.AcquireWriterLock(Timeout.Infinite);
     
     
                // Attach to PropertyChanged event for monitoring future properties' changes
                AttachPropertyChanged(item);
     
     
                // Check if it should be here
                if (!ShouldBeHere(item))
                    return;
     
     
                // Insert item in collection
                collection.Insert(index, item);
     
                // Notify about collection's changes
                RaisePropertyChanged(() => Count);
                RaisePropertyChanged("Item[]");
                RaiseCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, index));
     
                sync.ReleaseWriterLock();
            }
     
     
            public void RemoveAt(int index)
            {
                if (Thread.CurrentThread == dispatcher.Thread)
                    DoRemoveAt(index);
                else
                    dispatcher.BeginInvoke((Action)(() => DoRemoveAt(index)));
            }
     
     
            object IList.this[int index]
            {
                get { return this[index]; }
                set { this[index] = (T)value; }
            }
     
     
            private void DoRemoveAt(int index)
            {
                sync.AcquireWriterLock(Timeout.Infinite);
     
                if (collection.Count == 0 || collection.Count <= index)
                {
                    sync.ReleaseWriterLock();
                    return;
                }
     
     
                var item = collection[index];
     
     
                // Detach from PropertyChanged event
                DetachPropertyChanged(item); 
     
                // Remove item from collection
                collection.RemoveAt(index);
     
     
                // Notify about collection's changes
                RaisePropertyChanged(() => Count);
                RaisePropertyChanged("Item[]");
                RaiseCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item, index));
     
                sync.ReleaseWriterLock();
     
     
            }
     
     
            public T this[int index]
            {
                get
                {
                    sync.AcquireReaderLock(Timeout.Infinite);
                    var result = collection[index];
                    sync.ReleaseReaderLock();
                    return result;
                }
                set
                {
                    sync.AcquireWriterLock(Timeout.Infinite);
     
                    if (collection.Count == 0 || collection.Count <= index)
                    {
                        sync.ReleaseWriterLock();
                        return;
                    }
     
     
                    var oldItem = collection[index];
     
     
                    DetachPropertyChanged(oldItem);
                    AttachPropertyChanged(value);
     
     
                    if (ShouldBeHere(value))
                    {
                        collection[index] = value;
     
     
                        // Notify about collection's changes
                        RaisePropertyChanged("Item[]");
                        RaiseCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, value, oldItem, index));
                    }
                    else
                    {
                        //
                        // Remove current item from collection
                        //
     
     
                        // Detach from PropertyChanged event
                        DetachPropertyChanged(oldItem);
     
     
                        // Remove item from collection
                        collection.RemoveAt(index);
     
     
                        // Notify about collection's changes
                        RaisePropertyChanged(() => Count);
                        RaisePropertyChanged("Item[]");
                        RaiseCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, oldItem, index));
                    }
     
     
                    sync.ReleaseWriterLock();
                }
            }
     
     
            #region Internal methods
     
     
            private void AttachPropertyChanged(T item)
            {
                _InternalList.Add(item);
                if (item is INotifyPropertyChanged)
                {
                    (item as INotifyPropertyChanged).PropertyChanged += Item_PropertyChanged;
                    (item as INotifyPropertyChanged).PropertyChanged += EntityViewModelPropertyChanged;
                }
            }
     
     
            private void DetachPropertyChanged(T item)
            {
                _InternalList.Remove(item);
                if (item is INotifyPropertyChanged)
                {
                    (item as INotifyPropertyChanged).PropertyChanged -= Item_PropertyChanged;
                    (item as INotifyPropertyChanged).PropertyChanged -= EntityViewModelPropertyChanged;
                }
            }
     
     
            private void Item_PropertyChanged(object sender, PropertyChangedEventArgs e)
            {
                sync.AcquireWriterLock(Timeout.Infinite);
     
     
                var item = (T) sender;
     
     
                var containsAfter = ApplyFilter(item);
     
     
                if (containsAfter)
                    if (ItemPropertyChanged != null)
                        ItemPropertyChanged(sender, e);
     
     
                sync.ReleaseWriterLock();
            }
     
     
            private bool ApplyFilter(T item)
            {
                var contains = ContainsInternal(item);
                var containsAfter = contains;
     
     
                if (ShouldBeHere(item))
                {
                    if (!contains)
                    {
                        DoAddInternal(item, false);
                        containsAfter = true;
                    }
                }
                else
                {
                    if (contains)
                    {
                        DoRemoveInternal(item, false);
                        containsAfter = false;
                    }
                }
                return containsAfter;
            }
     
     
            private bool ShouldBeHere(T item)
            {
                return (Filter == null) || Filter(item);
            }
     
     
            private void RaisePropertyChanged<TSource>(Expression<Func<TSource>> propertyExpression)
            {
                var propertyName = ((MemberExpression)propertyExpression.Body).Member.Name;
                RaisePropertyChanged(propertyName);
            }
     
     
            private void RaisePropertyChanged(string propertyName)
            {
                if (PropertyChanged != null)
                    PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
     
     
            private void InitFrom(IEnumerable<T> source)
            {
                if (source == null)
                {
                    Clear();
                    return;
                }
     
     
                sync.AcquireWriterLock(Timeout.Infinite);
     
     
                foreach (var item in source)
                {
                    DoAddInternal(item, true);
                }
     
                sync.ReleaseWriterLock();
            }
     
     
            private void RaiseCollectionChanged(NotifyCollectionChangedEventArgs e)
            {
                if (CollectionChanged != null)
                    CollectionChanged(this, e);
            }
     
     
            public void ApplyFilter()
            {
                sync.AcquireWriterLock(Timeout.Infinite);
     
     
                foreach (var item in _InternalList)
                {
                    ApplyFilter(item);
                }
     
     
                sync.ReleaseWriterLock();
            }
            #endregion
     
     
            #endregion
     
     
            #region Events
     
     
            public event NotifyCollectionChangedEventHandler CollectionChanged;
            public event PropertyChangedEventHandler ItemPropertyChanged;
            public event PropertyChangedEventHandler PropertyChanged;
     
     
            #endregion
     
     
            #region Event handlers
     
     
            void Source_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
            {
                sync.AcquireWriterLock(Timeout.Infinite);
     
     
                if (e.OldItems != null)
                {
                    foreach (var oldItem in e.OldItems.OfType<T>())
                    {
                        DoRemoveInternal(oldItem, true);
                    }
                }
     
     
                if (e.NewItems != null)
                {
                    foreach (var newItem in e.NewItems.OfType<T>())
                    {
                        DoAddInternal(newItem, true);
                    }
                }
     
     
                sync.ReleaseWriterLock();
            }
     
     
            void EntityViewModelPropertyChanged(object sender, PropertyChangedEventArgs e)
            {
                NotifyCollectionChangedEventArgs args = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset);
                this.CollectionChanged(sender, args);
            }
            #endregion
        }
    }
    Il n'y a pas de problèmes. Il n'y a que des solutions.
    Malheureusement, elles sont parfois un peu dur à trouver ...


    Aucune touche n'a été maltraitée pour réaliser ce texte.

Discussions similaires

  1. MVVM, grid grouping expand/collaps ?
    Par ilanb dans le forum Ext JS / Sencha
    Réponses: 0
    Dernier message: 25/01/2015, 14h17
  2. Flex 2 : Grouping With DataGrid
    Par Sceener dans le forum Flex
    Réponses: 1
    Dernier message: 06/05/2010, 21h03
  3. Probleme Refresh Datagrid
    Par MrVentouse dans le forum Flex
    Réponses: 8
    Dernier message: 16/03/2010, 16h18
  4. [C#]datagrid & refresh
    Par manulemalin dans le forum ASP.NET
    Réponses: 2
    Dernier message: 04/12/2006, 10h14
  5. [VB.net] Refresh d'un datagrid au travers du dataAdapter
    Par WriteLN dans le forum Windows Forms
    Réponses: 5
    Dernier message: 14/06/2006, 10h39

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