Lilypie Primer PicLilypie Primer Ticker

viernes, 16 de marzo de 2007

Capítulo II: XBindingList se vuelve ordenada

En el anterior post, vimos como crear la clase XBindingList e implementamos la característica de búsqueda.

Ahora continuaremos con la implementacion de XBindingList añadiendo la opción de ordenación.

Como vimos anteriormente, la forma de añadir prestaciones a una clase derivada de BindingList es solapando métodos y propiedades. Para el caso específico de la ordenación, trabajaremos con las propiedades SupportsSortingCore, SortPopertyCore, SortDirectionCore, IsSortedCore y el método ApplySortCore

Primero debemos informar al mundo que nuestra colección soporta ordenación, para ello solapamos la propiedad SupportSortingCore, asi:


protected override bool SupportsSortingCore
{
get
{
return true;
}
}


Ahora debemos solapar las tres propiedades en las que almacenamos el estado actual de la ordenación: IsSortedCore, SortDirectionCore y SortPropertyCore.


IsSortedCore nos sirve para determinar si la colección está actualmente ordenada o no.


SortDirectionCore determina el sentido de la ordenación. Los posibles valores son Ascending y Descending.


SortPropertyCore determina la propiedad que sirve de criterio para la ordenación.


Entonces solapamos esas tres propiedades asi:



private bool _isSorted;
private ListSortDirection _sortDirection;
private PropertyDescriptor _sortProperty;
 
protected override bool IsSortedCore
{
get
{
return _isSorted;
}
}

protected override ListSortDirection SortDirectionCore
{
get
{
return _sortDirection;
}
}

protected override PropertyDescriptor SortPropertyCore
{
get
{
return _sortProperty;
}
}

Simplemente hemos definido tres campos privados que almacenarán el estado, y hemos solapado las propiedades para accesarlos.


Ahora implementamos el mecanismo de búsqueda. Para ello debemos solapar el método ApplySortCore, asi:


protected override void ApplySortCore(PropertyDescriptor prop, ListSortDirection direction)
{
_sortProperty = prop;
_sortDirection = direction;

if (this.Count == 0)
return;


SortComparer <T> comparer = new SortComparer(prop, direction);

(this.Items as List<T>).Sort(comparer);


_isSorted = true;
OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));

}


Este método recibe dos parámetros: prop que es la propiedad que actuará como el criterio de ordenación, y direction que es el sentido de la orientación, que puede ser acendente o descendente.


A continuación creamos una instancia de la clase SortComparer que será usado por el mecanismo de ordenación para hacer las comparaciones. la clase SortComparer está definida asi:


public class SortComparer<T> : IComparer<T>
{
private ListSortDirection _sortDirection = ListSortDirection.Ascending;
private PropertyDescriptor _propDescriptor = null;

public SortComparer(PropertyDescriptor propDescriptor, ListSortDirection sortDirection)
{
this._propDescriptor = propDescriptor;
this._sortDirection = sortDirection;
}

int IComparer<T>.Compare(T x, T y)
{
object xValue = _propDescriptor.GetValue(x);
object yValue = _propDescriptor.GetValue(y);
return CompareValues(xValue, yValue);
}

private int CompareValues(object xValue, object yValue)
{
int retValue = 0;
if (xValue is IComparable)
retValue = (xValue as IComparable).CompareTo(yValue);
else if (yValue is IComparable)
retValue = (yValue as IComparable).CompareTo(xValue);
else if (!xValue.Equals(yValue))
retValue = xValue.ToString().CompareTo(yValue.ToString());

if (_sortDirection == ListSortDirection.Descending)
retValue *= -1;
return retValue;
}
}

La clase SortComparer implementa la interfaz IComparer, siendo el método CompareValues el encargado de realizar todo el trabajo pesado: las comparaciones.

La línea (this.Items as List<T>).Sort(comparer) es donde realmente la ordenación tiene lugar. Simplemente invocamos al método Sort de la clase List<T> pasando como parámetro la instancia de la clase SortComparer que acabamos de crear.

Eso es todo, estamos listo para probar nuestra implementación. La misma aplicación que creamos anteriormente para probar lá búsqueda nos servirá para probar la ordenación. Con un simple click en la cabecera de las columnas podremos ver la ordenación en funcionamiento.


Con la implementación actual, XBindingList se comporta bastante bien cuando de ordenar se trata, pero para completar el ejercicio, debemos implementar también el método RemoveSortCore que es invocado cuando queremos dejar de aplicar la ordenación. Ahi se complica el panorama porque debemos guardar el orden (o desorden) original para que pueda ser restaurado luego. ...pero ese será tema de otro post.


Siguiente Capítulo: XBindingList se vuelve selectiva.

No hay comentarios.: