【问题标题】:Powershell pass textbox as function argumentPowershell将文本框作为函数参数传递
【发布时间】:2019-08-27 09:02:33
【问题描述】:

我正在使用带有System.Windows.Forms 的 PowerShell 制作一个简单的 GUI 表单。

对于每个文本框-按钮对,我希望按钮打开文件浏览器,一旦选择了文件,文件路径应该写在相应的文本框中。

在下面的代码中,New-TextBox 创建一个标签和一个文本框,New-Button 创建一个按钮。

使用这些函数可以创建带有 3 个按钮的 3 个文本框。

然后我创建了函数Set-FileDialogButton。它需要一个按钮和文本框作为参数,并且应该创建一个打开文件浏览器的按钮单击事件,获取选定的文件路径并将其从参数写入文本框。

点击事件和文件浏览器有效。但是,选择文件后,我得到了

The property 'Text' cannot be found on this object. Verify that the property exists and can b
e set.
At D:\...\test.ps1:62 char:5
+                 $inputTextBox.Text = $FileBrowser.FileName
+                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : PropertyNotFound

所以我假设在函数中传递文本框时我做错了。如果我不将点击事件包装在一个函数中,我的代码就可以正常工作。

代码:

Add-Type -assembly System.Windows.Forms
$main_form = New-Object System.Windows.Forms.Form
$main_form.Text ='AP209 Converter GUI'

$main_form.Width = 300
$main_form.Height = 200
$main_form.AutoSize = $true

#Creates a label and text box:
function New-TextBox($labelText, $x, $y, $w){
    $label = New-Object System.Windows.Forms.Label
    $label.Text = $labelText
    $label.Location  = New-Object System.Drawing.Point($x, $y)
    $label.AutoSize = $true
    $main_form.Controls.Add($label)

    $textbox            = New-Object system.Windows.Forms.TextBox
    $textbox.multiline  = $false
    $textbox.width      = $w
    $textbox.height     = 20
    $textbox.location   = New-Object System.Drawing.Point(($x + 50), $y)
    $main_form.Controls.Add($textbox)

    return $textbox
}
#Creates a button with $text as label:
function New-Button($text, $x, $y, $w, $h){
    $button = New-Object System.Windows.Forms.Button
    $button.Location = New-Object System.Drawing.Size($x, $y)
    $button.Size = New-Object System.Drawing.Size($w, $h)
    $button.Text = $text
    $main_form.Controls.Add($button)
    return $button
}

$textBoxW = 100
$labelX = 0
$buttonX = $x + 155

$y = 10
$dy = 30

$buttonW = 25
$buttonH = 20

#Create 3 text boxes and buttons:
$textbox1 = New-TextBox "File 1" $labelX  $y $textBoxW
$button1  = New-Button  "..."    $buttonX $y $buttonW $buttonH
$y = $y + $dy
$textbox2 = New-TextBox "File 2" $labelX  $y $textBoxW
$button2  = New-Button  "..."    $buttonX $y $buttonW $buttonH
$y = $y + $dy
$textbox3 = New-TextBox "File 3" $labelX  $y $textBoxW
$button3  = New-Button  "..."    $buttonX $y $buttonW $buttonH


#Set click event to button:
function Set-FileDialogButton($button, $inputTextBox){
    $button.Add_Click(
        {
            $FileBrowser = New-Object System.Windows.Forms.OpenFileDialog -Property @{ InitialDirectory = $loadpath}
            $fileBrowserReturned = $FileBrowser.ShowDialog()
            if($fileBrowserReturned -eq "OK"){
                $inputTextBox.Text = $FileBrowser.FileName
                $inputTextBox.SelectionStart = $inputTextBox.Text.Length;
            }                   
        }
    )
}
Set-FileDialogButton $button1 $textbox1
Set-FileDialogButton $button2 $textbox2
Set-FileDialogButton $button3 $textbox3



$main_form.ShowDialog()

【问题讨论】:

  • 如果您只在 AddClick 事件中分别处理每个文件浏览按钮,您的代码会更容易且更具可读性。
  • @Scepticalist 这个想法是通过将 AddClick 包装在一个函数中来删除重复代码,并使其更具可读性...

标签: winforms powershell


【解决方案1】:

您需要在定义时捕获变量引用并将它们绑定到事件处理程序的本地范围。你可以通过GetNewClosure() 做到这一点:

