Ivory February 2016

SelectedNode Property Of TreeView Object Hangs The Form Multithreading

I am working on a GUI script and I ran into a problem with my TreeView object. The problem occurs when I try to display the SelectedNode property or try to use the GetNodeAt() method of a TreeView that is displayed in another thread. I am able to display the TreeView object itself though. This is a sample of what I'm trying to do:

    $form = new-object system.windows.forms.form
    $treeview = new-object system.windows.forms.treeview
    $treeview.name = "tree view"
    $treeview.add_afterselect({write-host $this.selectednode})
    $treenode = new-object system.windows.forms.treenode
    $treenode.name = "tree node"
    $treenode.text = "tree node"
    $treenode2 = new-object system.windows.forms.treenode
    $treenode2.name = "second tree node"
    $treenode2.text = "second tree node"
    $treeview.nodes.addrange(@($treenode,$treenode2))
    $form.controls.add($treeview)
    $thread = [Management.Automation.Runspaces.RunspaceFactory]::CreateRunspace()
    $thread.Open()
    $thread.SessionStateProxy.SetVariable("form",$form)
    $thepipe = $thread.CreatePipeline({$form.Showdialog()})
    $thepipe.Input.Close()
    $thepipe.InvokeAsync()

The issue comes with the line $treeview.add_afterselect({write-host $this.selectednode}) When I click a node in the treeview the form will hang and I have to kill the Powershell process. The weird thing is I can display the TreeView object with no issue. Like this: $treeview.add_afterselect({write-host $this}). This will return the TreeView Object with no issues. I have also tried to use this instead $treeview.add_nodemouseclick({write-host $this.getnodeat($_.x,$_.y)}). This will also hang the form.

The problem comes from the form being displayed in another thread because when I do the same code but keep the form in the same thread I have no issues with displaying the selected node. like this:

    $form = new-object system.windows.fo        

Answers


Mathias R. Jessen February 2016

If you take a look at the TreeViewEventHandler method signature, you'll find that it takes two arguments, a sender and a TreeViewEventArgs object.

You can either "intercept" these by declaring your own named parameters, like so:

$treeview.add_AfterSelect({
    param($s,$e)

    # $e now refers to the TreeViewEventArgs
    Write-Host $e.Node
})

Or you can rely on the automatic event variables $Sender and $EventArgs:

$treeview.add_AfterSelect({
    Write-Host $EventArgs.Node
})

You may want to have a look at the help files for Register-ObjectEvent and about_Automatic_Variables


Don't use $this inside an event action - it's meant to be used as an instance reference in script method definitions, like so:

PS C:\> $obj = New-Object psobject -Property @{ Number = 3 }
PS C:\> $obj |Add-Member -Type ScriptMethod -Name GetSquare -Value { return $this.Number * $this.Number }
PS C:\> $obj.GetSquare()
9
PS C:\> $obj.Number = 4
PS C:\> $obj.GetSquare()
16

Post Status

Asked in February 2016
Viewed 2,005 times
Voted 13
Answered 1 times

Search




Leave an answer