el Guille, la Web del Visual Basic, C#, .NET y más...

Clasificar los elementos de... ItemCollection

 
Publicado el 22/Ago/2007
Actualizado el 22/Ago/2007
Autor: Guillermo 'guille' Som

En este artículo te explico cómo clasificar los elementos las colecciones de tipo ItemCollection que es el tipo de colección de todos los controles que tienen elementos, como el ListView, el ListBox, los menús, etc.



 

Introducción:

Todos los controles de WPF que tienen elementos dentro, es decir, que tengan una propiedad Items para acceder a los elementos, se pueden clasificar, el problema es que no tienen un método Sort para hacerlo.

El primer problema es que los elementos de la colección Items puede ser de diferentes tipos, ya que, como seguramente sabrás, el contenido de los elementos es... ¡cualquier cosa!

Debido a que no todos los elementos son de tipo cadena o de cualquier otro tipo "clasificable", en WPF se utiliza otra forma de clasificar, y eso se consigue con la colección SortDescriptionCollection, que contiene elementos del tipo SortDescription que define o contiene la propiedad por la que debe clasificarse y si se hará en forma ascendente o descendente.

La forma de "clasificar" los elementos es fácil... bueno, al menos si se sabe cómo hacerlo... je, je.

Por ejemplo, para clasificar los elementos de un ListBox llamado lst, podemos hacerlo así:

Me.lst.Items.SortDescriptions.Add( _
                                  New SortDescription("Content", _
                                                      ListSortDirection.Ascending))

Es decir, añadimos un nuevo objeto del tipo SortDescription a la colección SortDesciptions de los elementos del ListBox. En ese objeto "clasificador" le indicamos qué propiedad queremos usar para clasificar, en este caso, el contenido de la lista, es decir, la propiedad Content. Después indicamos el orden de clasificación, que es un valor del tipo ListSortDirection que está definida en System.ComponentModel.

 

Una cosa que es importante es que cada vez que queramos volver a clasificar, por ejemplo, de forma contraria a la anterior, debemos eliminar las "descripciones" de clasificación que ya hubiera. Esto lo conseguimos llamando al método Clear de esa colección:

Me.lst.Items.SortDescriptions.Clear()

Al hacer esta "limpieza" conseguimos otro objetivo, que es el de dejar la cosa como estaba... es decir, sin clasificar, por tanto solo debemos usar ese método si en realidad queremos dejarlo sin clasificar o si vamos a clasificar de forma diferente el contenido de esa lista.

 

La ventaja de usar esta forma de clasificar es que podemos crear un método que nos sirva para clasificar cualquier tipo de colección de elementos. Y esto es lo que hace el siguiente método:

Private Sub clasificarLista(ByVal items As ItemCollection, _
                            ByVal propiedad As String, _
                            ByVal ascendente As Boolean?)

    ' Clasificar los elementos según los parámetros

    ' Eliminar las definiciones de clasificación que hubiera
    items.SortDescriptions.Clear()

    If ascendente Then
        items.SortDescriptions.Add( _
                                   New SortDescription(propiedad, _
                                                       ListSortDirection.Ascending))
    Else
        items.SortDescriptions.Add( _
                                   New SortDescription(propiedad, _
                                                       ListSortDirection.Descending))
    End If

End Sub

 

Nota:
Debido a que el último parámetro es de tipo Boolean?, este código solo será válido para Visual Basic 2008 (o superior). Aunque si quieres usarlo con Visual Basic 2005, solo tendrás que cambiar el tipo para que sea Boolean y después hacer las conversiones pertinentes o... (que nadie nos escuche) usar Option Strict Off (pero que conste que yo no te he dicho que lo hagas).

 

Este método lo podemos llamar de varias formas, en el segundo parámetro le indicamos la propiedad por la que queremos clasificar, por ejemplo, en los ListBox o los ListView podemos usar la propiedad Content (como vimos en el ejemplo anterior) y si queremos clasificar los elementos de un menú, usaremos la propiedad Header:

Private Sub mnuClasMenu_Click(ByVal sender As Object, _
                              ByVal e As RoutedEventArgs) _
                              Handles mnuClasMenu.Click

    clasificarLista(Me.mnuFichero.Items, "Header", Me.chkAscendente.IsChecked)
End Sub

 

Respecto a esto de clasificar los menús, si cualquiera de los elementos no tiene un "Header" por el que clasificar, pues... recibiremos un error. Ese será el caso si hay "separadores" (objetos del tipo <Separator />)

 