#Set click event to button:
function Set-FileDialogButton($button, $inputTextBox){
    $button.Add_Click(
        {
            $FileBrowser = New-Object System.Windows.Forms.OpenFileDialog -Property @{ InitialDirectory = $loadpath}
            $fileBrowserReturned = $FileBrowser.ShowDialog()
            if($fileBrowserReturned -eq "OK"){
                $inputTextBox.Text = $FileBrowser.FileName
                $inputTextBox.SelectionStart = $inputTextBox.Text.Length;
            }                   
        }.GetNewClosure()
    )
}

使用您当前的代码,在事件处理程序执行之前,您的变量不会被绑定。因此 inputTextBox 为空。

【讨论】:

    【解决方案2】:

    试试这个:

    Add-Type -assembly System.Windows.Forms
    $main_form = New-Object System.Windows.Forms.Form
    $main_form.Text ='AP209 Converter GUI'
    
    $main_form.Width = 300
    $main_form.Height = 200
    $main_form.AutoSize = $true
    
    #Creates a label and text box:
    function New-TextBox($labelText, $x, $y, $w){
        $label = New-Object System.Windows.Forms.Label
        $label.Text = $labelText
        $label.Location  = New-Object System.Drawing.Point($x, $y)
        $label.AutoSize = $true
        $main_form.Controls.Add($label)
    
        $textbox            = New-Object system.Windows.Forms.TextBox
        $textbox.multiline  = $false
        $textbox.width      = $w
        $textbox.height     = 20
        $textbox.location   = New-Object System.Drawing.Point(($x + 50), $y)
        $main_form.Controls.Add($textbox)
    
        return $textbox
    }
    #Creates a button with $text as label:
    function New-Button($text, $x, $y, $w, $h){
        $button = New-Object System.Windows.Forms.Button
        $button.Location = New-Object System.Drawing.Size($x, $y)
        $button.Size = New-Object System.Drawing.Size($w, $h)
        $button.Text = $text
        $main_form.Controls.Add($button)
        return $button
    }
    
    $textBoxW = 100
    $labelX = 0
    $buttonX = $x + 155
    
    $y = 10
    $dy = 30
    
    $buttonW = 25
    $buttonH = 20
    
    #Create 3 text boxes and buttons:
    $textbox1 = New-TextBox "File 1" $labelX  $y $textBoxW
    $textbox1.Name = 'textbox1'
    $button1  = New-Button  "..."    $buttonX $y $buttonW $buttonH
    $button1.Name = 'button1'
    $y = $y + $dy
    $textbox2 = New-TextBox "File 2" $labelX  $y $textBoxW
    $textbox2.Name = 'textbox2'
    $button2  = New-Button  "..."    $buttonX $y $buttonW $buttonH
    $button2.Name = 'button2'
    $y = $y + $dy
    $textbox3 = New-TextBox "File 3" $labelX  $y $textBoxW
    $textbox3.Name = 'textbox3'
    $button3  = New-Button  "..."    $buttonX $y $buttonW $buttonH
    $button3.Name = 'button3'
    
    
    foreach( $control in $main_form.Controls ) {
    
        if( $control.Name -like 'button*' ) {
            $control.Add_Click(
                {
                    $FileBrowser = New-Object System.Windows.Forms.OpenFileDialog -Property @{ InitialDirectory = $loadpath}
                    $fileBrowserReturned = $FileBrowser.ShowDialog()
                    if($fileBrowserReturned -eq [System.Windows.Forms.DialogResult]::OK ) {
                        $controlNumber = $this.Name -replace '^\D+(\d+)$', '$1'
                        $textboxName   = 'textbox' + $controlNumber
                        foreach( $control in $this.parent.Controls ) {
                            if( $control.Name -eq $textboxName ) {
                                $control.Text = $FileBrowser.FileName 
                                $control.SelectionStart = $control.Text.Length
                            }
                        }
                    }
                } )
    
        }
    
    }
    
    
    $main_form.ShowDialog()
    

    【讨论】:

    • 答案@Palle Due 效果很好。我也试过了,但看起来 $control.Name -like 'button*' 永远不会返回 true?
    • 您必须为控件命名。复制并粘贴我的源代码完成,它会工作。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-28
    • 2023-03-26
    • 1970-01-01
    • 1970-01-01
    • 2021-04-13
    相关资源
    最近更新 更多