LimitedObservableCollection : partie 1

LimitedObservableCollection : partie 1

Problématique

Lorsque l’on souhaite limiter le nombre d’Item dans une listbox, on écrit :

dans le viewmodel

public get IEnumerable Last10Messages{
return Messages.Take(10);
}

et dans le xaml

<ListBox ItemSource="{Binding Messages}" />

<ListBox ItemSource="{Binding Last10Messages}" />

Le code fonctionne, toutefois, si ‘Messages’ était une ObservableCollection, on perd ici tous ses avantages. En effet, si vous ajoutez un nouvel item à messages, il sera automatiquement ajouté dans la première listbox mais pas dans seconde.

En effet, la fonction ObservableCollection::Take va retourner une IEnumerable et non une ObservableCollection, cela signifie que pour mettre à jour la table ListLimited, il faudra lancer un OnPropertyChanged de ‘Last10Messsages’, mais là, toute la table se remettra à jour et non juste une suppression/ajout des modification (on perd donc considérablement en performance).

Solution : LimitedObservableCollection

Nous allons donc créer une nouvelle classe, hébergeant un ObservableCollection, mais qui avoir pour fonction de filtrer les notifications et de limiter l’énumération sur la source.

Fonctionnement

 

Création

La solution serait donc de continuer à limiter le nombre d’item mais d’exposer une ObservableCollection.

Commençons donc par créer notre classe

public class LimitedObservableCollection
{

}

Dans le constructeur, deux paramètres seront obligatoires, une ObservableCollection correspondant à notre source et un int correspondant au nombre d’items que l’on souhaite au maximum.

private ObservableCollection _observable;
public int _limit;

public LimitedObservableCollection(ObservableCollection source,int limit)
{
_observable = source;
_limit = limit;
}

IEnumerable

Afin d’accéder aux données de notre collection, il faut implémenter l’interface IEnumerable :

public IEnumerator GetEnumerator()
{
return _observable.Take(_limit).GetEnumerator();
}

System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return _observable.Take(_limit).GetEnumerator();
}

Au niveau fonctionnel, on a l’équivalent de notre cas d’étude précédent, on récupère bien une liste de X élements, mais nous ne récupérons pas d’évènement lors de sa modification.

Récupération des évènements de modification de notre source

ObservableCollection implémente l’interface INotifyCollectionChanged.

Cette dernière capte :

  • le remplacement d’un item par un autre
  • l’ajout d’un item
  • la suppression d’un item
  • la remise à zéro de la collection

On va gérer ces 4 types d’évènements, mais avant enregistrons nous :

dans le constructeur :

source.CollectionChanged += new NotifyCollectionChangedEventHandler(o_CollectionChanged);

Notre fonction :

void o_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
switch (e.Action)
{

case NotifyCollectionChangedAction.Replace:
break;
case NotifyCollectionChangedAction.Add:
break;
case NotifyCollectionChangedAction.Reset:
break;
case NotifyCollectionChangedAction.Remove:
break;
}
}

INotifyCollectionChanged

On vient d’utiliser l’interface INotifyCollectionChanged de notre ObservableCollection, on va maintenant implémenter nous même l’interface INotifyCollectionChanged afin de pouvoir lancer nos évènements.

Ce que l’on va faire est plutôt simple, on va récupèrer les évènements de notre source, les analyser et envoyer nos propres évènements.

Il faut donc ajouter l’évènement CollectionChanged à notre classe et on implémentera une fonction OnCollectionChanged qui nous aidera à lancer cet évènement avec une gestion des erreurs.

public event NotifyCollectionChangedEventHandler  CollectionChanged;

protected void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
if (CollectionChanged != null)
try
{
CollectionChanged(this, e);
}
catch (System.NotSupportedException)
{
NotifyCollectionChangedEventArgs alternativeEventArgs =
new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset);
OnCollectionChanged(alternativeEventArgs);
}
}

La suite : LimitedObservableCollection : partie 2

Comments are closed.