Wpf - Ordenación de ObservableCollection

Descripción general

Este documento muestra la forma de ordenar una colección de objetos observable mediante [IComparer]

[TOC] Tabla de Contenidos


↑↑↑

1.1 A modo de introducción

Para ordenar una colección observable hay que seguir los siguientes pasos.


↑↑↑

1.2 Escribir el objeto contenido en la colección

''' <summary>
''' Esta clase representa a una foto
''' </summary>
<Serializable>
Public Class UnaFoto

    '-----------------------------
#Region "Variables y propiedades de la clase"

    Private _fileInfoImagen As System.IO.FileInfo

    Private _uriFullName As Uri = Nothing

    Private _strFullName As String
    Private _strName As String
    Private _dateCreationTime As Date


    ''' <summary>
    '''  Obtiene el nombre y la extension de la imagen
    ''' </summary>
    Public ReadOnly Property Name() As String
        Get
            Return _strName
        End Get
    End Property


    ''' <summary>
    '''  Obtiene la ruta completa (directorio + nombre + extension) de la imagen
    ''' </summary>
    Public ReadOnly Property FullName() As String
        Get
            Return _strFullName
        End Get
    End Property


    ''' <summary>
    '''  Obtiene el nombre y la extension de la imagen
    ''' </summary>
    Public ReadOnly Property UriFullName As Uri
        Get
            If _uriFullName Is Nothing Then
                _uriFullName = New Uri(FullName, UriKind.RelativeOrAbsolute)
            End If
            Return _uriFullName
        End Get
    End Property


    ''' <summary>
    '''  Obtiene la fecha de creación del fichero imagen
    ''' </summary>
    Public ReadOnly Property DateCreationTime() As Date
        Get
            Return _dateCreationTime
        End Get
    End Property

#End Region


#Region "Constructores"

    ''' <summary>
    '''  Constructor
    ''' </summary>
    ''' <param name=pfileInfoImagen">El valor del objeto FileInfo del fichero de la imagen</param>"
    Public Sub New(ByVal pfileInfoImagen As System.IO.FileInfo)

         pfileInfoImagen.Refresh()

        _fileInfoImagen = pfileInfoImagen

        _strFullName = pfileInfoImagen.FullName
        _strName = pfileInfoImagen.Name
        _dateCreationTime = pfileInfoImagen.CreationTime
    End Sub

#End Region


#Region "Interfaz IComparer "

    ' Métodos auxiliares que devuelven la interfaz
    ''' <summary>
    '''  Devuelve la interfaz [IComparer] para  comparar por nombre completo (ruta + nombre + extension)
    ''' </summary>
    Public Shared Function GetIComparerPorNombreCompleto(ByVal tipoOrdenacion As System.Data.SqlClient.SortOrder) As IComparer(Of UnaFoto)
        Return New CompararPorNombreCompleto(tipoOrdenacion)
    End Function

    ''' <summary>
    '''  Devuelve la interfaz [IComparer] para  comparar por nombre y la extension unicamente
    ''' </summary>
    Public Shared Function GetIComparerPorNombre(ByVal tipoOrdenacion As System.Data.SqlClient.SortOrder) As IComparer(Of UnaFoto)
        Return New CompararPorNombre(tipoOrdenacion)
    End Function

    ''' <summary>
    '''  Devuelve la interfaz [IComparer] para  comparar por fecha de creación del fichero
    ''' </summary>
    Public Shared Function GetIComparerPorFechaCreacion(ByVal tipoOrdenacion As System.Data.SqlClient.SortOrder) As IComparer(Of UnaFoto)
        Return New CompararPorFechaCreacion(tipoOrdenacion)
    End Function

#End Region

End Class


↑↑↑

