使用form返回变量无法生成返回值

时间:2016-09-02 06:42:05

标签: .net winforms powershell

我正在为一个用户编写脚本,该脚本连接多个PDF文件并将表格数据附加为文本文件。现在的问题是用户可以手动命名文本文件,以便脚本必须验证哪个PDF文件属于数据。通常它会按名称进行,但由于用户可以(并且显然)更改PDF的名称,脚本应要求用户选择要合并的正确PDF。

我在我的脚本中编写了一个函数,它使用Winforms显示包含可用PDF文件的Listbox,用户应选择一个。

function Select-Rechnung
{
    param
    (
        [string] $Rechnung,
        [string[]] $PdfFiles
    )

    $form = New-Object System.Windows.Forms.Form
    $form.Text = "Rechnung wählen"
    $form.Size = New-Object System.Drawing.Size(640,320)
    $form.StartPosition = "CenterScreen"

    $form.KeyPreview = $true
    $form.Add_KeyDown({if($_.KeyCode -eq "Enter") { $x = $PdfFiles[$ListBox.SelectedIndex]; $form.Close() }})
    $form.Add_KeyDown({if($_.KeyCode -eq "Escape") { $form.Close() }})

    $OkButton = New-Object System.Windows.Forms.Button
    $OkButton.Location = New-Object System.Drawing.Size(240,240)
    $OkButton.Size = New-Object System.Drawing.Size(75,23)
    $OkButton.Text = "OK"
    $OkButton.Add_Click({ $x = $PdfFiles[$ListBox.SelectedIndex]; $form.Close() })
    $form.Controls.Add($OkButton)

    $CancelButton = New-Object System.Windows.Forms.Button
    $CancelButton.Location = New-Object System.Drawing.Size(325,240)
    $CancelButton.Size = New-Object System.Drawing.Size(75,23)
    $CancelButton.Text = "Abbrechen"
    $CancelButton.Add_Click({$form.Close()})
    $form.Controls.Add($CancelButton)

    $Label = New-Object System.Windows.Forms.Label
    $Label.Location = New-Object System.Drawing.Size(10,20) 
    $Label.Size = New-Object System.Drawing.Size(600,20) 
    $Label.Text = [string]::Format("Für die Rechnung {0} wurden mehrere mögliche Dateien gefunden. Bitte auswählen:", $Rechnung)
    $form.Controls.Add($Label)

    $ListBox = New-Object System.Windows.Forms.ListBox
    $ListBox.Location = New-Object System.Drawing.Size(10,40)
    $ListBox.Size = New-Object System.Drawing.Size(600, 20)
    $ListBox.Height = 200
    foreach($pdfFile in $PdfFiles)
    {
        [void] $ListBox.Items.Add($pdfFile)
    }
    $form.Controls.Add($ListBox)

    $form.TopMost = $true
    $form.Add_Shown({$form.Activate()})
    [void] $form.ShowDialog()

    $x
}

现在,在KeyDown处理程序或Click处理程序中,该函数应将选定的PDF文件分配给变量$x。我已检查$PdfFiles是否正确地传递给函数,并且在处理程序执行期间,$PdfFiles[$ListBox.SelectedIndex]实际上具有正确的字符串值。但是,在处理完表单$x后访问ShowDialog时,它为空,因此函数的返回值为空。

为什么不将值(在处理程序中正确计算的值)分配给我的变量并返回它?

3 个答案:

答案 0 :(得分:2)

通过引入类似哈希表的引用类型来尝试它,并使用它来修改和返回值,如此

function Select-Rechnung
{
    param
    (
        [string] $Rechnung,
        [string[]] $PdfFiles
    )

    $x = @{ Value = '' }

    ...
    $OkButton.Add_Click({ $x.Value = $PdfFiles[$ListBox.SelectedIndex];
    ...

    $x.Value
}

您还可以通过使用
访问外部作用域的$x变量来实现目标 Set-Variable -Name x -Scope 1 $PdfFiles[$ListBox.SelectedIndex]
或者其他一个范围修饰符(globalscript - 请参阅about scopes),如果您想避免额外的哈希表。

答案 1 :(得分:2)

我现在通过解决这个问题来做到这一点。在KeyDownClick处理程序中,我不再直接设置变量,而是:

$form.Add_KeyDown({
    if($_.KeyCode -eq "Enter") 
    { 
         if($ListBox.SelectedIndex -ge 0) 
         { 
             $form.DialogResult = System.Windows.Forms.DialogResult]::OK;
         } 
         $form.Close() 
    }
})

最后,我会检查DialogResult

[string]$x = $null
if($form.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK)
{
    $x = $PdfFiles[$ListBox.SelectedIndex]
}   
return $x

这确实导致返回正确的值。

答案 2 :(得分:1)

我建议您将$ x变量的范围级别更改为至少脚本范围,以便在脚本中的任何位置都可以使用它。现在它只是"生活"内部脚本块的句柄事件。将每个$ x变量更改为 $ script:x

function Select-Rechnung
{
    param
    (
        [string] $Rechnung,
        [string[]] $PdfFiles
    )

    $form = New-Object System.Windows.Forms.Form
    $form.Text = "Rechnung wählen"
    $form.Size = New-Object System.Drawing.Size(640,320)
    $form.StartPosition = "CenterScreen"

    $form.KeyPreview = $true
    $form.Add_KeyDown({if($_.KeyCode -eq "Enter") { $script:x = $PdfFiles[$ListBox.SelectedIndex]; $form.Close() }})
    $form.Add_KeyDown({if($_.KeyCode -eq "Escape") { $form.Close() }})

    $OkButton = New-Object System.Windows.Forms.Button
    $OkButton.Location = New-Object System.Drawing.Size(240,240)
    $OkButton.Size = New-Object System.Drawing.Size(75,23)
    $OkButton.Text = "OK"
    $OkButton.Add_Click({ $script:x = $PdfFiles[$ListBox.SelectedIndex]; $form.Close() })
    $form.Controls.Add($OkButton)

    $CancelButton = New-Object System.Windows.Forms.Button
    $CancelButton.Location = New-Object System.Drawing.Size(325,240)
    $CancelButton.Size = New-Object System.Drawing.Size(75,23)
    $CancelButton.Text = "Abbrechen"
    $CancelButton.Add_Click({$form.Close()})
    $form.Controls.Add($CancelButton)

    $Label = New-Object System.Windows.Forms.Label
    $Label.Location = New-Object System.Drawing.Size(10,20) 
    $Label.Size = New-Object System.Drawing.Size(600,20) 
    $Label.Text = [string]::Format("Für die Rechnung {0} wurden mehrere mögliche Dateien gefunden. Bitte auswählen:", $Rechnung)
    $form.Controls.Add($Label)

    $ListBox = New-Object System.Windows.Forms.ListBox
    $ListBox.Location = New-Object System.Drawing.Size(10,40)
    $ListBox.Size = New-Object System.Drawing.Size(600, 20)
    $ListBox.Height = 200
    foreach($pdfFile in $PdfFiles)
    {
        [void] $ListBox.Items.Add($pdfFile)
    }
    $form.Controls.Add($ListBox)

    $form.TopMost = $true
    $form.Add_Shown({$form.Activate()})
    [void] $form.ShowDialog()

    $script:x
}

现在正以这种方式为我工作:

Select-Rechnung -Rechnung 'string' -PdfFiles 'file1.pdf','file2.pdf','file3.pdf'

输出:

file3.pdf