【问题标题】:Populate a ListView with a custom file list (FilePath and Size) in Powershell在 Powershell 中使用自定义文件列表(文件路径和大小)填充 ListView
【发布时间】:2020-05-26 08:58:08
【问题描述】:

我正在尝试制作一个远程复制工具,该工具在控制台中运行良好,但我无法为其创建 GUI。

当我用要复制的文件列表填充我的列表框时,它们只是没有按预期显示......

我的问题出在ChooseFiles 函数中

#xaml Code
$inputXML = @"
<Window x:Class="RemoteCopy.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:RemoteCopy"
        mc:Ignorable="d"
        Title="Remote Copy" Height="556.841" Width="800">
    <Grid>
        <Label Content="Remote Computer's IP:" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top"/>
        <TextBox x:Name="RemoteIPTextbox" HorizontalAlignment="Left" Height="20" Margin="238,16,0,0" TextWrapping="Wrap" Text="IP address" VerticalAlignment="Top" Width="128"/>
        <Label Content="Username: " HorizontalAlignment="Left" Height="26" Margin="10,40,0,0" VerticalAlignment="Top" Width="131"/>
        <Label Content="Password: " HorizontalAlignment="Left" Height="26" Margin="10,70,0,0" VerticalAlignment="Top" Width="131"/>
        <TextBox x:Name="UsernameTextbox" HorizontalAlignment="Left" Height="20" Margin="238,46,0,0" TextWrapping="Wrap" Text="Username" VerticalAlignment="Top" Width="128"/>
        <Button x:Name="CheckConnectionButton" Content="Check Connection" HorizontalAlignment="Left" Margin="389,46,0,0" VerticalAlignment="Top" Width="107" Height="20"/>
        <Button x:Name="ChooseFilesButton" Content="Choose Files" HorizontalAlignment="Left" Height="80" Margin="535,16,0,0" VerticalAlignment="Top" Width="122"/>
        <ListView x:Name="FilesListView" HorizontalAlignment="Left" Height="234" Margin="33,128,0,0" VerticalAlignment="Top" Width="720">
            <ListView.View>
                <GridView>
                    <GridViewColumn Header="File"/>
                    <GridViewColumn Header="Size"/>
                </GridView>
            </ListView.View>
        </ListView>
        <Button x:Name="StartCopyButton" Content="Start Copy" HorizontalAlignment="Left" Height="24" Margin="33,374,0,0" VerticalAlignment="Top" Width="720"/>
        <ProgressBar x:Name="ProgressBar" HorizontalAlignment="Left" Height="20" Margin="113,418,0,0" VerticalAlignment="Top" Width="572"/>
        <Label Content="Progress:" HorizontalAlignment="Left" Height="28" Margin="33,418,0,0" VerticalAlignment="Top" Width="67"/>
        <Label Content="100%" HorizontalAlignment="Left" Height="28" Margin="714,418,0,0" VerticalAlignment="Top" Width="39"/>
        <PasswordBox x:Name="Passwordbox" HorizontalAlignment="Left" Margin="238,78,0,0" VerticalAlignment="Top" Width="128"/>
        <Button x:Name="ExitButton" Content="Exit" HorizontalAlignment="Left" Height="21" Margin="283,455,0,0" VerticalAlignment="Top" Width="213"/>

    </Grid>
</Window>

"@


$inputXML = $inputXML -replace 'mc:Ignorable="d"','' -replace "x:N",'N' -replace '^<Win.*', '<Window'
[void][System.Reflection.Assembly]::LoadWithPartialName('presentationframework')
[xml]$XAML = $inputXML
#Read XAML

$reader=(New-Object System.Xml.XmlNodeReader $xaml)
try{
    $Form=[Windows.Markup.XamlReader]::Load( $reader )
}
catch{
    Write-Warning "Unable to parse XML, with error: $($Error[0])`n Ensure that there are NO SelectionChanged or TextChanged properties in your textboxes (PowerShell cannot process them)"
    throw
}


#===========================================================================
# Load XAML Objects In PowerShell
#===========================================================================

$xaml.SelectNodes("//*[@Name]") | %{"trying item $($_.Name)";
    try {Set-Variable -Name "WPF$($_.Name)" -Value $Form.FindName($_.Name) -ErrorAction Stop}
    catch{throw}
    }


Function Get-FormVariables{
    if ($global:ReadmeDisplay -ne $true){Write-host "If you need to reference this display again, run Get-FormVariables" -ForegroundColor Yellow;$global:ReadmeDisplay=$true}
    write-host "Found the following interactable elements from our form" -ForegroundColor Cyan
    get-variable WPF*
    }

    Get-FormVariables