1.3 Escribir las clases auxiliares que implementaran la interfaz [IComparer]

    ''' <summary>
    ''' Clase auxiliar para comparar por nombre completo (ruta + nombre + extension)
    ''' </summary>
    Private Class CompararPorNombreCompleto
        Implements IComparer(Of UnaFoto)

        ''' <summary> Para ordenaciones ascendentes o descendentes </summary>
        Private _modificadorSortOrder As Integer = 1

        ''' <summary> Constructor</summary>
        ''' <param name=tipoOrdenacion">Tipo de ordenación [Ascendente, descendente, no definida]</param>"
        ''' <remarks>Utilizo una enumeración de .Net, para no tener que definir una ex profeso</remarks>
        Public Sub New(ByVal tipoOrdenacion As System.Data.SqlClient.SortOrder)
            Select Case tipoOrdenacion
                Case Is = System.Data.SqlClient.SortOrder.Descending
                    _modificadorSortOrder = -1
                Case Is = System.Data.SqlClient.SortOrder.Ascending
                    _modificadorSortOrder = +1
                Case Is = System.Data.SqlClient.SortOrder.Unspecified
                    _modificadorSortOrder = +1
            End Select
        End Sub


        ''' <summary>
        ''' Compara dos objetos y devuelve un valor que indica si uno es menor, igual o mayor que el otro. 
        ''' </summary>
        ''' <param name=x">La primera imagen</param>"
        ''' <param name=y">La segunda imagen</param>"
        ''' <returns>
        '''  <para>Tipo: System.Int32                       </para> 
        '''  <para>    Menor que cero (-1) x es menor que y. </para> 
        '''  <para>    Cero           ( 0) x es igual que y. </para> 
        '''  <para>    Mayor que cero (+1) x es mayor que y. </para> 
        '''</returns>
        Public Function Compare(x As UnaFoto, y As UnaFoto) As Integer Implements IComparer(Of UnaFoto).Compare

            ' dos objetos nulos son iguales
            If x Is Nothing AndAlso y Is Nothing Then Return 0

            ' cualquier objeto no nulo es mayor que un objeto nulo
            If x Is Nothing Then Return 1
            If y Is Nothing Then Return -1

            ' realizar la comparación
            Dim resultadoComparacion As Integer = String.Compare(x.FullName, y.FullName)

            ' modificación ascendente o descendente
            Return resultadoComparacion * _modificadorSortOrder

        End Function
    End Class


    ''' <summary>
    ''' Clase auxiliar para comparar por nombre y la extension unicamente
    ''' </summary>  
    Private Class CompararPorNombre
        Implements IComparer(Of UnaFoto)

        Private _modificadorSortOrder As Integer = 1

        Public Sub New(ByVal tipoOrdenacion As System.Data.SqlClient.SortOrder)
            Select Case tipoOrdenacion
                Case Is = System.Data.SqlClient.SortOrder.Descending
                    _modificadorSortOrder = -1
                Case Is = System.Data.SqlClient.SortOrder.Ascending
                    _modificadorSortOrder = +1
                Case Is = System.Data.SqlClient.SortOrder.Unspecified
                    _modificadorSortOrder = +1
            End Select
        End Sub

        Public Function Compare(x As UnaFoto, y As UnaFoto) As Integer Implements IComparer(Of UnaFoto).Compare
            ' dos objetos nulos son iguales
            If x Is Nothing AndAlso y Is Nothing Then Return 0
            ' cualquier objeto no nulo es mayor que un objeto nulo
            If x Is Nothing Then Return 1
            If y Is Nothing Then Return -1

            ' realizar la comparación
            Dim resultadoComparacion As Integer = String.Compare(x.Name, y.Name)
            ' modificación ascendente o descendente
            Return resultadoComparacion * _modificadorSortOrder
        End Function
    End Class



    ''' <summary>
    ''' Clase auxiliar para comparar por fecha de creación del fichero
    ''' </summary> 
    Private Class CompararPorFechaCreacion
        Implements IComparer(Of UnaFoto)

        Private _modificadorSortOrder As Integer = 1

        Public Sub New(ByVal tipoOrdenacion As System.Data.SqlClient.SortOrder)
            Select Case tipoOrdenacion
                Case Is = System.Data.SqlClient.SortOrder.Descending
                    _modificadorSortOrder = -1
                Case Is = System.Data.SqlClient.SortOrder.Ascending
                    _modificadorSortOrder = +1
                Case Is = System.Data.SqlClient.SortOrder.Unspecified
                    _modificadorSortOrder = +1
            End Select
        End Sub

        Public Function Compare(x As UnaFoto, y As UnaFoto) As Integer Implements IComparer(Of UnaFoto).Compare
            ' dos objetos nulos son iguales
            If x Is Nothing AndAlso y Is Nothing Then Return 0
            ' cualquier objeto no nulo es mayor que un objeto nulo
            If x Is Nothing Then Return 1
            If y Is Nothing Then Return -1

            ' realizar la comparación
            Dim resultadoComparacion As Integer = Date.Compare(x.DateCreationTime, y.DateCreationTime)
            ' modificación ascendente o descendente
            Return resultadoComparacion * _modificadorSortOrder
        End Function
    End Class


