Сортировка столбцов управления Listview с целочисленными значениями в формах Powershell

Я пытаюсь отсортировать размер столбца (КБ) в следующем списке. Столбец Размер (КБ) сортируется на основе текстового значения, которое не соответствует ожидаемому результату. Я получаю правильные результаты для всех других столбцов

# Defining the listbox fo displaying the search results
$lvw_resultsListView = New-Object System.Windows.Forms.ListView -Property @{
    View        = [System.Windows.Forms.View]::Details
    Location    = New-Object System.Drawing.Size(10, 40)  
    Width       = 700
    Height      = 350
    Scrollable  = $true
    MultiSelect = $true
    Font        = 'Arial,10'
    AutoSize    = $true
    Sorting     = "Ascending"
    FullRowSelect = $true
    GridLines = $True
}

Вот код, который добавляет столбцы в список

# Adding Columns to List View
$lvw_resultsListView.columns.Add("Filename", 150) | Out-Null
$lvw_resultsListView.columns.Add("Path", 340) | Out-Null
$lvw_resultsListView.columns.Add("Size (kb)", 90) | Out-Null
$lvw_resultsListView.columns.Add("Created on", 70) | Out-Null
$lvw_resultsListView.columns.Add("Ext", 60) | Out-Null

Вот код, который добавляет значения из файлового объекта

# Clearing list view items
$lvw_resultsListView.Items.Clear()
# Adding file information to the list bx by cycling through each file
foreach ($file in $global:files) {
    $fileItem = New-Object System.Windows.Forms.ListViewItem( $file.BaseName)
    $fileItem.Subitems.Add($file.FullName) | Out-Null
    $fileItem.Subitems.Add($file.Length) | Out-Null
    $tempCreationDate = $file.CreationTime | Get-Date -f "yyyy-MM-dd"
    $fileItem.Subitems.Add($tempCreationDate) | Out-Null
    $fileItem.Subitems.Add($file.Extension) | Out-Null
    $lvw_resultsListView.Items.Add($fileItem) | Out-Null
}

А вот функция сортировки, которая вызывается при щелчке столбца

function SortListView {
    Param(
        [System.Windows.Forms.ListView] $senderPsItem,
        $column
    )
    $temp = $senderPsItem.Items | Foreach-Object { $_ }
    $Script:SortingDescending = !$Script:SortingDescending
    $senderPsItem.Items.Clear()
    $senderPsItem.ShowGroups = $false
    $senderPsItem.Sorting = 'none'
    
    if($column.Text -eq "Size (kb)") {
        
        $senderPsItem.Items.AddRange(($temp | Sort-Object -Descending:$script:SortingDescending -Property @{ Expression={ [int]$_.SubItems[$column].Text } }))
        
    } else {
        $senderPsItem.Items.AddRange(($temp | Sort-Object -Descending:$script:SortingDescending -Property @{ Expression={ $_.SubItems[$column].Text } }))

    }
}

Здесь (фрагмент из формы результатов) пример результата, который я получаю для столбца Размер (КБ)

введите здесь описание изображения

Вот код, вызывающий функцию сортировки

$lvw_resultsListView.Add_ColumnClick({SortListView $this $_.Column})

Может ли кто-нибудь предложить способ улучшить мою функцию сортировки, чтобы правильно отсортировать целочисленный столбец. Я попытался преобразовать тест в целое число с помощью метода [int], как видно из функции сортировки? Заранее спасибо!


person rhythmo    schedule 15.04.2021    source источник
comment
Поместите Write-Host $temp под назначением переменной и щелкните столбец, который вы хотите отсортировать, это поможет понять, почему ваша функция не работает. Совет: вы можете посмотреть на DataGridView с DataTable в качестве источника данных. Кодировать будет намного проще.   -  person Santiago Squarzon    schedule 16.04.2021
comment
Ух ты! Это действительно помогло. Спасибо Сантьяго!   -  person rhythmo    schedule 16.04.2021


Ответы (2)


Условие IF для проверки размера столбца (КБ) было неправильным. Для исправления этого использовался индекс столбца.

Измененный

if($column.Text -eq Размер (КБ))

to

если($столбец-уравнение 2)

