Подстановка переменных - ссылка не работает - PullRequest
2 голосов
/ 27 января 2020

У меня есть этот код для тестирования GUI сборки в PowerShell, и я хочу сделать его короче, сделав функцию для создания метки или кнопки, чтобы упростить добавление большего количества из них впоследствии. То, что я хочу проверить здесь, это сделать так, чтобы при нажатии кнопки 1 он менял текст метки 1. Но я не могу заставить это работать. Это мой код:

Add-Type -assembly System.Windows.Forms
$main_form = New-Object System.Windows.Forms.Form
$main_form.Text = "Test1"
$main_form.Width = 250
$main_form.Height = 250

function add-Label
{
param($LabelNum, $LabelText)
$script:Label_Current = New-Variable -Name "Label_{$LabelNum}" -Value $LabelNum -Force -PassThru
$script:Label_Current = New-Object System.Windows.Forms.Label

$script:Label_Current.Name = "Label_$LabelNum"
$script:Label_Current.Text = "$LabelText"
$LabelHeight = 1+ $LabelNum * 50
$script:Label_Current.Location = New-Object System.Drawing.Point(10,$LabelHeight)

$main_form.Controls.Add($script:Label_Current)
}

function add-Button
{
param($ButtonNum, $ButtonText)
$Button_Current = New-Variable -name "Button_{$ButtonNum}" -Value $ButtonNum -Force -PassThru
$Button_Current = New-Object System.Windows.Forms.Button
$Button_Current.Text = "$ButtonText"
$ButtonHeight = 1+ $ButtonNum * 50
$Button_Current.Location = New-Object System.Drawing.Point(150,$ButtonHeight)
$Button_Current.Add_Click({$Label_Current.Text = "Test10"})
$main_form.Controls.Add($Button_Current)
}

add-Label -LabelNum 0 -LabelText "Test3"
add-Label -LabelNum 1 -LabelText "Test3"
add-Label -LabelNum 2 -LabelText "Test3"
add-Label -LabelNum 3 -LabelText "Test3"
add-Button -ButtonNum 0 -ButtonText "Test3"
add-Button -ButtonNum 1 -ButtonText "Test3"
add-Button -ButtonNum 2 -ButtonText "Test3"
add-Button -ButtonNum 3 -ButtonText "Test3"


$main_form.ShowDialog() 