↑↑↑

1.4 las funciones que permiten el acceso a la interfaz [IComparer]

    ' (Funciones que estan en la clase UnaFoto)
    ' Métodos auxiliares que devuelven la interfaz

    ''' <summary>
    '''  Devuelve la interfaz [IComparer] para  comparar por nombre completo (ruta + nombre + extension)
    ''' </summary>
    Public Shared Function GetIComparerPorNombreCompleto(ByVal tipoOrdenacion As System.Data.SqlClient.SortOrder) As IComparer(Of UnaFoto)
        Return New CompararPorNombreCompleto(tipoOrdenacion)
    End Function

    ''' <summary>
    '''  Devuelve la interfaz [IComparer] para  comparar por nombre y la extension unicamente
    ''' </summary>
    Public Shared Function GetIComparerPorNombre(ByVal tipoOrdenacion As System.Data.SqlClient.SortOrder) As IComparer(Of UnaFoto)
        Return New CompararPorNombre(tipoOrdenacion)
    End Function

    ''' <summary>
    '''  Devuelve la interfaz [IComparer] para  comparar por fecha de creación del fichero
    ''' </summary>
    Public Shared Function GetIComparerPorFechaCreacion(ByVal tipoOrdenacion As System.Data.SqlClient.SortOrder) As IComparer(Of UnaFoto)
        Return New CompararPorFechaCreacion(tipoOrdenacion)
    End Function


↑↑↑

1.5 Escribir la clase colección

Imports System.Collections.ObjectModel
Imports System.Collections.Specialized
''' <summary>
'''  Esta clase representa a una colección de fotos en un directorio
''' </summary>
Public Class ColecccionDeFotos
    Inherits ObservableCollection(Of UnaFoto)



    Private _directorio As System.IO.DirectoryInfo



    Public Sub New()
        'Me.New(New System.IO.DirectoryInfo("F:\Fotos\"))
    End Sub

    Public Sub New(path As String)
        Me.New(New System.IO.DirectoryInfo(path))
    End Sub

    Public Sub New(directory As System.IO.DirectoryInfo)
        _directorio = directory
        Update(_directorio)
    End Sub


    Public Property Path() As String
        Get
            Return _directorio.FullName
        End Get
        Set
            If String.Equals(_directorio.FullName, Value) = False Then
                _directorio = New System.IO.DirectoryInfo(Value)
                Update(_directorio)
            End If
        End Set
    End Property


    Private Sub Update(ByVal pdirectorio As System.IO.DirectoryInfo)
        Try
            'Dim directorio As New DirectoryInfo(Fi.FullName)
            Dim ficherosDirectorio As System.IO.FileInfo() = pdirectorio.GetFiles

            If ficherosDirectorio.Count > 0 Then
                Me.Clear()

                For Each unFichero As System.IO.FileInfo In ficherosDirectorio
                    ' excluir ficheros ocultos -  exclude hidden files 
                    If (unFichero.Attributes And System.IO.FileAttributes.Hidden) <> System.IO.FileAttributes.Hidden Then
                        ' excluir ficheros que no sean images
                        If unFichero.Extension.ToLower = ".jpg" OrElse
                           unFichero.Extension.ToLower = ".jpeg" OrElse
                           unFichero.Extension.ToLower = ".png" OrElse
                           unFichero.Extension.ToLower = ".tif" Then
                            'Dim nuevaFoto As New Foto(unFichero)
                            'Add(nuevaFoto)
                            Add(New UnaFoto(unFichero))
                        End If
                    End If
                Next
            End If


        Catch ex As System.IO.DirectoryNotFoundException
            Throw
        Catch ex As Exception
            Throw
        End Try
    End Sub



    Public ReadOnly Property ListaItemsCollections As ObservableCollection(Of UnaFoto)
        Get
            Return Me
        End Get
    End Property


    'Protected Friend Shadows Sub RemoveItem(index As Integer)
    '    MyBase.RemoveItem(0)
    'End Sub


    ''' <summary>
    '''  Devuelve la interfaz [IComparer] para  comparar por nombre completo (ruta + nombre + extension)
    ''' </summary>
    Public Sub OrdenarPorNombreCompleto(ByVal tipoOrdenacion As System.Data.SqlClient.SortOrder)

        Dim arrayAux As UnaFoto() = MyBase.ToArray
        System.Array.Sort(arrayAux, UnaFoto.GetIComparerPorNombreCompleto(tipoOrdenacion))

        Me.Clear()
        For Each unFichero As UnaFoto In arrayAux
            Add(unFichero)
        Next
    End Sub


    ''' <summary>
    '''  Devuelve la interfaz [IComparer] para  comparar por nombre y la extension unicamente
    ''' </summary>
    Public Sub OrdenarPorNombre(ByVal tipoOrdenacion As System.Data.SqlClient.SortOrder)

        Dim arrayAux As UnaFoto() = MyBase.ToArray
        System.Array.Sort(arrayAux, UnaFoto.GetIComparerPorNombre(tipoOrdenacion))

        Me.Clear()
        For Each unFichero As UnaFoto In arrayAux
            Add(unFichero)
        Next
    End Sub

    ''' <summary>
    '''  Devuelve la interfaz [IComparer] para  comparar por fecha de creación del fichero
    ''' </summary>
    Public Sub OrdenarPorFechaCreacion(ByVal tipoOrdenacion As System.Data.SqlClient.SortOrder)

        Dim arrayAux As UnaFoto() = MyBase.ToArray
        System.Array.Sort(arrayAux, UnaFoto.GetIComparerPorFechaCreacion(tipoOrdenacion))

        Me.Clear()
        For Each unFichero As UnaFoto In arrayAux
            Add(unFichero)
        Next
    End Sub

End Class


↑↑↑

1.6 A modo de corolario

Lo más importante es fijarse en la secuencia de funciones


↑↑↑

1.6.1 En la clase UnFoto

    ''' <summary>
    '''  Clase [UnaFoto] Devuelve la interfaz [IComparer] para  comparar por fecha de creación del fichero
    ''' </summary>
    Public Shared Function GetIComparerPorFechaCreacion(ByVal tipoOrdenacion As System.Data.SqlClient.SortOrder) As IComparer(Of UnaFoto)
        Return New CompararPorFechaCreacion(tipoOrdenacion)
    End Function


