XAML issue - Creating a function

Hi All,

I’m trying to tidy up my code and one part is to create a function or module for my runspace creation to reduce repetition of code.

If I attempt to import the XAML and related code into the function, the code executes, but no GUI.

If I past the XAML and related code into the function it all works normally

I know there are issues with adding a script and XAML, but there must be a workaround to this?

Thanks

James

#Create a synchronised hashtable to share variables between runspaces if required
If($sync.count -lt 1){$sync = [hashtable]::Synchronized(@{})}

#Dynamically generate runspaces and related control variables
Function createRunspace {
    param(
        $shortName,
        $code,
        $debug
    )

    #name of runspace set manually or obtained from code
    $runspaceName = $shortName + "CPRunspace"
    $runspaceCmd = $shortName + "Cmd"
    $runspaceInvoke = $shortName + "Invoke"
    $runspaceClose = $shortName + "Close"

    #define variable if required
    If($debug){
        $path = $sync.path = $PSScriptRoot
        $sync.PCUser = $env:USERNAME 
        $sync.alertFontSize = 16
        $sync.popupDuration = 10 #How long in seconds should the extend popup stay on screen
    }Else{$path = $sync.path} 

    #If runspace isnt already running, create and run custom code within it
    $activeRunspaces = Get-Runspace
    If((Get-Runspace).name -notcontains $runspaceName){

        #create dynamically named runspace 
        New-Variable -Name $runspaceName -PassThru -Force -Value ([runspacefactory]::CreateRunspace())
        (Get-Variable -Name $runspaceName -ValueOnly).ApartmentState = "STA" 
        (Get-Variable -Name $runspaceName -ValueOnly).ThreadOptions = "ReuseThread" 
        (Get-Variable -Name $runspaceName -ValueOnly).Name = "$runspaceName"
        (Get-Variable -Name $runspaceName -ValueOnly).open()
        (Get-Variable -Name $runspaceName -ValueOnly).SessionStateProxy.SetVariable("sync",$sync) 

        #script template that allows us to pass through the custom code and any other required local variables
        $scriptTemplate = {
    
            #local Variables to pass into Runspace
            $ParamList = @{
                logName = $logName
                debug = $debug
                logging = $logging
                code = $code
            }

            [PowerShell]::Create().AddScript({
                Param ($logName, $debug, $logging, $code) #pass variables into runspace
                [pscustomobject]@{
                    logName = $logName
                    debug = $debug
                    logging = $logging
                    code = $code
                }
            
                #unique code to run inside new runspace 
                .$code

            }).AddParameters($ParamList)
        }

        #create dynamically named script variable
        New-Variable -Name $runspaceCmd -PassThru -Force -Value ( .$scriptTemplate )

        #Invoke script to run in the new Runspace
        (Get-Variable -Name $runspaceCmd -ValueOnly).Runspace = (Get-Variable -Name $runspaceName -ValueOnly)
        $runspaceInvoke = (Get-Variable -Name $runspaceCmd -ValueOnly).BeginInvoke(),"Background"
        Start-Sleep -Milliseconds 200
    }
}

$shortName = "incident" #runspace shortname
$debug = $true #debugging?

