Search code examples
powershellxamlvariablesstring-interpolationquoting

Xaml Variable in a Textblock


Learning PowerShell, I was suggested to solve an issue with Xaml. Not knowing Xaml at all, I was able to build a window the way I expect it to be for a private project of mine.

Playing around with Xaml and the below code, I was able to generate a Window and place a table in it. The idea is for later, that a loop will build the Table and so far that is also running.

Clear-Host
$Test = "Vocabulary Test Results"

$AnotherTest = '<TextBlock FontWeight="Bold" Margin="10" FontFamily="Arial" FontSize="28" Foreground="Blue" HorizontalAlignment="Center" Text="$Test" />  <Separator />'

#Load Assembly and Library
Add-Type -AssemblyName PresentationFramework

[xml]$Form = @"
<Window 


    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"  
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"  
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"  




    Title="MainWindow" Height="1000" Width="1000">  

     <ScrollViewer VerticalScrollBarVisibility="Auto">  

      <StackPanel VerticalAlignment="Top">  

        $AnotherTest

      <Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="1*" />
        <ColumnDefinition Width="1*" />
        <ColumnDefinition Width="1*" />
        <ColumnDefinition Width="1*" />
        <ColumnDefinition Width="1*" />
    </Grid.ColumnDefinitions>

    <Grid.RowDefinitions>
        <RowDefinition Height="1*" />
        <RowDefinition Height="1*" />
        <RowDefinition Height="1*" />
        <RowDefinition Height="1*" />
    </Grid.RowDefinitions>

    <TextBlock FontWeight="Bold" Margin="10" FontFamily="Arial" FontSize="18" Foreground="Black" HorizontalAlignment="Center" Text="Question Nr:" />
    <TextBlock Grid.Column="1" FontWeight="Bold" Margin="10" FontFamily="Arial" FontSize="18" Foreground="Black" HorizontalAlignment="Center" Text="Asked Question" />
    <TextBlock Grid.Column="2" FontWeight="Bold" Margin="10" FontFamily="Arial" FontSize="18" Foreground="Black" HorizontalAlignment="Center" Text="Expected Answer" />
    <TextBlock Grid.Column="3" FontWeight="Bold" Margin="10" FontFamily="Arial" FontSize="18" Foreground="Black" HorizontalAlignment="Center" Text="Your Answer" />
    <TextBlock Grid.Column="4" FontWeight="Bold" Margin="10" FontFamily="Arial" FontSize="18" Foreground="Black" HorizontalAlignment="Center" Text="Result" />



    <Button Grid.Column="1" Grid.Row="1">Button 5</Button>
    <Button Grid.Column="2" Grid.Row="1">Button 6</Button>
    <Button Grid.Row="2">Button 7</Button>
    <Button Grid.Column="1" Grid.Row="2">Button 8</Button>


</Grid>

</StackPanel>  
</ScrollViewer>  
</Window> 

"@

#Create a form
$XMLReader = (New-Object System.Xml.XmlNodeReader $Form)
$XMLForm = [Windows.Markup.XamlReader]::Load($XMLReader)

#Show XMLform
[void]$XMLForm.ShowDialog()

The issue I am fighting now is with the line containing this code:

$AnotherTest = '<TextBlock FontWeight="Bold" Margin="10" FontFamily="Arial" FontSize="28" Foreground="Blue" HorizontalAlignment="Center" Text="$Test" />  <Separator />'

I tried to add a variable behind "Text" but trying all kinds of things, I am not able to receive "Vocabulary Test Results" as text. Either I have an error messages or end up with with a blank field, or see the variable code and not the expected result.

I tried several ideas like

Text="$($Test")
Text=$Test
Text=""$Test""
Text={$Test}

and a few more. None of these did return the expected result. Trying to find some solution online, I did see some binding examples but must admit, that I did not fully understand, how that works.

Is there an easy way to solve this or is there no way around bindings and if yes, how would I do that?

Thank you for any help and suggestions


Solution

    • "..." quoting (double-quoting) is required in order for variable references (e.g. $text) or subexpressions (e.g., $($text + '!')) embedded in such a string to be expanded (interpolated), i.e., to be replaced with their value.

      • By contrast, the content of a '...' (single-quoted) string is interpreted verbatim - no expansion happens.
    • If you need to embed literal " characters in a "..." string, you need to escape them (each), which can be done in one of two ways:

      • As `", which is preferable, because ` generally acts as PowerShell's escape character; e.g.:
        • "Nat `"King`" Cole"
      • Alternatively, inside "..." only, you may use "".
        • "Nat ""King"" Cole"
    • You can avoid the need for this escaping if you use an expandable here-string (@"<newline>...<newline>"@), as you're already using to assign to the $Form variable; do note that the closing delimiter, "@, must be on its own line and at the very start of that line to be recognized.

    See about_Quoting_Rules.

    Applied to your scenario:

    • As an expandable string, with escaping:
    $AnotherTest = "<TextBlock FontWeight=`"Bold`" ... Text=`"$Test`" />  <Separator />"
    
    • As an expandable here-string, without the need for escaping:
    $AnotherTest = @"
    <TextBlock FontWeight="Bold" Margin="10" FontFamily="Arial" FontSize="28" Foreground="Blue" HorizontalAlignment="Center" Text="$Test" />  <Separator />
    "@