Include Xaml once packaged

Tool: Visual Studio 2019
Version: 5.7.21

Been a while since i used the tool, once you got teh NTFS module resolved, however ive gone to use the tool today having made a slight change to a file, however when i packaged it it wouldnt run unless i copied the XAML file to the same folder the exe was now in.

Ive not had to do that before and wondered if it wa snew or if i was doing something wrong?

TBH not always entirely sure what settings i should be using when packaging. Its a WPF as well

Iā€™m also looking into the same situation. for Iā€™m using Visual Studio 2019
not sure if Iā€™m calling/sourcing it correctly in the code behind

I did see this in the documents Package.psd1 - PowerShell Pro Tools (poshtools.com)

but Iā€™m not sure if this is implemented with the method used in Visual Studio apart from the package script to exe. right mouse click on ps1. I donā€™t see or know how to include additional resources.

maybe @adam or someone can shine some light.

looking at the output I can see that it embed the main XAML. but what I donā€™t see is it doing the same for any other.

------ Build started: Project: WPFDemo, Configuration: Debug Any CPU ------
Checking license
OutputPath is Y:\Users\ME\source\repos\WPFTest\WPFDemo\bin\Debug
Bundling WPFDemo1.xaml.ps1
Parsing file WPFDemo1.xaml.ps1.
Bundling XAML
Embedding XAML file Y:\Users\ME\source\repos\WPFTest\WPFDemo\WPFDemo1.xaml
Packaging C:\Users\ME\AppData\Local\Temp\WPFDemo1.xaml.ps1
Creating temp directory: C:\Users\ME\AppData\Local\Temp\2dab761db89246a39a73e1453d427949
Packaging modulesā€¦

what Iā€™m trying to do is use a ContentControl, to display additional information and or any other type of control that may be ideal for whatever action Iā€™m trying to present to the user.

the additional resource is a UserControl XAML that gets sent to the ContentControl when a user hits a button.

I am aware that manual embedding would work, however, depending on the scope of the project this can be quite a bit of additional XAML to manually include.

I would expect the Resource properties set to True would also embed the additional XAML file.

I think weā€™ll have to enhance this because itā€™s not going to automatically embed additional XAML files. Iā€™ll open an issue for it.

@Adam, could we not use the pre-build part of the EXE build to embed the XAML in some way.

or are you saying currently this is not possible and requires ā€œenhancementsā€ to allow it? at least thatā€™s my understanding of your post.

You could certainly use the pre-build steps to embed the XAML some how. The enhancement would be to make it work all automatically without having to do that.

looking at how I can go about the pre-build, until if and when this functionality is added

I was thinking maybe

Merge-Script - PowerShell Pro Tools (poshtools.com)

use Merge-Script to merge the ps1 that is first built with the project before adding the WPF to the project.

and maybe something like
(ā€™$RegisterView = @"ā€™ + $RegisterView + ā€˜"@ā€™ | Out-String) | Set-Content .\WPFDemo1.ps1

to build out the ps1 before a merge

Iā€™m sure there is a better way.

Since you are bundling the XAML as a resource, you should be able to read and execute it.

This post lays out how to use the resource methods to access the embedded resources: Specify user when building exe - #6 by adam

So then in your Import-XamlView function, you could use the read the manifest stream for the XAML file using the referenced example rather than writing out a separate file.

The problem is I donā€™t think my additional resource is being added. even though I have it checked

I just tried this myself and the resource is included but it looks like the compilation process messes with the XAML resource for some reason. Hereā€™s an example of how to read the embedded XAML resource.

I have a project that includes WpfWindow1.xaml.

image

This produces an executable that includes that resource. You can see the resource is stored under WpfWindow1.xaml.g.resources.

You can also view resources by loading them via PowerShell.

PS C:\Users\adamr> $Assembly = [System.Reflection.Assembly]::LoadFrom('C:\Users\adamr\source\repos\PowerShellModuleProject1\PowerShellModuleProject1\bin\Debug\WpfWindow1.xaml.exe')
PS C:\Users\adamr> $Assembly.GetManifestResourceNames()
WpfWindow1.xaml.g.resources
WpfWindow1.xaml.script.ps1

Next, youā€™ll need to read the resource use a ResourceReader and StreamReader.

$stream = $Assembly.GetManifestResourceStream('WpfWindow1.xaml.g.resources')
$rr = New-Object -TypeName System.Resources.ResourceReader -ArgumentList $stream
$sr = new-object system.io.streamreader -argumentList $rr.value

Using the stream reader, you can grab the XAML.

PS C:\Users\adamr> $sr.ReadToEnd()
<Window

  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

  Title="MainWindow" Height="350" Width="525">

    <Grid>

        <Label Content="Label" HorizontalAlignment="Left" Margin="68,38,0,0" VerticalAlignment="Top" Width="197"/>

        <Button Content="Button" HorizontalAlignment="Left" Margin="307,41,0,0" VerticalAlignment="Top" Width="75"/>

    </Grid>

</Window>

So then rather than:

[Xml]$Xaml = Get-Content -Path $PSScriptRoot\WPFDemo1.xaml

Use

$Assembly = [System.Reflection.Assembly]::GetEntryAssembly()
$stream = $Assembly.GetManifestResourceStream('WpfWindow1.xaml.g.resources')
$rr = New-Object -TypeName System.Resources.ResourceReader -ArgumentList $stream
$sr = new-object system.io.streamreader -argumentList $rr.value
[Xml]$Xaml = $Sr.ReadToEnd()

@adam I think Iā€™m seeing what youā€™re getting at and this worked for me.

I added $ra and targeted by name the XAML so I can pull out the one I want.

The next step for me is to see if it loads properly in the ContentControl

$Assembly = [System.Reflection.Assembly]::LoadFrom('Y:\Users\me\source\repos\HDTS\bin\Debug\mainHTDS.xaml.exe')
$Assembly.GetManifestResourceNames()
$stream = $Assembly.GetManifestResourceStream('mainHTDS.xaml.g.resources')

$rr = New-Object -TypeName System.Resources.ResourceReader -ArgumentList $stream
$ra = $rr | ? {$_.name -match "registerview.xaml"}


$sr = new-object system.io.streamreader -argumentList $ra.Value

$sr.ReadToEnd()

Just a heads up that automatically bundling additional XAML has been added to the next version (2021.9.0) and that will be available September 14th.

You wonā€™t need to even add them as resources as the packager will located them automatically.

1 Like