Ordenar un listbox
ResueltoErich-Oueb Mensajes publicados 5 Estado Membre -
Hola, estoy cargando un archivo de texto (zonas separadas por ; y sin encabezados) en un ListBox. Solo tomo la primera zona y quisiera ordenarla y, si es posible, sin duplicados. He intentado con Sort-Object | Get-Unique pero no funciona. ¿Alguien podría ayudarme?
Aquí está el código que llena el ListBox:
$ListePC = New-Object System.Windows.Forms.ListBox
$ListePC.Location = New-Object System.Drawing.Point(350,40)
$ListePC.Size = New-Object System.Drawing.Size(300,20)
$ListePC.Height = 160
$Computers = Get-Content \\chemin\Parc.txt
foreach($Computer in $Computers)
{
$Zone=$Computer.split(';')
[void]$ListePC.items.add($Zone[0])
}
$form.Controls.Add($ListePC)
2 réponses
Hola,
Para hacer esto, puedes utilizar algunas funciones integradas de PowerShell.
Get-Content "\\ruta\Parc.txt" | ForEach-Object { $_.split(';')[0] } extrae la primera sección de cada línea.
Sort-Object | Select-Object -Unique ordena la lista y elimina los duplicados.
Luego, el bucle foreach agrega cada elemento único y ordenado a la ListBox.
# Creación de la ListBox $ListePC = New-Object System.Windows.Forms.ListBox $ListePC.Location = New-Object System.Drawing.Point(350,40) $ListePC.Size = New-Object System.Drawing.Size(300,20) $ListePC.Height = 160 # Lectura del archivo y extracción de la primera sección $Computers = Get-Content "\\ruta\Parc.txt" | ForEach-Object { $_.split(';')[0] } # Ordenar los elementos y eliminar duplicados $UniqueSortedComputers = $Computers | Sort-Object | Select-Object -Unique # Agregar los elementos ordenados y únicos a la ListBox foreach($Computer in $UniqueSortedComputers) { [void]$ListePC.items.add($Computer) } # Agregar la ListBox al formulario $form.Controls.Add($ListePC) Sí, si quieres mostrar varias columnas en tu interfaz gráfica, como la zona [2] y la zona [3] además de la zona [1] mientras ordenas por la zona [1], una ListView sería efectivamente más adecuada que una ListBox, ya que permite gestionar varias columnas.
Aquí te muestro cómo puedes adaptar tu script para utilizar una ListView con varias columnas y ordenar los elementos únicamente en función de la primera zona (zona [0]).
# Creación de la ListView $ListView = New-Object System.Windows.Forms.ListView $ListView.Location = New-Object System.Drawing.Point(350,40) $ListView.Size = New-Object System.Drawing.Size(500,200) $ListView.View = [System.Windows.Forms.View]::Details $ListView.FullRowSelect = $true # Adición de las columnas $ListView.Columns.Add("Zona 1", 150) # Para mostrar la zona [0] $ListView.Columns.Add("Zona 2", 150) # Para mostrar la zona [2] $ListView.Columns.Add("Zona 3", 150) # Para mostrar la zona [3] # Lectura del archivo y extracción de las zonas 1, 2 y 3 $Computers = Get-Content "\\ruta\Parc.txt" | ForEach-Object { $Zone = $_.split(';') [PSCustomObject]@{ Zona1 = $Zone[0] Zona2 = $Zone[2] Zona3 = $Zone[3] } } # Ordenar los elementos por Zona1 $SortedComputers = $Computers | Sort-Object Zona1 # Agregar los elementos ordenados en la ListView foreach($Computer in $SortedComputers) { $item = New-Object System.Windows.Forms.ListViewItem($Computer.Zona1) $item.SubItems.Add($Computer.Zona2) $item.SubItems.Add($Computer.Zona3) [void]$ListView.Items.Add($item) } # Adición de la ListView al formulario $form.Controls.Add($ListView) La ListView está configurada con tres columnas (Zona 1, Zona 2, Zona 3).
El modo de visualización está definido en Detalles para poder mostrar las columnas.
FullRowSelect permite seleccionar toda la fila.
El archivo se lee y se transforma en objetos personalizados (PSCustomObject) con tres propiedades: Zona1, Zona2 y Zona3 correspondientes a las zonas [0], [2] y [3] del archivo.
Sort-Object Zona1 ordena los elementos únicamente en función de la primera zona (Zona1).
Para cada elemento ordenado, se crea un objeto ListViewItem con la primera zona como elemento principal, y las otras dos zonas se añaden como SubItems.
Genial, solo faltaba $ListView.Height = 160 (de lo contrario solo se veían las cabeceras de las columnas). Sin embargo, una cosa muy simple, no encuentro cómo recuperar la Zona1 seleccionada en una variable. Por ejemplo, a continuación, me muestra en blanco. He probado con las propiedades .text o .value, pero no ha funcionado mejor.
if ($ListView.SelectedItems) {
$NomPC = $ListView.SelectedItems.items[0]
[System.Windows.Forms.MessageBox]::Show($NomPC)
}
Para recuperar el elemento seleccionado en un ListView, el método correcto es acceder a la propiedad Text del elemento seleccionado. El problema en su ejemplo es que intenta acceder a items[0] que no existe en este momento.
A continuación, se muestra cómo puede recuperar correctamente el valor de la Zona1 (primera columna) del elemento seleccionado:
if ($ListView.SelectedItems.Count -gt 0) { # Recuperar el texto de la primera columna (Zona1) del elemento seleccionado $NomPC = $ListView.SelectedItems[0].Text [System.Windows.Forms.MessageBox]::Show($NomPC) } else { [System.Windows.Forms.MessageBox]::Show("No se ha seleccionado ningún elemento.") } Si desea recuperar los valores de otras columnas (por ejemplo, Zona2 y Zona3), puede utilizar la propiedad SubItems:
if ($ListView.SelectedItems.Count -gt 0) { $NomPC = $ListView.SelectedItems[0].Text # Zona 1 $Zona2 = $ListView.SelectedItems[0].SubItems[1].Text # Zona 2 $Zona3 = $ListView.SelectedItems[0].SubItems[2].Text # Zona 3 [System.Windows.Forms.MessageBox]::Show("Zona 1: $NomPC`nZona 2: $Zona2`nZona 3: $Zona3") } $ListView.SelectedItems[0].SubItems[1].Text accede a la Zona2 (índice 1).
$ListView.SelectedItems[0].SubItems[2].Text accede a la Zona3 (índice 2).
Así podrá mostrar las diferentes zonas seleccionadas en un cuadro de mensaje.
if ($ListView.SelectedItems.Count -gt 0) { # Recuperar los valores de las diferentes áreas del elemento seleccionado $Zona1 = $ListView.SelectedItems[0].Text # Zona 1 $Zona2 = $ListView.SelectedItems[0].SubItems[1].Text # Zona 2 $Zona3 = $ListView.SelectedItems[0].SubItems[2].Text # Zona 3 # Mostrar las áreas en un cuadro de mensaje [System.Windows.Forms.MessageBox]::Show("Zona 1: $Zona1`nZona 2: $Zona2`nZona 3: $Zona3") } else { # Mensaje si no se selecciona ningún elemento [System.Windows.Forms.MessageBox]::Show("No se ha seleccionado ningún elemento.") }
Gracias Bruno, además con los comentarios parece tan simple. ¿Puedo abusar complicando el problema: si quiero mostrar en el listbox 2 zonas más del archivo además de, por ejemplo, [2] y [3] y solo ordenar respecto a la zona [1], creo que debo usar listview, ¿no?