Ahí abajo tienes un ejemplo completo de esto que te acabo de contar, y en este caso, está tanto el código de Visual Basic como el de C# y el correspondiente XAML con el "diseño" de la ventana.

Nota:
En el caso de C#, debes poner el nombre completo de la clase en el código XAML:
<Window x:Class="EquivalenciasNETyWPF_cs.Window2"

 

Espero que te sea de utilidad.

Nos vemos.
Guillermo

 


Código Xaml El código Xaml
<Window x:Class="Window2"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Prueba de clasificar elementos" Height="400" Width="400">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="30" />
            <RowDefinition />
        </Grid.RowDefinitions>
        <Menu IsMainMenu="True" Grid.Row="0">
            <MenuItem Name="mnuFichero" Header="_Fichero">
                <MenuItem Header="Abrir" />
                <MenuItem Header="Guardar" />
                <MenuItem Header="Guardar como" />
                <MenuItem Header="Mezclar" />
                <MenuItem Header="Cerrar" />
            </MenuItem>
            <MenuItem Header="_Clasificar">
                <MenuItem Name="mnuClasMenu" Header="Clasificar el menú de Fichero" />
                <MenuItem Header="Clasificar el ListView" Click="btnClasifLW_Click" />
                <MenuItem Header="Clasificar el ListBox" Click="btnClasifLst_Click" />
                <Separator />
                <MenuItem Header="Dejarlos sin clasificar" 
                          Click="btnSinClasificar_Click" />
            </MenuItem>
        </Menu>
        <StackPanel Grid.Row="1">
            <ListView Name="lvw" Margin="0,0,8,8" IsSynchronizedWithCurrentItem="True"
                      HorizontalAlignment="Stretch">
                <ListView.View>
                    <GridView>
                        <GridViewColumn Header="Probando"/>
                    </GridView>
                </ListView.View>
                <ListViewItem Content="Este es un elemento del ListView" />
                <ListViewItem Content="Este es otro elemento del ListView" />
                <ListViewItem Content="Este es el tercer elemento del ListView" />
                <ListViewItem Content="Con este ya van cuatro" />
                <ListViewItem Content="Y este es el quinto..." />
            </ListView>
            <ListBox Name="lst">
                <ListBoxItem Content="Hola Mundo"/>
                <ListBoxItem Content="Esto es un listBoxItem"/>
                <ListBoxItem Content="Este también es un elemento de un ListBox"/>
                <ListBoxItem Content="Porque no engraso los ejes..."/>
                <ListBoxItem Content="me llaman abandonao..."/>
            </ListBox>
            <Label />
            <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" 
                        Margin="8,8,0,0">
                <Button Name="btnClasifLW" Content="Clasificar el ListView" 
                        Margin="0,0,8,0" />
                <Button Name="btnClasifLst" Content="Clasificar el ListBox" />
            </StackPanel>
            <CheckBox Name="chkAscendente" Content="Clasificar de forma ascendente" 
                      IsChecked="True" Margin="8,8,0,0"
                      ToolTip="Márcalo para clasificar de forma ascendente..."
                      HorizontalAlignment="Center"/>
            <Button Name="btnSinClasificar" 
                    Content="Restaurar los valores sin clasificar" 
                    Margin="0,8,0,0" />
        </StackPanel>
    </Grid>
</Window>

 

Código para Visual Basic.NET (VB.NET) El código para Visual Basic 2008
Imports System.Windows
Imports System.Windows.Controls
Imports System.ComponentModel