#===========================================================================
# Use this space to add code to the various form elements in your GUI
#===========================================================================


#my test folder
c:
Set-Location c:\temp

function DisplayInBytes($num) 
#reference: https://stackoverflow.com/questions/24616806/powershell-display-files-size-as-kb-mb-or-gb
{
    $suffix = "B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"
    $index = 0
    while ($num -gt 1kb) 
    {
        $num = $num / 1kb
        $index++
    } 
    "{0:N1} {1}" -f $num, $suffix[$index]
}


function ChooseFiles
{
    $WPFFilesListView.Clear()
    $filesToCopy = Get-Files
    $filesToCopy.FileNames | ForEach-Object {
        $currentfilesize = (Get-Item $_).Length
        $currentfilesize = DisplayInBytes -num $currentfilesize
        $row = New-Object System.Windows.Forms.ListViewItem($_)
        [void]$row.SubItems.Add("$currentfilesize")
        [void]$WPFFilesListView.Items.Add($row)
    }
}


Function Get-Files($initialDirectory="")
#Reference to https://stackoverflow.com/questions/15885132/file-folder-chooser-dialog-from-a-windows-batch-script
{
    [System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms")|Out-Null

    $myFile = new-object Windows.Forms.OpenFileDialog
    $myFile.InitialDirectory = Get-Location
    $myFile.Filter = "Text Files (*.txt)|*.txt|Powershell Script Files (*.ps1)|*.ps1|Batch Files (*.bat)|*.bat|All Files (*.*)|*.*"
    $myFile.ShowHelp = $true
    $myFile.Multiselect = $true
    [void]$myfile.ShowDialog()

    if ($myFile.Multiselect) { $myFile.FileNames } else { $myFile.FileName }
    return $myFile
}


$WPFExitButton.Add_Click({$form.close()})
$WPFChooseFilesButton.Add_Click({ChooseFiles})


$Form.ShowDialog() | out-null

选择我的文件并填充我的列表框的功能是这个:

function ChooseFiles
{
    $WPFFilesListView.Clear()
    $filesToCopy = Get-Files
    $filesToCopy.FileNames | ForEach-Object {
        $currentfilesize = (Get-Item $_).Length
        $currentfilesize = DisplayInBytes -num $currentfilesize
        $row = New-Object System.Windows.Forms.ListViewItem($_)
        [void]$row.SubItems.Add("$currentfilesize")
        [void]$WPFFilesListView.Items.Add($row)
    }
}

但我的结果看起来像这样:

我打算显示文件名和文件大小, 如果我测试他们工作的变量

Write-host $_
write-host $currentfilesize

每列一个

【问题讨论】:

  • 预期输出是什么?你能详细说明一下吗?
  • 嗨,我已经编辑了这个问题。我需要 1 列带有文件路径 + 文件名,另一列带有文件大小。谢谢
  • $filesToCopy.FileNames 的输出是什么?
  • 我使用 Get-Files 函数选择的文件列表,$filestocopy.gettype() 返回一个 System.array

标签: powershell xaml listview user-interface


【解决方案1】:

你需要改变两件事来修复显示:

  1. 向 ListView 添加 DisplayMemberBinding

    <ListView x:Name="FilesListView" HorizontalAlignment="Left" Height="234" Margin="33,128,0,0" VerticalAlignment="Top" Width="720">
        <ListView.View>
            <GridView>
                <GridViewColumn Header="File" DisplayMemberBinding="{Binding File}"/>
                <GridViewColumn Header="Size" DisplayMemberBinding="{Binding Size}"/>
            </GridView>
        </ListView.View>
    </ListView>
    
  2. 将具有指定绑定属性的 pscustomobject 传递给 ListView

function ChooseFiles
{
  $WPFFilesListView.Clear()
  $filesToCopy = Get-Files
  $filesToCopy.FileNames | ForEach-Object {
    $currentfilesize = (Get-Item $_).Length
    $currentfilesize = DisplayInBytes -num $currentfilesize
    $WPFFilesListView.Items.Add([pscustomobject]@{File=$_;Size=$currentfilesize})
  }
}

【讨论】:

  • 一百万,它成功了:)
猜你喜欢
  • 2015-05-13
  • 2022-01-10
  • 1970-01-01
  • 1970-01-01
  • 2016-09-19
  • 1970-01-01
  • 2011-09-18
  • 2014-01-31
相关资源
最近更新 更多