#code to run inside the new runspace
$code = {
    Add-Type -AssemblyName PresentationFramework

    $guiPosition = @" 
        WindowStartupLocation="CenterScreen" 
"@

    $guiTitleBar = @"
        <Label Name="incidentTitle" Content="Report Incident" FontWeight="Normal" Background="red" Foreground="White" Width="Auto" HorizontalContentAlignment="Center"/>
"@

    $guiBody = @"
        <Grid.RowDefinitions>
            <RowDefinition Height="1*" />
            <RowDefinition Height="1*" />
            <RowDefinition Height="10" />
            <RowDefinition Height="1*" />
            <RowDefinition Height="1*" />
        </Grid.RowDefinitions>
        <Label Name="Report" Grid.Row="0" Content="Select the Incident Severity" FontWeight="Normal"  Foreground="Black" Width="Auto" Margin="5,5,5,0"/>
        <ComboBox Name="incidentSeverity"  Grid.Row="1" Width="Auto" Margin="5,5,5,5"/>
        <Label Name="Notes" Grid.Row="3" Content="Incident Notes" FontWeight="Normal" Foreground="Black" Width="Auto" Margin="5,5,5,0"/>
        <TextBox Name="incidentNotes" Grid.Row="4" TextWrapping="Wrap" Width="Auto" Margin="5,5,5,5"/>
"@

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

        <Button Name="btnIncident" Content="Report Incident w/o Screenshot" Grid.Row="0" Background="#f5f5f5" FontWeight="normal" BorderBrush="{x:Null}" BorderThickness = "0" Margin="5,15,5,5" Width="Auto"/>
        <Button Name="btnScreenshot" Content="Report Incident with Screenshot" Grid.Row="1" FontWeight="Normal" Background="#f5f5f5" BorderBrush="{x:Null}" BorderThickness = "0" Margin="5,15,5,5" Width="Auto"/>    
"@

    #load gui style
    ."$($sync.Path)\guiStyle.ps1"

    #Create GUI
    $incidentXAML=(New-Object System.Xml.XmlNodeReader $guiStyle)
    $sync.incidentWindow =[Windows.Markup.XamlReader]::Load($incidentXAML)
    
    $sync.incidentClose = $false

    [System.Media.SystemSounds]::Exclamation.Play()
    
    #show dialog window, wrapped in an async variable to handle errors
    $incidentAsync = $sync.incidentWindow.Dispatcher.InvokeAsync({
        $sync.incidentWindow.ShowDialog() | Out-Null
    })

    $incidentAsync.Wait() | Out-Null
    #show dialog window, wrapped in an async variable to handle errors
    
}

#create the runspace with custom code
createRunspace -shortName "shortName" -code $code -debug $true


        

So if I replace line 59 with the contents of $code at line 78, it all works swimmingly, but that reduces the effectiveness of the function

I can save the contents of $code at line 78 into a script .ps1 file and import it at line 59 and that works fine too

It’s only if I create a subscript of that code and then try and import it to the function that it doesn’t work

 

thanks

James

here’s the guiStyle.ps1 script contents if you need to run my code above

[xml]$guiStyle = $null

[xml]$guiStyle = @"  
    <Window 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Name="Window" Title="" SizeToContent="WidthAndHeight" $guiPosition WindowStyle="None" ResizeMode="NoResize" AllowsTransparency="True" Background="Transparent" Opacity="1" Topmost="True" ShowInTaskbar="False">
        <Border x:Name="MainBorder" Margin="10" CornerRadius="8" BorderThickness="0" BorderBrush="Black" Padding="0" >
            <Border.Effect>
                <DropShadowEffect x:Name="DSE" Color="Black" Direction="270" BlurRadius="20" ShadowDepth="3" Opacity="0.6" />
            </Border.Effect>
            <Border.Triggers>
                <EventTrigger RoutedEvent="Window.Loaded">
                    <BeginStoryboard>
                        <Storyboard>
                            <DoubleAnimation Storyboard.TargetName="DSE" Storyboard.TargetProperty="ShadowDepth" From="0" To="3" Duration="0:0:1" AutoReverse="False" />
                            <DoubleAnimation Storyboard.TargetName="DSE" Storyboard.TargetProperty="BlurRadius" From="0" To="20" Duration="0:0:1" AutoReverse="False" />
                        </Storyboard>
                    </BeginStoryboard>
                </EventTrigger>
            </Border.Triggers>
            <Grid>
                <Border Name="Mask" CornerRadius="8" Background="White" />
                <Grid x:Name="Grid" Background="White">
                <Grid.OpacityMask>
                    <VisualBrush Visual="{Binding ElementName=Mask}"/>
                </Grid.OpacityMask>
                    <StackPanel Name="StackPanel">
                        <Grid Margin="0,0,0,0" HorizontalAlignment="Center" Width="Auto">
                            <StackPanel HorizontalAlignment="Left" Height="Auto" VerticalAlignment="Top" Width="Auto ">
                                
                                <Grid Height="Auto" VerticalAlignment="Top" Width="Auto">
                                    $guiTitleBar
                                </Grid>

                                <Grid Height="Auto" VerticalAlignment="Top" Width="Auto" Background="White">
                                    $guiBody
                                </Grid>

                                <Grid Height="Auto" VerticalAlignment="Top" Width="Auto" Background="White">
                                    $guiButtons
                                </Grid>
                            </StackPanel>
                        </Grid>
                    </StackPanel>
                </Grid>
            </Grid>
        </Border>
    </Window>
"@