powershellvariableswpf-controls

Powershell v5 - variable name replacement when referring to WPF objects


I have 5 buttons which will fire file selection dialog to populate 5 text fields with the selected file-path. One button per file selection to fill a single WPF form text field. I don't want to do this with a switch statement by repeating 6 lines of code for each button. I want to simplify it.
I can get the sender button name but what I cant do is set the text field using a variable set through the switch option. Any ideas?

# General buttons file selection handler
 $WPFselectmergefile1.AddHandler([System.Windows.Controls.Button]::ClickEvent, $selectmergefile)
$WPFselectmergefile2.AddHandler([System.Windows.Controls.Button]::ClickEvent, $selectmergefile)

...

# handler function - as is - so this one works with lines per option.
[System.Windows.RoutedEventHandler]$Script:SelectMergeFile = {
param($sender, $e)
switch($sender.name) {
'selectmergefile1'  {
    FileDetails 'mergefile1' $WPFmergefile1.Text 2 # prep store 
    $x = File $Global:SourceFolder
    $WPFmergefile1.Text = $x
    $Global:SelectedMergeFile1 = $x
    FileDetails 'mergefile1' $WPFmergefile1.Text 2 # update store
 }
 'selectmergefile2' {
    FileDetails 'mergefile2' $WPFmergefile2.Text 2 
    $x = File $Global:SourceFolder
    $WPFmergefile2.Text = $x
    $Global:SelectedMergeFile2 = $x 
    FileDetails 'mergefile2' $WPFmergefile2.Text 2
 }
...

# What I want to do:
[System.Windows.RoutedEventHandler]$Script:SelectMergeFile = {
    param($sender, $e)
    $opt = $sender.Substring($sender.length-1)
    FileDetails "mergefile$opt" $WPFmergefile$opt.Text 2 
    $x = File $Global:SourceFolder
    $WPFmergefile$opt.Text = $x
    $Global:SelectedMergeFile$opt = $x  
    FileDetails "mergefile$opt" $WPFmergefile$opt.Text 2
}

I have tried for variable substitution:

"mergefile$opt"        # which works

$WPFmergefile$opt.Text    # which doesnt
$WPFmergefile$($opt).Text # which doesnt
$Global:SelectedMergeFile$opt = .. # which doesnt

Not sure what I need to do here..


Solution

  • As suggested in the comments, you can use Get-Variable -ValueOnly to retrieve the value of a variable by name:

    (Get-Variable "mergefile$opt" -ValueOnly).Text
    

    That being said, you might want to consider organizing your controls in a hashtable or other dictionary type instead.

    Assuming you have something like the folowing in place to automatically assign XAML controls to variables:

    $xaml.SelectNodes("//*[@Name]") | ForEach-Object {
        Set-Variable -Name "WPF$($_.Name)" -Value $Window.FindName($_.Name)
    }
    

    Replace it with:

    # create hashtable to hold the control references
    $WPFControls = @{}
    
    $xaml.SelectNodes("//*[@Name]") | ForEach-Object {
        $WPFControls[$_.Name] = $Window.FindName($_.Name)
    }
    

    Now you can easily reference the controls by name:

    $WPFControls["mergefile$opt"].Text = $x