循环通过WPF / Powershell中的控件

时间:2010-08-06 08:03:55

标签: wpf powershell loops wpf-controls

我正在尝试遍历Powershell / WPF应用程序中的一些控件。没什么好看的,只需在mouseEnter事件上设置一些文字。

如果我不循环代码,它可以正常工作:

$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"
     })     

但如果我尝试与循环相同的东西,它会设置所有控件MouseEnter事件,将文本设置为“Four”,即数组的最后一个元素:

$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
     })
}

任何人都有任何想法,为什么会这样,以及如何解决它?

谢谢,

好的 - 这甚至更怪......

尝试使用肯特建议的解决方案来解决这个问题。我使用$ localControl也一样,所以我想我会尝试使用数组来确保每个条目都是不同的:

$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
     })
}

我所知道的行为是,每当我鼠标移动一个控件时,文本只会逐步增加数组。例如,我悬停的第一个控件将输出“One”,下一个将输出“Two”,依此类推,直到我的数组在输出null时耗尽。

这个“一个”,“两个”,“三个”,“四个”输出顺序是相同的,无论我将鼠标悬停在控件上的顺序。

......等一下。已将$ i = $ i + 1放入MouseEnter!

修改为:

$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
}

将所有输出设置为null。

2 个答案:

答案 0 :(得分:1)

您需要从scriptblocks中创建一个闭包。你面临的是这样的:

$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

所以如果你做一个闭包,它可能会有所帮助:

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

scriptblock中的变量未绑定到创建的范围。相反,它们在当前范围内进行评估:

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

答案 1 :(得分:0)

获取$control的本地副本:

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

您的循环完成后,所有对$control的引用都将得到解决,因此它们都会引用您收藏中的最后一项。