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
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With