Partial Public Class Window2

    Private Sub btnClasifLW_Click(ByVal sender As Object, _
                                  ByVal e As RoutedEventArgs) _
                                  Handles btnClasifLW.Click

        ' Clasificar el Listview por el contenido de los elementos
        clasificarLista(Me.lvw.Items, "Content", Me.chkAscendente.IsChecked)

    End Sub

    Private Sub btnClasifLst_Click(ByVal sender As Object, _
                                   ByVal e As RoutedEventArgs) _
                                   Handles btnClasifLst.Click

        ' Clasificar el ListBox por el contenido de los elementos
        clasificarLista(Me.lst.Items, "Content", Me.chkAscendente.IsChecked)

    End Sub

    Private Sub mnuClasMenu_Click(ByVal sender As Object, _
                                  ByVal e As RoutedEventArgs) _
                                  Handles mnuClasMenu.Click

        clasificarLista(Me.mnuFichero.Items, "Header", Me.chkAscendente.IsChecked)
    End Sub

    ''' <summary>
    ''' Clasifica los elementos de la lista indicada
    ''' </summary>
    ''' <param name="items">
    ''' Elementos de la lista que se va a clasificar 
    ''' </param>
    ''' <param name="propiedad">
    ''' Nombre la propiedad por la que se va a clasificar
    ''' </param>
    ''' <param name="ascendente">
    ''' Valor verdadero o falso según sea ascendente o no
    ''' </param>
    ''' <remarks></remarks>
    Private Sub clasificarLista(ByVal items As ItemCollection, _
                                ByVal propiedad As String, _
                                ByVal ascendente As Boolean?)

        ' Clasificar los elementos según los parámetros
        ' Eliminar las definiciones de clasificación que hubiera
        items.SortDescriptions.Clear()

        If ascendente Then
            items.SortDescriptions.Add( _
                                       New SortDescription( _
                                               propiedad, _
                                               ListSortDirection.Ascending))
        Else
            items.SortDescriptions.Add( _
                                       New SortDescription( _
                                               propiedad, _
                                               ListSortDirection.Descending))
        End If

    End Sub

    ''' <summary>
    ''' Dejar todos los elementos sin clasificar
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Private Sub btnSinClasificar_Click(ByVal sender As Object, _
                                       ByVal e As RoutedEventArgs) _
                                       Handles btnSinClasificar.Click

        Me.lst.Items.SortDescriptions.Clear()
        Me.lvw.Items.SortDescriptions.Clear()
        Me.mnuFichero.Items.SortDescriptions.Clear()
    End Sub
End Class

 

Código para C Sharp (C#) El código para C#
using System;
using System.Windows;
using System.Windows.Controls;

using System.ComponentModel;

namespace EquivalenciasNETyWPF_cs
{

public partial class Window2 : Window
{
    public Window2()
    {
        InitializeComponent();

        mnuClasMenu.Click +=new RoutedEventHandler(mnuClasMenu_Click);
    }

    private void btnClasifLW_Click(object sender, RoutedEventArgs e)
    {
        // Clasificar el Listview por el contenido de los elementos
        clasificarLista(this.lvw.Items, "Content", 
                        this.chkAscendente.IsChecked);
    }

    private void btnClasifLst_Click(object sender, RoutedEventArgs e)
    {
        // Clasificar el ListBox por el contenido de los elementos
        clasificarLista(this.lst.Items, "Content", 
                        this.chkAscendente.IsChecked);
    }

    private void mnuClasMenu_Click(object sender, RoutedEventArgs e)
    {
        clasificarLista(this.mnuFichero.Items, "Header", 
                        this.chkAscendente.IsChecked);
    }

    /// <summary>
    /// Clasifica los elementos de la lista indicada
    /// </summary>
    /// <param name="items">
    /// Elementos de la lista que se va a clasificar
    /// </param>
    /// <param name="propiedad">
    /// Nombre la propiedad por la que se va a clasificar
    /// </param>
    /// <param name="ascendente">
    /// Valor verdadero o falso según sea ascendente o no
    /// </param>
    /// <remarks></remarks>
    private void clasificarLista(ItemCollection items, 
                                 string propiedad, 
                                 bool? ascendente)
    {
        // Clasificar los elementos según los parámetros

        // Eliminar las definiciones de clasificación que hubiera
        items.SortDescriptions.Clear();

        if (ascendente.Value)
        {
            items.SortDescriptions.Add( 
                new SortDescription( 
                    propiedad, ListSortDirection.Ascending));
        }
        else
        {
            items.SortDescriptions.Add( 
                new SortDescription( 
                    propiedad, ListSortDirection.Descending));
        }
    }

    /// <summary>
    /// Dejar todos los elementos sin clasificar
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    /// <remarks></remarks>
    private void btnSinClasificar_Click(object sender, RoutedEventArgs e)
    {
        this.lst.Items.SortDescriptions.Clear();
        this.lvw.Items.SortDescriptions.Clear();
        this.mnuFichero.Items.SortDescriptions.Clear();
    }
}

}

Espacios de nombres usados en el código de este artículo:

System.Windows
System.Windows.Controls
System.ComponentModel
 


 

Código de ejemplo (comprimido):

Todo el código está en el artículo, tanto para Visual Basic como para C# además del código XAML.



La fecha/hora en el servidor es: 25/11/2024 14:46:58

La fecha actual GMT (UTC) es: 

©Guillermo 'guille' Som, 1996-2024