Précédent   Forum du club des développeurs et IT Pro > Dotnet > Général Dotnet > Contribuez
Contribuez Proposez vos articles, cours, tutoriels, faq, sources pour .NET
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse
 
Outils de la discussion
Publicité
'
Vieux 22/02/2012, 17h57   #1
adaneels
Membre actif
 
Avatar de adaneels
 
Homme Arnaud DANEELS
Chef de projet MOA
Inscription : août 2006
Messages : 233
Détails du profil
Informations personnelles :
Nom : Homme Arnaud DANEELS
Âge : 33
Localisation : France

Informations professionnelles :
Activité : Chef de projet MOA

Informations forums :
Inscription : août 2006
Messages : 233
Points : 174
Points : 174
Envoyer un message via ICQ à adaneels Envoyer un message via MSN à adaneels Envoyer un message via Yahoo à adaneels Envoyer un message via Skype™ à adaneels
Par défaut .NET 4 : enrichir List<T> d'un évènement

Bonjour,

Juste pour faire part d'une chose qui peut être utile à certains et qui pourrait pourquoi pas entrer dans les contributions

J'ai eu besoin d'utiliser une liste qui lance un évènement avant suppression d'un ou plusieurs éléments de cette liste (à la manière des triggers en base de données).

J'ai donc créé ces deux classes :
Code :
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
  public class BeforeRemoveEventArgs : EventArgs
  {
    public BeforeRemoveEventArgs(object item)
    {
      this.item = item;
    }
 
    public object item;
  }
 
  public class ListTrigerred<T> : List<T>
  {
    public delegate void BeforeRemoveEventHandler(object sender, BeforeRemoveEventArgs e);
    public event BeforeRemoveEventHandler BeforeRemove;
 
    public new bool Remove(T item)
    {
      if (BeforeRemove != null)
      {
        List<T> l = new List<T>();
        l.Add(item);
        BeforeRemove(this, new BeforeRemoveEventArgs(l));
      }
 
      return base.Remove(item);
    }
 
    public new int RemoveAll(Predicate<T> match)
    {
      if (BeforeRemove != null)
        BeforeRemove(this, new BeforeRemoveEventArgs(this.FindAll(match)));
 
      return base.RemoveAll(match);
    }
  }
L'utilisation se fait comme suit :
Code :
1
2
3
4
5
6
7
8
 
    public ListTrigerred<Point> lsPoints = new ListTrigerred<Point>();
    lsPoints.BeforeRemove += delegate(object sender, BeforeRemoveEventArgs e)
      {
        List<Point> PointsToRemove = (List<Point>)e.item;
 
        // TODO : implémenter les actions à effectuer avant la suppression des points
      };
J'ai utilisé une méthode anonyme pour condenser le code mais vous pouvez bien évidemment utiliser une fonction ou autres!
Le type Point peut être remplacé par n'importe quel type.


Bon dév,
Arnaud D.
__________________
--
Arnaud DANEELS
adaneels est déconnecté   Envoyer un message privé Réponse avec citation 10
Vieux 22/02/2012, 18h09   #2
adaneels
Membre actif
 
Avatar de adaneels
 
Homme Arnaud DANEELS
Chef de projet MOA
Inscription : août 2006
Messages : 233
Détails du profil
Informations personnelles :
Nom : Homme Arnaud DANEELS
Âge : 33
Localisation : France

Informations professionnelles :
Activité : Chef de projet MOA

Informations forums :
Inscription : août 2006
Messages : 233
Points : 174
Points : 174
Envoyer un message via ICQ à adaneels Envoyer un message via MSN à adaneels Envoyer un message via Yahoo à adaneels Envoyer un message via Skype™ à adaneels
avec l'implémentation de RemoveRange et RemoveAt, c'est mieux :
Code :
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
 
  public class BeforeRemoveEventArgs : EventArgs
  {
    public BeforeRemoveEventArgs(object item)
    {
      this.item = item;
    }
 
    public object item;
  }
 
  public class ListTrigerred<T> : List<T>
  {
    public delegate void BeforeRemoveEventHandler(object sender, BeforeRemoveEventArgs e);
    public event BeforeRemoveEventHandler BeforeRemove;
 
    public new bool Remove(T item)
    {
      if (BeforeRemove != null)
      {
        List<T> l = new List<T>();
        l.Add(item);
        BeforeRemove(this, new BeforeRemoveEventArgs(l));
      }
 
      return base.Remove(item);
    }
 
    public new int RemoveAll(Predicate<T> match)
    {
      if (BeforeRemove != null)
        BeforeRemove(this, new BeforeRemoveEventArgs(this.FindAll(match)));
 
      return base.RemoveAll(match);
    }
 
    public new void RemoveAt(int index)
    {
      if (BeforeRemove != null)
      {
        List<T> l = new List<T>();
        l.Add(this[index]);
        BeforeRemove(this, new BeforeRemoveEventArgs(l));
      }
 
      base.RemoveAt(index);
    }
 
    public new void RemoveRange(int index, int count)
    {
      if (BeforeRemove != null)
        BeforeRemove(this, new BeforeRemoveEventArgs(this.GetRange(index, count)));
 
      base.RemoveRange(index, count);
    }
  }
