Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scope issue with .add_Click({})

I try to dynamically assign functions to dynamically created buttons. Unfortunately, variables are not being passed to the .add_Click({}) block as I expect it.

I tried already to create a global variable $Global:Var, or to enter the variable in a hash table or created a function which I called in my click statement. However, at most I only got the last item from the list.

How can I dynamically allocate a variable to the $var.add_Click({}) block?

My code:

Foreach ($Tenant in $Customer){
    if (-not ($Tenant -eq "")){
        $Tenant_Button = New-Object -TypeName System.Windows.Forms.Button
        $Tenant_Button.Location = New-Object -TypeName System.Drawing.Size(5, (15 + ($Tenant_Counter++ * 40)))
        $Tenant_Button.Size = New-Object -TypeName System.Drawing.Size(125, 35)
        $Tenant_Button.Text = $Tenant
        $Tenant_Button.Font = $Font_AccountButton

#Below starts the .add_Click({}) part!#
#Above variables are not accessible in the below part. 

        $Tenant_Button.add_Click({
            $Customer_Domain = ($CsvImport | Where-Object {$_.command_name -match "Admin $($Tenant_Button.Text)"}).command_name
            $DomainCounter = 0
            Foreach ($Domain in $Customer_Domain){
                $Button_Cust = New-Object -TypeName System.Windows.Forms.Button
                $Button_Cust.Location = New-Object -TypeName System.Drawing.Size(545, (25 + ($DomainCounter++ * 40)))
                $Button_Cust.Size = New-Object -TypeName System.Drawing.Size(125, 35)
                $Button_Cust.Text = $Domain

                $MainWindow.Controls.Add($Button_Cust)

                $Button_Cust.add_Click({
                    $FunctionIndex = [array]::IndexOf(($CsvImport).command_name, $Domain)
                    $Customer_Function = ($CsvImport[$FunctionIndex]).object_command

                    Invoke-Expression -Command $Customer_Function
                })
            }
         })
         $GroupBox_Acc.Controls.Add($Tenant_Button)

As mentioned before, with the global variable or the function or a hash table solution I managed to enter one variable content but always only the last. Hence, all buttons had the same function assigned. How can I assign twenty different functions to twenty different buttons?

To complete the example I provide the surrounding code. Enter the 'problematic' code in the $Button_Accounts.add_Click({}) (It can be found in the end of the below code) command.

$CsvImport = Import-Csv -Delimiter ',' -LiteralPath 'C:\Test\Coding\commands.csv'

$MainWindow = New-Object -TypeName System.Windows.Forms.Form
$MainWindow.Text = 'Administrator Window'
$MainWindow.Width = 600
$MainWindow.Height = 555
$MainWindow.AutoSize = $true

$Button_Accounts = New-Object -TypeName System.Windows.Forms.Button
$Button_Accounts.Location = New-Object -TypeName System.Drawing.Size(25, 225)
$Button_Accounts.Size = New-Object -TypeName System.Drawing.Size(200, 75)
$Button_Accounts.Text = 'Accounts'

    $MainWindow.Controls.Add($Button_Accounts)

$ComboBox = New-Object -TypeName System.Windows.Forms.ComboBox
$GroupBox_Acc = New-Object -TypeName System.Windows.Forms.GroupBox

$Customer = $CsvImport.customer | Select-Object -Unique

$GroupBox_Acc.Text = 'Tenant List:'
$GroupBox_Acc.Location = New-Object -TypeName System.Drawing.Point(250, 25)
$GroupBox_Acc.Size = New-Object -TypeName System.Drawing.Size(270, 500)

$MainWindow.Controls.Add($GroupBox_Acc)

$Button_Accounts.Add_Click({
## Add above code here ##
})
$MainWindow.ShowDialog()

An example of the csv content:

command_group, Customer, command_name, object_commmand
Accounts, AAAA, Add Admin AP account, add_AP_admin_account
Accounts, AAAA, Add Admin AP Local account, add_AP_Local_admin_account
Accounts, BBBB, Add Admin ARL G account, add_ARLG_admin_account
Accounts, BBBB, Add Admin ARL CO account, add_ARLCO_admin_account
like image 606
Alex_P Avatar asked Sep 16 '26 19:09

Alex_P


1 Answers

So lets talk about why it doesnt work first.

The script block {} is using the last value of the variable called before being run.

@("RED","BLUE","GREEN") | %{
    $Team = $_
    $Button.add_Click({
        [System.Windows.MessageBox]::Show($Team)
    })
}
$MainWindow.ShowDialog()

The Dialog will always pop back Green no matter if I hit the Red or Blue button it will still only popup Green. Thats because when the event for Click is sent it takes what the very last value of the variable $Team is.

So the fix is GetNewClosure()

@("RED","BLUE","GREEN") | %{
    $Team = $_
    $Button.add_Click({
        [System.Windows.MessageBox]::Show($Team)
    }.GetNewClosure())
}
$MainWindow.ShowDialog()

What GetNewClosure() on the scriptblock {} does is take the current value of the variables and stores them with the scriptblock. So if the variable changes it doesnt effect the variable being stored in the scriptblock.

The above code returns Red when Red is clicked, Blue when Blue is clicked and Green when Green is clicked.

like image 188
ArcSet Avatar answered Sep 19 '26 00:09

ArcSet



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!