Looping through controls in WPF / Powershell

此生再无相见时 提交于 2019-12-12 01:28:29

问题


I am trying to loop through some controls in a Powershell / WPF application. Nothing fancy, just setting some text on a mouseEnter event.

It works fine if I don't loop the code:

$reader = New-Object System.Xml.XmlNodeReader $xaml 
$d = [Windows.Markup.XamlReader]::Load($reader) 

$d.FindName("GridOne").add_mouseEnter({ 
        $d.FindName("HelpText").Content = "One"
     })

$d.FindName("GridTwo").add_mouseEnter({ 
        $d.FindName("HelpText").Content = "Two"
     })

$d.FindName("GridThree").add_mouseEnter({ 
        $d.FindName("HelpText").Content = "Three"
     })

$d.FindName("GridFour").add_mouseEnter({ 
        $d.FindName("HelpText").Content = "Four"
     })     

But if I try the same thing as a loop it sets all the controls MouseEnter events to set the text to "Four", the last element of the array:

$reader = New-Object System.Xml.XmlNodeReader $xaml 
$d = [Windows.Markup.XamlReader]::Load($reader) 

$arrControls = ("One","Two","Three","Four")

foreach ($control in $arrControls) { 
     $d.FindName("Grid$control").add_mouseEnter({ 
        $d.FindName("HelpText").Content = $control
     })
}

Anyone have any thoughts why this is, and how I can fix it?

Thanks,

Ben

OK - This is even weirder...

Tried to address this using a solution along the lines of Kent's suggestion. I got the same using $localControl, so thought I'd try using an array to ensure each entry was distinct:

$i = 0
$localControl = @()
foreach ($control in $arrControls) { 
    $localControl += $control
    write-host "$d.FindName('Grid$control').add_mouseEnter({ $d.FindName('HelpText').Content = $control })"
     $d.FindName("Grid$control").add_mouseEnter({ 
        $d.FindName("HelpText").Content = $localControl[$i]
        $i = $i + 1
     })
}

The behaviour I know get is that each time I mouseOver a control, the text just increments through the array one step. For example, the first control I hover over will output "One", the next will output "Two" and so on, until my array is exhausted when it just outputs null.

This "One", "Two", "Three", "Four" output order is the same regardless of the order I hover over the controls.

... Wait a minute. Have put the $i = $i + 1 in the MouseEnter!

Amended to:

$i = 0
$localControl = @()
foreach ($control in $arrControls) { 
    $localControl += $control
    write-host "$d.FindName('Grid$control').add_mouseEnter({ $d.FindName('HelpText').Content = $control })"
     $d.FindName("Grid$control").add_mouseEnter({ 
        $d.FindName("HelpText").Content = $localControl[$i]
     })
     $i = $i + 1
}

Sets all the outputs to null.


回答1:


You need to make a closure from the scriptblocks. What you are facing to is like this:

$i = 1
$block1 = { write-host $i }
$i = 2
$block2 = { write-host $i }
& $block1
& $block2

#---------------- after a change...

$i = 1
$block1 = { write-host $i }.GetNewClosure()
$i = 2
$block2 = { write-host $i }.GetNewClosure()
$i = 3
$block3 = { write-host $i }.GetNewClosure()
& $block1
& $block2
& $block3

So if you make a closure, it could help:

foreach ($control in $arrControls) { 
     $d.FindName("Grid$control").add_mouseEnter({ 
        $d.FindName("HelpText").Content = $control
     }.GetNewClosure())
}

Variables in scriptblock are not bound to the scope where there were created. Instead they are evaluated in current scope:

PS> $var = 'at beginning'
PS> $writer = { write-host $var }
PS> function test {
  $var = 1
  & $writer
  & { 
    $var = 10
    & $writer 
  }
}
PS> test
1
10
PS> & $writer
at beginning



回答2:


Take a local copy of $control:

foreach ($control in $arrControls) { 
     $localControl = $control
     $d.FindName("Grid$control").add_mouseEnter({ 
        $d.FindName("HelpText").Content = $localControl
     })
}

All references to $control are being resolved after your loop has completed, so they all refer to the last item in your collection.



来源:https://stackoverflow.com/questions/3421964/looping-through-controls-in-wpf-powershell

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!