__________________
--
Arnaud DANEELS
adaneels est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 22/02/2012, 22h32   #3
tomlev
Rédacteur/Modérateur


 
Avatar de tomlev
 
Homme Thomas Levesque
Développeur .NET
Inscription : février 2004
Messages : 17 839
Détails du profil
Informations personnelles :
Nom : Homme Thomas Levesque
Âge : 31
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 : 17 839
Points : 34 230
Points : 34 230
Tu peux aussi utiliser BindingList<T> ou ObservableCollection<T>Cela dit ça ne donnera pas exactement le même comportement :

- l'évènement sera déclenché après l'ajout ou la suppression, et non avant (je ne sais pas si c'est un problème pour l'usage que tu en fais)

- l'évènement sera déclenché pour chaque élément ajouté ou supprimé, et non pas pour l'ensemble des éléments à ajouter ou supprimer (dans le cas de AddRange/RemoveRange/RemoveAll)
__________________

Pas de questions techniques par MP ! Le forum est là pour ça...

Tutoriels : Les markup extensions en WPF - La sérialisation XML avec .NET (Aller plus loin) - Extraction de données de pages web à l'aide de HTML Agility Pack
Projet : Dvp.NET, la librairie .NET open-source des membres de Developpez !
tomlev est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 23/02/2012, 09h02   #4
adaneels
Membre actif
 
Avatar de adaneels
 
Homme Arnaud DANEELS
Chef de projet MOA
Inscription : août 2006
Messages : 233
Détails du profil
Informations personnelles :
Nom : Homme Arnaud DANEELS
Âge : 33
Localisation : France

Informations professionnelles :
Activité : Chef de projet MOA

Informations forums :
Inscription : août 2006
Messages : 233
Points : 174
Points : 174
Envoyer un message via ICQ à adaneels Envoyer un message via MSN à adaneels Envoyer un message via Yahoo à adaneels Envoyer un message via Skype™ à adaneels
Tout d'abord merci de l'attention portée

Oui, c'est vrai, j'aurai pu partir sur une ObservableCollection.

L'implémentation que j'ai faite a pour différences de :
faire un évènement pour une action (la suppression ici ; je n'aime pas trop tout retrouver dans un switch ).
L'évènement est levé pour une liste d'éléments et non un élément afin d'optimiser le côté performance.
Et oui, l'évènement est levé avant la suppression car j'avais besoin d'accéder à son contenu (c'est juste un choix lors de l'écriture, je sais qu'on a accès aux éléments supprimés d'une ObservableCollection via e.OldItems).

Bref, par rapport au besoin, je trouvais cette méthodologie plus propre.

S'il y a des avis contraires ou nuancés, je suis tout ouïe voire je serai ravi de les lire (il faut toujours sortir de sa tour d'ivoire ).
__________________
--
Arnaud DANEELS
adaneels est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 23/02/2012, 09h49   #5
tomlev
Rédacteur/Modérateur


 
Avatar de tomlev
 
Homme Thomas Levesque
Développeur .NET
Inscription : février 2004
Messages : 17 839
Détails du profil
Informations personnelles :
Nom : Homme Thomas Levesque
Âge : 31
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 : 17 839
Points : 34 230
Points : 34 230
Disons que ton implémentation a un défaut un peu gênant...

Si je fais ça :

Code :
1
2
3
4
5
List<string> list = new ListTrigerred<string>();
 
...
 
list.RemoveAll(s => s.StartsWith("a"));
Ton évènement ne sera pas déclenché, car la méthode List<T>.RemoveAll n'est pas virtuelle, donc la méthode ListTrigerred<T>.RemoveAll ne fait que la masquer et ne participe pas au polymorphisme. Tu es donc obligé de savoir, au niveau où tu vas appeler RemoveAll, que tu as à faire à une ListTriggered<T> et non à une List<T>, ce qui n'est pas forcément une bonne chose car en général il vaut mieux essayer de faire abstraction du type concret. Cela dit, vu que de toutes façons RemoveAll n'est définie dans aucune interface mais seulement dans la classe List<T>, le problème existait déjà à la base...
__________________

Pas de questions techniques par MP ! Le forum est là pour ça...

Tutoriels : Les markup extensions en WPF - La sérialisation XML avec .NET (Aller plus loin) - Extraction de données de pages web à l'aide de HTML Agility Pack
Projet : Dvp.NET, la librairie .NET open-source des membres de Developpez !
tomlev est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse
Outils de la discussion

Navigation rapide


Fuseau horaire GMT +2. Il est actuellement 04h00.


 
 
 
 
Partenaires

Hébergement Web