Когда я запускаю его, как сейчас, все кнопки будут изменять только последнюю добавленную метку. Когда я скажу ему изменить текст указанного c номера ($Button_Current.Add_Click({$Label_1.Text = "Test10"}), он скажет «Объект не найден»

Заранее спасибо!

Ответы [ 3 ]

2 голосов
/ 27 января 2020

Вместо того, чтобы пытаться создать новые переменные для меток и кнопок, вы можете использовать для этого собственную коллекцию элементов управления форм и, используя имя элементов управления меткой, достаточно просто указать целевую метку c.

Примерно так:

Add-Type -AssemblyName System.Windows.Forms

function Add-Label ([int]$index, [string]$labelText) {
    $top  = 1 + $index * 50
    $temp = New-Object System.Windows.Forms.Label
    $temp.Name = "Label$index"
    $temp.Text = $labelText
    $temp.Location = New-Object System.Drawing.Point(10,$top)

    $main_form.Controls.Add($temp)
}

function Add-Button ([int]$index, [string]$buttonText, [string]$newLabelText) {
    $top   = 1 + $index * 50
    $temp  = New-Object System.Windows.Forms.Button
    $temp.Text = $buttonText
    $temp.Name = "Button$index"
    $temp.Location = New-Object System.Drawing.Point(150,$top)
    # store the new text for the label in the button Tag
    # because inside the Click() method, $newLabelText is unknown
    $temp.Tag = $newLabelText   

    $temp.Add_Click({ 
        # get the index for the label from the buttons name
        $labelIndex = [int]($this.Name -replace '\D')
        # use the Find method to get the wanted label by name
        $main_form.Controls.Find("Label$labelIndex", $true)[0].Text = $this.Tag
    })

    $main_form.Controls.Add($temp)
}

$main_form = New-Object System.Windows.Forms.Form
$main_form.Text   = "Test1"
$main_form.Width  = 250
$main_form.Height = 250

# add the controls to the form
(0..3) | ForEach-Object { 
    Add-Label $_ "Test$_"
    Add-Button $_ "Button$_" "New Label Text $_" 
}

$main_form.ShowDialog() 

# don't forget to dispose of the form when done !
$main_form.Dispose()
1 голос
/ 28 января 2020

Это может быть немного «умным» решением, а не «простым для понимания и поддержки» решением, но я все равно добавил его, потому что оно использует то, о чем я не знал до того, как начал изучать этот ответ - то есть метод ScriptBlock.GetNewClosure :

Add-Type -assembly System.Windows.Forms

function New-Label
{
    param($LabelNum, $LabelText)
    $label = New-Object System.Windows.Forms.Label
    $label.Name = "Label_$LabelNum"
    $label.Text = $LabelText
    $LabelY = 1 + $LabelNum * 50
    $label.Location = New-Object System.Drawing.Point(10, $LabelY)
    return $label
}

function New-Button
{
    param($ButtonNum, $ButtonText)
    $button = New-Object System.Windows.Forms.Button
    $button.Text = $ButtonText
    $ButtonY = 1 + $ButtonNum * 50
    $button.Location = New-Object System.Drawing.Point(150, $ButtonY)
    return $button
}

function New-Form
{

    $form = New-Object System.Windows.Forms.Form
    $form.Text = "Test1"
    $form.Width = 250
    $form.Height = 250

    # create an array of labels
    $labels = 0..3 | % {
        New-Label -LabelNum $_ -LabelText "label_$($_)"
    }

    # add the labels to the form
    $labels | % { $form.Controls.Add($_) }

    # create an array of buttons
    $buttons = 0..3 | % {
        New-Button -ButtonNum $_ -ButtonText "button_$($_)"
    }

    # add the buttons to the form
    $buttons | % { $form.Controls.Add($_) }

    # add event handlers onto the buttons
    for( $i = 0; $i -lt $buttons.Length; $i++ )
    {
        $buttons[$i].Add_Click(
            { $labels[$i].Text = $buttons[$i].Text }.GetNewClosure()
        )
    }
    return $form
}

$main_form = New-Form
$main_form.ShowDialog() 

Я сделал несколько вещей, которые (на мой взгляд) упрощают ваш код, удаляя ссылки на глобальные переменные внутри функций. Вместо того, чтобы добавлять метки и кнопки к самим $main_form функциям, они просто возвращают независимую метку или кнопку и позволяют вызывающему коду принять решение об их использовании.

«Умный» (но, возможно, не такой «умный») ") бит использует GetNewClosure в New-Form - сначала мы создаем параллельные массивы меток и кнопок, а затем объединяем их вместе, чтобы создать обработчики событий.

Это дает то преимущество, что вам не нужно снова «найти» метки и кнопки по имени после их создания, потому что вы храните ссылки на них в массивах, но у него есть недостаток в том, что он использует GetNewClosure, что нелегко объяснить, что он на самом деле делает!

Я думаю, что ответ Тео может быть более прагматичным c, но вот несколько ссылок на документацию для GetNewEnclosure на тот случай, если вы захотите прочитать об этом ...

Надеюсь, это поможет ...

0 голосов
/ 28 января 2020

Я решил проблему так:

Add-Type -assembly System.Windows.Forms
$main_form = New-Object System.Windows.Forms.Form
$main_form.Text = "Test1"
$main_form.Width = 250
$main_form.Height = 250

$global:LabelArray = @()



function add-Label
{
param($LabelNum, $LabelText)
$Labelvar = New-Object System.Windows.Forms.Label
$LabelHeight = 1+ $LabelNum * 50
$dynamicVar = "Label_{0}" -f $LabelNum
$CurrentVar = New-variable -Name $dynamicVar -Value $Labelvar -PassThru -Force
$global:LabelArray += $CurrentVar

$global:LabelArray[$LabelNum].Value.Text = "$LabelText"
$global:LabelArray[$LabelNum].Value.Location = New-Object System.Drawing.Point(10,$LabelHeight)
$main_form.Controls.Add($global:LabelArray[$LabelNum].Value)
}

function add-Button
{
param($ButtonNum, $ButtonText)
$Button_Current = New-Variable -name "Button_{$ButtonNum}" -Value $ButtonNum -Force -PassThru
$Button_Current = New-Object System.Windows.Forms.Button
$Button_Current.Text = "$ButtonText"
$ButtonHeight = 1+ $ButtonNum * 50
$Button_Current.Location = New-Object System.Drawing.Point(150,$ButtonHeight)

switch($ButtonNum)
{
0 {$Button_Current.Add_Click({write-host $script:LabelArray[0].Value.Text})}
1 {$Button_Current.Add_Click({write-host $script:LabelArray[1].Value.Text})}
2 {$Button_Current.Add_Click({write-host $script:LabelArray[2].Value.Text})}
3 {$Button_Current.Add_Click({write-host $script:LabelArray[3].Value.Text})}
}

$main_form.Controls.Add($Button_Current)
}



add-Label -LabelNum 0 -LabelText "Test1"
add-Label -LabelNum 1 -LabelText "Test2"
add-Label -LabelNum 2 -LabelText "Test3"
add-Label -LabelNum 3 -LabelText "Test4"
add-Button -ButtonNum 0 -ButtonText "Test3"
add-Button -ButtonNum 1 -ButtonText "Test3"
add-Button -ButtonNum 2 -ButtonText "Test3"
add-Button -ButtonNum 3 -ButtonText "Test3"


$main_form.ShowDialog() 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...