Я обновил функцию сортировки, чтобы исправить условие IF

function SortListView {
    Param(
        [System.Windows.Forms.ListView] $senderPsItem,
        $column
    )
    $temp = $senderPsItem.Items | Foreach-Object { $_ }
    $Script:SortingDescending = !$Script:SortingDescending
    $senderPsItem.Items.Clear()
    $senderPsItem.ShowGroups = $false
    $senderPsItem.Sorting = 'none'
    Write-Host $column
    
    if($column -eq 2) {
        
        $senderPsItem.Items.AddRange(($temp | Sort-Object -Descending:$script:SortingDescending -Property @{ Expression={ [int]$_.SubItems[$column].Text } }))
        
    } else {
        $senderPsItem.Items.AddRange(($temp | Sort-Object -Descending:$script:SortingDescending -Property @{ Expression={ $_.SubItems[$column].Text } }))

    }
}

Это дает правильные результаты для целочисленного столбца.

person rhythmo    schedule 15.04.2021

Вот попробуйте этот код, он поможет вам понять, почему я упомянул DataGridView и DataTable, лично для меня это оказало большое влияние при работе с WPF.

Попробуйте отсортировать столбцы *Time и Length, и вы поймете, почему :)

Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
Add-Type -AssemblyName PresentationFramework

$myFont='Helvetica'

$mainForm=New-Object System.Windows.Forms.Form
$mainForm.StartPosition='CenterScreen'
$mainForm.Icon=[System.Drawing.Icon]::ExtractAssociatedIcon("$PSHOME\PowerShell.exe")
$mainForm.KeyPreview=$True
$mainForm.FormBorderStyle='Fixed3D'
$mainForm.Text='Test'
$mainForm.WindowState='Maximized'

$bounds=($mainForm.CreateGraphics()).VisibleClipBounds.Size

$dataGrid=New-Object System.Windows.Forms.DataGridView
$dataGrid.Size=New-Object System.Drawing.Size(($bounds.Width-20),$($bounds.Height-140))
$dataGrid.Location=New-Object System.Drawing.Size(10,60)
$dataGrid.Font=New-Object System.Drawing.Font($myFont,9,[System.Drawing.FontStyle]::Regular)
$dataGrid.DefaultCellStyle.WrapMode='True'
$dataGrid.AllowUserToAddRows=$false
$dataGrid.SelectionMode=0
$dataGrid.MultiSelect=$True
$dataGrid.ReadOnly=$false
$dataGrid.EnableHeadersVisualStyles=$True
$datagrid.Anchor='Top, Bottom, Left'
$mainForm.Controls.Add($dataGrid)

#Here goes your Data Source
$dataSource = Get-ChildItem "$HOME\Documents" -File|select Name,Length,LastWriteTime,CreationTime

$columns=$dataSource[0].PSobject.Properties.Name
$table = New-Object system.Data.DataTable

foreach($column in $columns)
{
    $type=switch -Wildcard($column)
    {
        'Length'{[int]}
        '*Time'{[datetime]}
        Default{[string]}
    }

    $i = New-Object System.Data.DataColumn
    $i.DataType = $type
    $i.ColumnName = $column
    $table.Columns.Add($i)
}

foreach($line in $dataSource)
{
    $row = $table.NewRow()
    
    foreach($column in $columns)
    {
        $row.$column = $line.$column
    }

    $table.Rows.Add($row)
}

# Here you bind your DataSource to your DataGridView
$dataGrid.DataSource=$table

$dataGrid.RowHeadersVisible=$false
$dataGrid.ColumnHeadersBorderStyle=2
$dataGrid.AutoSizeColumnsMode=[System.Windows.Forms.DataGridViewAutoSizeColumnMode]::AllCells
$dataGrid.ColumnHeadersHeight=25

$sum=0
$dataGrid.Columns.Width|%{$sum+=$_}

if($sum -lt $dataGrid.Width)
{
    $dataGrid.Columns[-1].AutoSizeMode=[System.Windows.Forms.DataGridViewAutoSizeColumnMode]::Fill
}


$mainForm.ShowDialog()
person Santiago Squarzon    schedule 15.04.2021