1

I have a winform application which populate some data after I click on $button_UpdateTS, how do I add the data stored in a variable, that comes available after I click on that button ?

The data I want in my list view is stored in an array called $results

$button_UpdateTS = New-Object System.Windows.Forms.Button
$button_UpdateTS.Location = New-Object System.Drawing.Size(15, 954)
$button_UpdateTS.Size = New-Object System.Drawing.Size(320, 32)
$button_UpdateTS.TextAlign = "MiddleCenter"
$button_UpdateTS.Text = “Update Tasksequence”
$button_UpdateTS.Add_Click( { $Results = Set-DynamicVariables 
-Manufacturer "$($listview_Vendor.SelectedItems)" 
-TSPackageID "$($ListView_Tasksequences.SelectedItems.SubItems[1].Text)" -WhatIf })
    $Form.Controls.Add($button_UpdateTS)

Which gives me :

$Results = 
SKUNotExistsDriverName    : XPS Notebook 9560
SKUNotExistsDriverID      : PS10053F
SKUNotExistsDriverSKU     : 07BE
SKUNotExistsDriverVersion : A12
SKUNotExistsBIOSName      : XPS Notebook 9560
SKUNotExistsBIOSID        : PS10053E
SKUNotExistsBIOSSKU       : 07BE
SKUNotExistsBIOSVersion   : 1.15.0

This is the list I want it stored in :

$Global:listview_NotExists_SKU = New-Object System.Windows.Forms.ListView
$listview_NotExists_SKU.Location = New-Object System.Drawing.Size(515, 670)
$listview_NotExists_SKU.Size = New-Object System.Drawing.Size(486, 235)
$listview_NotExists_SKU.View = "Details"
$listview_NotExists_SKU.FullRowSelect = $true
$listview_NotExists_SKU.MultiSelect = $true
$listview_NotExists_SKU.Sorting = "None"
$listview_NotExists_SKU.AllowColumnReorder = $true
$listview_NotExists_SKU.GridLines = $true
$listview_NotExists_SKU.Add_ColumnClick( { SortListView $this $_.Column })
$Form.Controls.Add($listview_NotExists_SKU)

I tried with this function, but that does not work:

Function Get-Results {
        ForEach ($Result in $Results) {
            $listview_NotExists_SKU.Items.Add($Result) 
       }
}

$Form.Add_Shown( { $Form.Load; Get-results })
BenDK
  • 131
  • 2
  • 7

1 Answers1

1

Because an event-handling script block added with e.g. .Add_Click() runs in in a child scope of the caller, assigning to variable $Results there ($Results = ...) creates a scope-local variable that neither the scope in which the event handler was set up nor subsequently invoked event handlers can see.

To create a variable in the script scope, which subsequently invoked event handlers can see as well[1], use the $script: scope specifier:

$button_UpdateTS.Add_Click( { $script:Results = ... } )

Note:

  • If the scope in which the event handlers are set up isn't the script scope (e.g., if the code is inside a function) and you want to more generically reference that scope from within an event handler, use Set-Variable -Scope 1 -Name Results -Value ..., which targets the respective parent scope.[1]

  • An alternative to setting a variable in the parent scope explicitly is to use a hashtable defined in the parent scope whose entries can be used in lieu of variables that the event-handler script blocks can modify too.[2] See this answer for an example.


[1] For more information about scopes in PowerShell, see the bottom section of this answer.

[2] This technique works, because even though the variable containing the hashtable is defined in the parent scope, the child scope can access its value and modify the entries of the referenced hashtable object rather than the variable itself.

mklement0
  • 382,024
  • 64
  • 607
  • 775
  • Well, I was about to ask exactly this but I see you already updated your answer. I understand that the child scope can see the value of the parent's scope variable and normally it would not be able to update it's value, but why or how is it possible that the child's scope (when using a hashtable) can update the value of a hashtable Key and even add/remove Keys? If it's too much hassle answering here I can definitely ask a new question but I would much appreciate to understand why does this work. – Santiago Squarzon Oct 27 '21 at 23:12
  • @SantiagoSquarzon, footnote [2] is meant to answer your question - I'm happy to improve it if you tell me where it falls short. Note the distinction between a _variable object_ and the _object it references_. – mklement0 Oct 27 '21 at 23:15
  • Yes, the footnote explains that it (child scope) can modify it's members but why it is able to do that? – Santiago Squarzon Oct 27 '21 at 23:18
  • 1
    @SantiagoSquarzon, descendent scopes can _get_ the value of variables in an ancestral scope. If the _value_ of such a variable is a _mutable object_ - such as a hashtable - modifying that object also surfaces in the variable (value) in the ancestral scope. – mklement0 Oct 27 '21 at 23:23
  • Oh my, thank you for helping me understand. I guess I already knew this by practice but not by theory. In addition to your comment this helped me understand further: "Value types (numbers, strings, booleans) are always immutable, but arrays, objects, and hashtables are mutable." - Thanks again! – Santiago Squarzon Oct 27 '21 at 23:34
  • 1
    You're welcome, @SantiagoSquarzon. The value-type vs. reference-type dichotomy is a good _rule of thumb_: value types _typically are_ immutable, as officially _recommended_, but technically they _can be mutable_. – mklement0 Oct 28 '21 at 01:21