↑↑↑

1.6.2 En la clase colección

Observa el juego que hay que hacer para que la ventana actualice la información de la colección una vez ordenada.

    ''' <summary>
    '''  Clase [ ObservableCollection(Of UnaFoto)]
    '''  Devuelve la interfaz [IComparer] para  comparar por fecha de creación del fichero
    ''' </summary>
    Public Sub OrdenarPorFechaCreacion(ByVal tipoOrdenacion As System.Data.SqlClient.SortOrder)

        Dim arrayAux As UnaFoto() = MyBase.ToArray
        System.Array.Sort(arrayAux, UnaFoto.GetIComparerPorFechaCreacion(tipoOrdenacion))

        Me.Clear()
        For Each unFichero As UnaFoto In arrayAux
            Add(unFichero)
        Next
    End Sub


↑↑↑

1.6.3 En el código del formulario llamador

El formulario llamador definirá mediante botones y/o menús, la forma de ordenación, y los eventos Clic llamaran a una de estas funciones.

    Private Sub OrdenarPorFechaCreacionAscendente()
        coleccionFotos.OrdenarPorFechaCreacion(System.Data.SqlClient.SortOrder.Ascending)
    End Sub

    Private Sub OrdenarPorFechaCreacionDescendente()
        coleccionFotos.OrdenarPorFechaCreacion(System.Data.SqlClient.SortOrder.Descending)
    End Sub

↑↑↑

A.2.Enlaces

[Para saber mas]
[Grupo de documentos]
[Documento Index]
[Documento Start]
[Imprimir el Documento]
© 1997 - - La Güeb de Joaquín
Joaquín Medina Serrano
Ésta página es española

Codificación
Fecha de creación
Última actualización
[HTML5 Desarrollado usando CSS3]