Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamically assign information to an "Add_Click" event on a GUI button in powershell

Tags:

powershell

I want to Dynamically assign information to an "Add_Click" event on a GUI button in powershell.

So an overview - I am making a GUI tool, that loads some buttons for custom "fixes" for peoples PC's. Each button is loaded from a script, and each script contains variables for information such as, Button Name, Button Icon, as well as a function that does whatever the script is meant to do.

So as per example below, I am finding the problem is where I assign the Add_Click event. I'm sorry not sure how to explain better, but it does not seem to expand the $script variable, it will save the add_click as the variable, so that when I run the program, all buttons are using whatever was last stored in the variable $script (so all the buttons look different, but run the same script).

What I want to be able to do, is have each button use an Add_Click to run whatever script is stored in $script at the time the Add_Click is assigned in the "Foreach" loop.

Example script:

#Button Container (Array to store all the Buttons)
$ComputerActionButtons = @()

#Get all the script files that we will load as buttons
$buttonsFileArray = Get-ChildItem  "$dir\Addin\ " | Select -ExpandProperty Name

#Load Buttons
$ButtonTempCount = 1
Foreach ($script in $buttonsFileArray){
    . $dir\Addin\$script
    Write-Host "Loading Button: $ButtonName"

    # Generate button
    $TempButton = New-Object System.Windows.Forms.Button 
    $TempButton.Location = New-Object System.Drawing.Size(140,20) 
    $TempButton.Size = New-Object System.Drawing.Size(100,100) 
    $TempButton.Text = "$ButtonName"
    $TempButton.Image = $ButtonIcon
    $TempButton.TextImageRelation = "ImageAboveText"
    $TempButton.Add_Click({& $dir\Addin\$script}) 
    $ComputerActionButtons += $TempButton
}

#Add Buttons to panel
$CAButtonLoc = 20
Foreach ($button in $ComputerActionButtons){
    $button.Location = New-Object System.Drawing.Size(50,$CAButtonLoc)
    $ComputerActionsPanel.Controls.Add($button)
    $CAButtonLoc = $CAButtonLoc + 120
}

I have been researching variables, found you can do a New-Variable and Get-Variable command to dynamically set and get variable names, but using this does not seem to help because of the original problem.

I hope I have explained this well enough, please let me know if I can give more information to help.

Thank you,

Adam

like image 762
AdMaN Avatar asked Dec 06 '25 00:12

AdMaN


2 Answers

Instead of using GetNewClosure, which create new dynamic module, capture local scope variables to it and bind ScriptBlock to that module, so in fact you lose access to any function defined not in global scope, you can just store any button specific data in the button itself. Control base class have Tag property where you can store any data you want.

$TempButton.Tag=@{Script=$script}
$TempButton.Add_Click({param($Sender) & "$dir\Addin\$($Sender.Tag.Script)"})
like image 62
user4003407 Avatar answered Dec 08 '25 11:12

user4003407


You need to create a closure over the $script value at the time of assignment, instead of relying on the value of $script at runtime.

Fortunately, all ScriptBlocks support this with the GetNewClosure() method.

foreach($i in 1..3){
    $blocks += {echo $i}.GetNewClosure()
}
$blocks |Foreach-Object {$_.Invoke()}

which produces:

1
2
3

As opposed to

foreach($i in 1..3){
    $blocks += {echo $i}
}
$blocks |Foreach-Object {$_.Invoke()}

which produces:

3
3
3

What GetNewClosure() does is that it "captures" the variables referenced inside the ScriptBlock at that time and binds it to the local scope of the scriptblock.

This way the original $i variable (or $script for that matter) is "hidden" beneath an $i variable that has the same value as $i used to have - namely at the time GetNewClosure() was called

like image 30
Mathias R. Jessen Avatar answered Dec 08 '25 11:12

Mathias R. Jessen



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!