diff --git a/.gitignore b/.gitignore
index 40199a432..d692dd410 100644
--- a/.gitignore
+++ b/.gitignore
@@ -357,4 +357,4 @@ MigrationBackup/
# Community Toolkit Labs generated files
Toolkit.Labs.All.sln
-Labs.SampleRefs.props
+common/MultiTarget/Generated/**
diff --git a/.vscode/launch.json b/.vscode/launch.json
index a604a5cc7..8cabf0500 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -27,7 +27,7 @@
"type": "PowerShell",
"request": "launch",
"name": "Discover samples",
- "script": "${workspaceFolder}/DiscoverSamples.ps1",
+ "script": "${workspaceFolder}/common/MultiTarget/GenerateAllProjectReferences.ps1; ${workspaceFolder}/common/GenerateVSCodeLaunchConfig.ps1; ",
"presentation": {
"group": "2",
"order": 2
diff --git a/DiscoverSamples.ps1 b/DiscoverSamples.ps1
deleted file mode 100644
index cc12deb7f..000000000
--- a/DiscoverSamples.ps1
+++ /dev/null
@@ -1,104 +0,0 @@
-Param (
- [Parameter(HelpMessage = "Disables suppressing changes to the ./.vscode/launch.json file in git, allowing changes to be committed.")]
- [switch]$allowGitChanges = $false
-)
-
-$templatedSampleProjectReferencesDefinitionMarker = "[TemplatedSampleProjectReferences]"
-$sampleRefsPropsTemplatePath = "$PSScriptRoot/common/Labs.SampleRefs.props.template";
-$generatedSampleRefsPropsPath = "$PSScriptRoot/common/Labs.SampleRefs.props";
-
-function CreateVsCodeLaunchConfigJson {
- param (
- [string]$projectName
- )
-
- return "{
- `"name`": `"$projectName`",
- `"type`": `"coreclr`",
- `"request`": `"launch`",
- `"program`": `"dotnet`",
- `"args`": [
- `"run`",
- `"build`",
- `"/r`",
- `"/p:UnoSourceGeneratorUseGenerationHost=true`",
- `"/p:UnoSourceGeneratorUseGenerationController=false`",
- `"/p:UnoRemoteControlPort=443`",
- `"--project=`$`{workspaceFolder`}/labs/$projectName/samples/$projectName.Wasm/$projectName.Wasm.csproj`"
- ],
- `"presentation`": {
- `"group`": `"2`"
- },
- `"cwd`": `"`$`{workspaceFolder`}/labs/$projectName/samples/$projectName.Wasm`"
- }";
-}
-
-# Execute ProjectReference generation for all heads
-$sampleRefsPropsTemplate = Get-Content -Path $sampleRefsPropsTemplatePath;
-Write-Output "Loaded sample ProjectReference template from $sampleRefsPropsTemplatePath";
-
-# Add sample projects
-foreach ($sampleProjectPath in Get-ChildItem -Recurse -Path "$PSScriptRoot/labs/*/samples/*.Samples/*.Samples.csproj") {
- $relativePath = Resolve-Path -Relative -Path $sampleProjectPath;
- $relativePath = $relativePath.TrimStart('.\');
- $projectName = [System.IO.Path]::GetFileNameWithoutExtension($relativePath);
-
- Write-Host "Adding $projectName to project references";
-
- $projectReferenceDefinition = "";
-
- $sampleRefsPropsTemplate = $sampleRefsPropsTemplate -replace [regex]::escape($templatedSampleProjectReferencesDefinitionMarker), ($templatedSampleProjectReferencesDefinitionMarker + "
- " + $projectReferenceDefinition);
-}
-
-# Add library projects
-foreach ($sampleProjectPath in Get-ChildItem -Recurse -Path "$PSScriptRoot/labs/*/src/*.csproj") {
- $relativePath = Resolve-Path -Relative -Path $sampleProjectPath;
- $relativePath = $relativePath.TrimStart('.\');
- $projectName = [System.IO.Path]::GetFileNameWithoutExtension($relativePath);
-
- Write-Host "Adding $projectName to project references";
-
- $projectReferenceDefinition = "";
-
- $sampleRefsPropsTemplate = $sampleRefsPropsTemplate -replace [regex]::escape($templatedSampleProjectReferencesDefinitionMarker), ($templatedSampleProjectReferencesDefinitionMarker + "
- " + $projectReferenceDefinition);
-}
-
-$sampleRefsPropsTemplate = $sampleRefsPropsTemplate -replace [regex]::escape($templatedSampleProjectReferencesDefinitionMarker), "";
-
-# Save
-Set-Content -Path $generatedSampleRefsPropsPath -Value $sampleRefsPropsTemplate;
-Write-Output "Sample project references generated at $generatedSampleRefsPropsPath";
-
-$launchConfigJson = Get-Content -Path "$PSScriptRoot/.vscode/launch.json";
-$launchConfig = $launchConfigJson | ConvertFrom-Json;
-
-# Remove all non-generated configurations
-$originalConfigurations = $launchConfig.configurations;
-$launchConfig.configurations = @();
-$launchConfig.configurations += $originalConfigurations[0];
-$launchConfig.configurations += $originalConfigurations[1];
-
-foreach ($wasmProjectPath in Get-ChildItem -Recurse -Path "$PSScriptRoot/labs/*/samples/*.Wasm/*.Wasm.csproj") {
- $projectName = [System.IO.Path]::GetFileNameWithoutExtension($wasmProjectPath) -Replace ".Wasm", "";
- Write-Host "Generating VSCode launch config for $projectName";
-
- $configJson = CreateVsCodeLaunchConfigJson $projectName;
- $config = $configJson | ConvertFrom-Json;
-
- $launchConfig.configurations += $config;
-}
-
-if ($allowGitChanges.IsPresent) {
- Write-Warning "Changes to the default launch.json in Labs can now be committed. Run this command again without the -allowGitChanges flag to disable committing further changes.";
- git update-index --no-assume-unchanged ./.vscode/launch.json
-}
-else {
- Write-Output "Changes to the default launch.json in Labs are now suppressed. To switch branches, run git reset --hard with a clean working tree. Include the -allowGitChanges flag to enable committing changes.";
- git update-index --assume-unchanged $PSScriptRoot/.vscode/launch.json
-}
-
-# Save
-Set-Content -Path "$PSScriptRoot/.vscode/launch.json" -Value ($launchConfig | ConvertTo-Json -Depth 9);
-Write-Output "Saved VSCode launch configs to $PSScriptRoot/.vscode/launch.json";
\ No newline at end of file
diff --git a/GenerateAllSolution.ps1 b/GenerateAllSolution.ps1
index 323ee4858..2f1ac702a 100644
--- a/GenerateAllSolution.ps1
+++ b/GenerateAllSolution.ps1
@@ -4,6 +4,10 @@ Param (
[string]$UseUnoWinUI = 2
)
+# Generate required props for "All" solution.
+& ./common/MultiTarget/GenerateAllProjectReferences.ps1
+& ./common/GenerateVSCodeLaunchConfig.ps1
+
# Set WinUI version for Uno projects
$originalWorkingDirectory = Get-Location;
@@ -243,6 +247,3 @@ $solutionTemplate = $solutionTemplate -replace "(?m)^\s*`r`n", "";
# Save
Set-Content -Path $generatedSolutionFilePath -Value $solutionTemplate;
Write-Output "Solution generated at $generatedSolutionFilePath";
-
-# Run sample discovery
-& ./DiscoverSamples.ps1
diff --git a/common/GenerateVSCodeLaunchConfig.ps1 b/common/GenerateVSCodeLaunchConfig.ps1
new file mode 100644
index 000000000..28b30700b
--- /dev/null
+++ b/common/GenerateVSCodeLaunchConfig.ps1
@@ -0,0 +1,62 @@
+Param (
+ [Parameter(HelpMessage = "Disables suppressing changes to the ./.vscode/launch.json file in git, allowing changes to be committed.")]
+ [switch]$allowGitChanges = $false
+)
+
+function CreateVsCodeLaunchConfigJson {
+ param (
+ [string]$projectName
+ )
+
+ return "{
+ `"name`": `"$projectName`",
+ `"type`": `"coreclr`",
+ `"request`": `"launch`",
+ `"program`": `"dotnet`",
+ `"args`": [
+ `"run`",
+ `"build`",
+ `"/r`",
+ `"/p:UnoSourceGeneratorUseGenerationHost=true`",
+ `"/p:UnoSourceGeneratorUseGenerationController=false`",
+ `"/p:UnoRemoteControlPort=443`",
+ `"--project=`$`{workspaceFolder`}/labs/$projectName/samples/$projectName.Wasm/$projectName.Wasm.csproj`"
+ ],
+ `"presentation`": {
+ `"group`": `"2`"
+ },
+ `"cwd`": `"`$`{workspaceFolder`}/labs/$projectName/samples/$projectName.Wasm`"
+ }";
+}
+
+$launchConfigJson = Get-Content -Path "$PSScriptRoot/../.vscode/launch.json" -ErrorAction Stop;
+$launchConfig = $launchConfigJson | ConvertFrom-Json;
+
+# Remove all non-generated configurations
+$originalConfigurations = $launchConfig.configurations;
+$launchConfig.configurations = @();
+$launchConfig.configurations += $originalConfigurations[0];
+$launchConfig.configurations += $originalConfigurations[1];
+
+foreach ($wasmProjectPath in Get-ChildItem -Recurse -Path "$PSScriptRoot/../*/*/samples/*.Wasm/*.Wasm.csproj") {
+ $projectName = [System.IO.Path]::GetFileNameWithoutExtension($wasmProjectPath) -Replace ".Wasm", "";
+ Write-Host "Generating VSCode launch config for $projectName";
+
+ $configJson = CreateVsCodeLaunchConfigJson $projectName;
+ $config = $configJson | ConvertFrom-Json;
+
+ $launchConfig.configurations += $config;
+}
+
+if ($allowGitChanges.IsPresent) {
+ Write-Warning "Changes to the default launch.json can now be committed. Run this command again without the -allowGitChanges flag to disable committing further changes.";
+ git update-index --no-assume-unchanged $PSScriptRoot/../.vscode/launch.json
+}
+else {
+ Write-Output "Changes to the default launch.json are now suppressed. To switch branches, run git reset --hard with a clean working tree. Include the -allowGitChanges flag to enable committing changes.";
+ git update-index --assume-unchanged $PSScriptRoot/../.vscode/launch.json
+}
+
+# Save
+Set-Content -Path "$PSScriptRoot/../.vscode/launch.json" -Value ($launchConfig | ConvertTo-Json -Depth 9);
+Write-Output "Saved VSCode launch configs to $(Resolve-Path $PSScriptRoot/../.vscode/launch.json)";
\ No newline at end of file
diff --git a/common/Labs.Head.props b/common/Labs.Head.props
index 1b926edf9..3bf9273c5 100644
--- a/common/Labs.Head.props
+++ b/common/Labs.Head.props
@@ -29,6 +29,8 @@
true
true
true
+
+ $(DefineConstants);LABS_ALL_SAMPLES
diff --git a/common/Labs.SampleRefs.props.template b/common/Labs.SampleRefs.props.template
deleted file mode 100644
index 43aeba790..000000000
--- a/common/Labs.SampleRefs.props.template
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
- $(DefineConstants);LABS_ALL_SAMPLES
-
-
- [TemplatedSampleProjectReferences]
-
-
\ No newline at end of file
diff --git a/common/MultiTarget/Defaults.props b/common/MultiTarget/Defaults.props
new file mode 100644
index 000000000..86e5e82f7
--- /dev/null
+++ b/common/MultiTarget/Defaults.props
@@ -0,0 +1,5 @@
+
+
+ uwp;wasdk;wpf;wasm;linuxgtk;macos;ios;android;
+
+
\ No newline at end of file
diff --git a/common/MultiTarget/GenerateAllProjectReferences.ps1 b/common/MultiTarget/GenerateAllProjectReferences.ps1
new file mode 100644
index 000000000..5bb8fad65
--- /dev/null
+++ b/common/MultiTarget/GenerateAllProjectReferences.ps1
@@ -0,0 +1,46 @@
+Param (
+ [Parameter(HelpMessage = "The directory where props files for discovered projects should be saved.")]
+ [string]$projectPropsOutputDir = "$PSScriptRoot/Generated"
+)
+
+$preWorkingDir = $pwd;
+Set-Location $PSScriptRoot;
+
+# Delete and recreate output folder.
+Remove-Item -Path $projectPropsOutputDir -Recurse -Force -ErrorAction SilentlyContinue | Out-Null;
+New-Item -ItemType Directory -Force -Path $projectPropsOutputDir -ErrorAction SilentlyContinue | Out-Null;
+
+# Discover projects in provided paths
+foreach ($projectPath in Get-ChildItem -Directory -Depth 0 -Path "$PSScriptRoot/../../labs/") {
+ # Normalize project path
+ $projectName = $projectPath.Name;
+
+ # Folder layout is expected to match the Community Toolkit.
+ # Uses the values from the source library project as the fallback for the sample project.
+ # This behavior also implemented in MultiTarget.props for TargetFramework evaluation.
+ $srcPath = Resolve-Path "$($projectPath.FullName)\src";
+ $srcProjectPath = Get-ChildItem -File "$srcPath\*.csproj";
+
+ $samplePath = Resolve-Path "$($projectPath.FullName)\samples\$projectName.Samples";
+ $sampleProjectPath = Get-ChildItem -File "$samplePath\*.csproj";
+
+ if ($srcProjectPath.Length -eq 0) {
+ Write-Error "Could not locate source csproj for $projectName";
+ exit(-1);
+ }
+
+ if ($sampleProjectPath.Length -eq 0) {
+ Write-Error "Could not locate sample csproj for $projectName";
+ exit(-1);
+ }
+
+ # Generate s for sample project
+ # Use source project MultiTarget as first fallback.
+ & $PSScriptRoot\GenerateMultiTargetAwareProjectReferenceProps.ps1 -projectPath $sampleProjectPath -outputPath "$projectPropsOutputDir/$($sampleProjectPath.BaseName).props" -multiTargetFallbackPropsPath @("$srcPath/MultiTarget.props", "$samplePath/MultiTarget.props", "$PSScriptRoot/Defaults.props");
+
+ # Generate s for src project
+ & $PSScriptRoot\GenerateMultiTargetAwareProjectReferenceProps.ps1 -projectPath $srcProjectPath -outputPath "$projectPropsOutputDir/$($srcProjectPath.BaseName).props" -multiTargetFallbackPropsPath @("$srcPath/MultiTarget.props", "$PSScriptRoot/Defaults.props");
+}
+
+
+Set-Location $preWorkingDir;
\ No newline at end of file
diff --git a/common/MultiTarget/GenerateMultiTargetAwareProjectReferenceProps.ps1 b/common/MultiTarget/GenerateMultiTargetAwareProjectReferenceProps.ps1
new file mode 100644
index 000000000..a50ccdacb
--- /dev/null
+++ b/common/MultiTarget/GenerateMultiTargetAwareProjectReferenceProps.ps1
@@ -0,0 +1,84 @@
+Param (
+ [Parameter(HelpMessage = "The full path of the csproj to generated references to.", Mandatory = $true)]
+ [string]$projectPath,
+
+ [Parameter(HelpMessage = "A path to a .props file where generated content should be saved to.", Mandatory = $true)]
+ [string]$outputPath,
+
+ [Parameter(HelpMessage = "The path to the template used to generate the props file.")]
+ [string]$templatePath = "$PSScriptRoot/MultiTargetAwareProjectReference.props.template",
+
+ [Parameter(HelpMessage = "The path to the props file that contains the default MultiTarget values.")]
+ [string[]]$multiTargetFallbackPropsPath = @("$PSScriptRoot/Defaults.props"),
+
+ [Parameter(HelpMessage = "The placeholder text to replace when inserting the project file name into the template.")]
+ [string]$projectFileNamePlaceholder = "[ProjectFileName]",
+
+ [Parameter(HelpMessage = "The placeholder text to replace when inserting the project path into the template.")]
+ [string]$projectRootPlaceholder = "[ProjectRoot]"
+)
+
+$preWorkingDir = $pwd;
+Set-Location $PSScriptRoot;
+
+$relativeProjectPath = Invoke-Expression -C "(Resolve-Path -Relative -Path $projectPath)";
+$templateContents = Get-Content -Path $templatePath;
+
+Set-Location $preWorkingDir;
+
+# Insert csproj file name.
+$csprojFileName = [System.IO.Path]::GetFileName($relativeProjectPath);
+$templateContents = $templateContents -replace [regex]::escape($projectFileNamePlaceholder), $csprojFileName;
+
+# Insert project directory
+$relativeProjectDirectory = [System.IO.Path]::GetDirectoryName($relativeProjectPath);
+$templateContents = $templateContents -replace [regex]::escape($projectRootPlaceholder), "$relativeProjectDirectory";
+
+function LoadMultiTargetsFrom([string] $path) {
+ $fileContents = "";
+
+ # If file does not exist
+ if ($false -eq (Test-Path -Path $path -PathType Leaf)) {
+ # Load first available default
+ foreach ($fallbackPath in $multiTargetFallbackPropsPath) {
+ if (Test-Path $fallbackPath) {
+ $fileContents = Get-Content $fallbackPath -ErrorAction Stop;
+ break;
+ }
+ }
+ }
+ else {
+ # Load requested file
+ $fileContents = Get-Content $path -ErrorAction Stop;
+ }
+
+ # Parse file contents
+ $regex = Select-String -Pattern '(.+?)<\/MultiTarget>' -InputObject $fileContents;
+
+ if ($null -eq $regex -or $null -eq $regex.Matches -or $null -eq $regex.Matches.Groups -or $regex.Matches.Groups.Length -lt 2) {
+ Write-Error "Couldn't get MultiTarget property from $path";
+ exit(-1);
+ }
+
+ return $regex.Matches.Groups[1].Value;
+}
+
+# Load multitarget preferences for project
+$multiTargets = LoadMultiTargetsFrom("$([System.IO.Path]::GetDirectoryName($projectPath))\MultiTarget.props");
+
+$templateContents = $templateContents -replace [regex]::escape("[IntendedTargets]"), $multiTargets;
+
+$multiTargets = $multiTargets.Split(';');
+Write-Host "Generating project references for $([System.IO.Path]::GetFileNameWithoutExtension($csprojFileName)): $($multiTargets -Join ', ')"
+
+$templateContents = $templateContents -replace [regex]::escape("[CanTargetWasm]"), "'$($multiTargets.Contains("wasm").ToString().ToLower())'";
+$templateContents = $templateContents -replace [regex]::escape("[CanTargetUwp]"), "'$($multiTargets.Contains("uwp").ToString().ToLower())'";
+$templateContents = $templateContents -replace [regex]::escape("[CanTargetWasdk]"), "'$($multiTargets.Contains("wasdk").ToString().ToLower())'";
+$templateContents = $templateContents -replace [regex]::escape("[CanTargetWpf]"), "'$($multiTargets.Contains("wpf").ToString().ToLower())'";
+$templateContents = $templateContents -replace [regex]::escape("[CanTargetLinuxGtk]"), "'$($multiTargets.Contains("linuxgtk").ToString().ToLower())'";
+$templateContents = $templateContents -replace [regex]::escape("[CanTargetMacOS]"), "'$($multiTargets.Contains("macos").ToString().ToLower())'";
+$templateContents = $templateContents -replace [regex]::escape("[CanTargetiOS]"), "'$($multiTargets.Contains("ios").ToString().ToLower())'";
+$templateContents = $templateContents -replace [regex]::escape("[CanTargetDroid]"), "'$($multiTargets.Contains("android").ToString().ToLower())'";
+
+# Save to disk
+Set-Content -Path $outputPath -Value $templateContents;
diff --git a/common/Labs.MultiTarget.props b/common/MultiTarget/MultiTarget.props
similarity index 58%
rename from common/Labs.MultiTarget.props
rename to common/MultiTarget/MultiTarget.props
index 841cd5b20..37ff1b8b4 100644
--- a/common/Labs.MultiTarget.props
+++ b/common/MultiTarget/MultiTarget.props
@@ -1,19 +1,30 @@
-
+
+
+
+
+
-
- $(NetStandardCommonTargetFramework);
- $(UwpTargetFramework);
- $(WinAppSdkTargetFramework);
- $(MacOSLibTargetFramework);
- $(iOSLibTargetFramework);
- $(AndroidLibTargetFramework);
-
+ $(TargetFrameworks);$(UwpTargetFramework)
+ $(TargetFrameworks);$(WinAppSdkTargetFramework)
+
+ $(TargetFrameworks);$(NetStandardCommonTargetFramework)
+ $(TargetFrameworks);$(MacOSLibTargetFramework)
+ $(TargetFrameworks);$(iOSLibTargetFramework)
+ $(TargetFrameworks);$(AndroidLibTargetFramework)
true
true
@@ -25,10 +36,12 @@
10.0.17763.0
10.0.19041.0
+
WMC1006;CS8034;
+
@@ -46,6 +59,7 @@
+
@@ -64,4 +78,4 @@
c:\Program Files\Microsoft Visual Studio\2022\Preview\Common7\IDE\Extensions\Xamarin.VisualStudio\Xamarin.Mac.dll
-
+
\ No newline at end of file
diff --git a/common/MultiTarget/MultiTargetAwareProjectReference.props.template b/common/MultiTarget/MultiTargetAwareProjectReference.props.template
new file mode 100644
index 000000000..7fea92b4b
--- /dev/null
+++ b/common/MultiTarget/MultiTargetAwareProjectReference.props.template
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/common/MultiTarget/ReadMe.md b/common/MultiTarget/ReadMe.md
new file mode 100644
index 000000000..c4f7eaf64
--- /dev/null
+++ b/common/MultiTarget/ReadMe.md
@@ -0,0 +1,37 @@
+# MultiTarget
+
+`` is a custom property that indicates which target a component is designed to be built for / run on.
+
+The supplied targets are used to create project references, generate solution files, enable/disable TargetFrameworks, and build nuget packages.
+
+## Basic usage
+
+Create a `MultiTarget.props` file in the root of your source project to change the platform targets for your component. This will be picked up automatically by your sample project, unless it has a `MultiTarget.props` of its own defined.
+
+By default, all available targets are enabled:
+```xml
+
+
+ uwp;wasdk;wpf;wasm;linuxgtk;macos;ios;android;
+
+
+```
+
+For example, to only target UWP, WASM and Android:
+
+```xml
+
+
+ uwp;wasm;android
+
+
+```
+
+
+## ProjectReference Generation
+
+The script `GenerateAllProjectReferences.ps1` will scan for toolkit components and generate `.props` files for each.
+
+## NuGet Packages
+
+The `` property is used to define the `TargetFrameworks` supported by that project. Projects packed into a NuGet packages will reflect this.
diff --git a/common/Labs.Sample.props b/common/SampleProjectConfig.props
similarity index 100%
rename from common/Labs.Sample.props
rename to common/SampleProjectConfig.props
diff --git a/common/Scripts/UseUnoWinUI.ps1 b/common/Scripts/UseUnoWinUI.ps1
index 3ab9cf4c4..49eb71726 100644
--- a/common/Scripts/UseUnoWinUI.ps1
+++ b/common/Scripts/UseUnoWinUI.ps1
@@ -47,9 +47,9 @@ function ApplyWinUISwap([string] $filePath) {
Write-Output "Switching to WinUI $winUIMajorVersion";
-ApplyWinUISwap $PSScriptRoot\..\Labs.Head.Uno.props
-ApplyWinUISwap $PSScriptRoot\..\Labs.Uno.props
-ApplyWinUISwap $PSScriptRoot\..\Labs.ProjectIdentifiers.props
+ApplyWinUISwap $PSScriptRoot/../Labs.Head.Uno.props
+ApplyWinUISwap $PSScriptRoot/../Labs.Uno.props
+ApplyWinUISwap $PSScriptRoot/../Labs.ProjectIdentifiers.props
if ($allowGitChanges.IsPresent) {
Write-Warning "Changes to the default Uno package settings in Labs can now be committed.`r`nRun this command again without -allowGitChanges to disable committing further changes.";
@@ -58,4 +58,4 @@ else {
Write-Output "Changes to the default Uno package settings in Labs are now suppressed.`r`nTo switch branches, run `"git reset --hard`" with a clean working tree.";
}
-Write-Output "Done"
\ No newline at end of file
+Write-Output "Done, switched to WinUI $winUIMajorVersion"
\ No newline at end of file
diff --git a/labs/CanvasLayout/samples/CanvasLayout.Samples/CanvasLayout.Samples.csproj b/labs/CanvasLayout/samples/CanvasLayout.Samples/CanvasLayout.Samples.csproj
index d9dadd648..c5985646e 100644
--- a/labs/CanvasLayout/samples/CanvasLayout.Samples/CanvasLayout.Samples.csproj
+++ b/labs/CanvasLayout/samples/CanvasLayout.Samples/CanvasLayout.Samples.csproj
@@ -5,10 +5,10 @@
-
+
-
+
CanvasLayoutExperiment.Samples
diff --git a/labs/CanvasLayout/src/CommunityToolkit.Labs.WinUI.CanvasLayout.csproj b/labs/CanvasLayout/src/CommunityToolkit.Labs.WinUI.CanvasLayout.csproj
index f0b2f5dfa..535f3ef02 100644
--- a/labs/CanvasLayout/src/CommunityToolkit.Labs.WinUI.CanvasLayout.csproj
+++ b/labs/CanvasLayout/src/CommunityToolkit.Labs.WinUI.CanvasLayout.csproj
@@ -7,7 +7,7 @@
-
+
CommunityToolkit.Labs.WinUI.CanvasLayoutRns
diff --git a/labs/CanvasView/samples/CanvasView.Samples/CanvasView.Samples.csproj b/labs/CanvasView/samples/CanvasView.Samples/CanvasView.Samples.csproj
index 4838a1389..883248489 100644
--- a/labs/CanvasView/samples/CanvasView.Samples/CanvasView.Samples.csproj
+++ b/labs/CanvasView/samples/CanvasView.Samples/CanvasView.Samples.csproj
@@ -5,10 +5,10 @@
-
+
-
+
CanvasViewExperiment.Samples
diff --git a/labs/CanvasView/src/CommunityToolkit.Labs.WinUI.CanvasView.csproj b/labs/CanvasView/src/CommunityToolkit.Labs.WinUI.CanvasView.csproj
index f22040495..8187de720 100644
--- a/labs/CanvasView/src/CommunityToolkit.Labs.WinUI.CanvasView.csproj
+++ b/labs/CanvasView/src/CommunityToolkit.Labs.WinUI.CanvasView.csproj
@@ -7,7 +7,7 @@
-
+
CommunityToolkit.Labs.WinUI.CanvasViewRns
diff --git a/labs/RivePlayer/samples/RivePlayer.Samples/RivePlayer.Samples.csproj b/labs/RivePlayer/samples/RivePlayer.Samples/RivePlayer.Samples.csproj
index dd77a1ca9..7870a3258 100644
--- a/labs/RivePlayer/samples/RivePlayer.Samples/RivePlayer.Samples.csproj
+++ b/labs/RivePlayer/samples/RivePlayer.Samples/RivePlayer.Samples.csproj
@@ -5,10 +5,10 @@
-
+
-
+
RivePlayerExperiment.Samples
diff --git a/labs/RivePlayer/src/CommunityToolkit.Labs.WinUI.Rive.RivePlayer.csproj b/labs/RivePlayer/src/CommunityToolkit.Labs.WinUI.Rive.RivePlayer.csproj
index 0a7edb443..002eb07f2 100644
--- a/labs/RivePlayer/src/CommunityToolkit.Labs.WinUI.Rive.RivePlayer.csproj
+++ b/labs/RivePlayer/src/CommunityToolkit.Labs.WinUI.Rive.RivePlayer.csproj
@@ -7,7 +7,7 @@
-
+
CommunityToolkit.Labs.WinUI.Rive
diff --git a/labs/RivePlayer/src/MultiTarget.props b/labs/RivePlayer/src/MultiTarget.props
new file mode 100644
index 000000000..f73b29dd4
--- /dev/null
+++ b/labs/RivePlayer/src/MultiTarget.props
@@ -0,0 +1,9 @@
+
+
+
+ uwp;wasdk;wasm;
+
+
\ No newline at end of file
diff --git a/labs/SettingsControls/samples/SettingsControls.Samples/SettingsControls.Samples.csproj b/labs/SettingsControls/samples/SettingsControls.Samples/SettingsControls.Samples.csproj
index a61bfb645..4bf0146f4 100644
--- a/labs/SettingsControls/samples/SettingsControls.Samples/SettingsControls.Samples.csproj
+++ b/labs/SettingsControls/samples/SettingsControls.Samples/SettingsControls.Samples.csproj
@@ -5,10 +5,10 @@
-
+
-
+
SettingsControlsExperiment.Samples
diff --git a/labs/SettingsControls/src/CommunityToolkit.Labs.WinUI.SettingsControls.csproj b/labs/SettingsControls/src/CommunityToolkit.Labs.WinUI.SettingsControls.csproj
index f235a149f..b51459490 100644
--- a/labs/SettingsControls/src/CommunityToolkit.Labs.WinUI.SettingsControls.csproj
+++ b/labs/SettingsControls/src/CommunityToolkit.Labs.WinUI.SettingsControls.csproj
@@ -7,7 +7,7 @@
-
+
CommunityToolkit.Labs.WinUI.SettingsControlsRns
diff --git a/labs/SizerBase/samples/SizerBase.Samples/SizerBase.Samples.csproj b/labs/SizerBase/samples/SizerBase.Samples/SizerBase.Samples.csproj
index 5b460836d..2e181adcf 100644
--- a/labs/SizerBase/samples/SizerBase.Samples/SizerBase.Samples.csproj
+++ b/labs/SizerBase/samples/SizerBase.Samples/SizerBase.Samples.csproj
@@ -5,10 +5,10 @@
-
+
-
+
SizerBaseExperiment.Samples
diff --git a/labs/SizerBase/src/CommunityToolkit.Labs.WinUI.SizerBase.csproj b/labs/SizerBase/src/CommunityToolkit.Labs.WinUI.SizerBase.csproj
index 328226ea4..11cecb96c 100644
--- a/labs/SizerBase/src/CommunityToolkit.Labs.WinUI.SizerBase.csproj
+++ b/labs/SizerBase/src/CommunityToolkit.Labs.WinUI.SizerBase.csproj
@@ -7,7 +7,7 @@
-
+
CommunityToolkit.Labs.WinUI.SizerBaseRns
diff --git a/labs/StackedNotificationsBehavior/samples/StackedNotificationsBehavior.Samples/StackedNotificationsBehavior.Samples.csproj b/labs/StackedNotificationsBehavior/samples/StackedNotificationsBehavior.Samples/StackedNotificationsBehavior.Samples.csproj
index a57abbd18..eda1d7119 100644
--- a/labs/StackedNotificationsBehavior/samples/StackedNotificationsBehavior.Samples/StackedNotificationsBehavior.Samples.csproj
+++ b/labs/StackedNotificationsBehavior/samples/StackedNotificationsBehavior.Samples/StackedNotificationsBehavior.Samples.csproj
@@ -5,10 +5,10 @@
-
+
-
+
StackedNotificationsBehaviorExperiment.Samples
diff --git a/labs/StackedNotificationsBehavior/src/CommunityToolkit.Labs.WinUI.StackedNotificationsBehavior.csproj b/labs/StackedNotificationsBehavior/src/CommunityToolkit.Labs.WinUI.StackedNotificationsBehavior.csproj
index 3734bd8f5..9a50e72c0 100644
--- a/labs/StackedNotificationsBehavior/src/CommunityToolkit.Labs.WinUI.StackedNotificationsBehavior.csproj
+++ b/labs/StackedNotificationsBehavior/src/CommunityToolkit.Labs.WinUI.StackedNotificationsBehavior.csproj
@@ -7,7 +7,7 @@
-
+
CommunityToolkit.Labs.WinUI.StackedNotificationsBehaviorRns
diff --git a/labs/StackedNotificationsBehavior/src/MultiTarget.props b/labs/StackedNotificationsBehavior/src/MultiTarget.props
new file mode 100644
index 000000000..b11c19426
--- /dev/null
+++ b/labs/StackedNotificationsBehavior/src/MultiTarget.props
@@ -0,0 +1,9 @@
+
+
+
+ uwp;wasdk;wpf;wasm;linuxgtk;macos;ios;android;
+
+
\ No newline at end of file
diff --git a/platforms/CommunityToolkit.Labs.Droid/CommunityToolkit.Labs.Droid.csproj b/platforms/CommunityToolkit.Labs.Droid/CommunityToolkit.Labs.Droid.csproj
index a64b58a74..ad4b6c55b 100644
--- a/platforms/CommunityToolkit.Labs.Droid/CommunityToolkit.Labs.Droid.csproj
+++ b/platforms/CommunityToolkit.Labs.Droid/CommunityToolkit.Labs.Droid.csproj
@@ -30,7 +30,7 @@
-
+
Debug
diff --git a/platforms/CommunityToolkit.Labs.Skia.Gtk/CommunityToolkit.Labs.Skia.Gtk.csproj b/platforms/CommunityToolkit.Labs.Skia.Gtk/CommunityToolkit.Labs.Skia.Gtk.csproj
index 1ad6a213d..c600549e1 100644
--- a/platforms/CommunityToolkit.Labs.Skia.Gtk/CommunityToolkit.Labs.Skia.Gtk.csproj
+++ b/platforms/CommunityToolkit.Labs.Skia.Gtk/CommunityToolkit.Labs.Skia.Gtk.csproj
@@ -27,7 +27,7 @@
-
+
WinExe
diff --git a/platforms/CommunityToolkit.Labs.Skia.WPF/CommunityToolkit.Labs.Skia.WPF.csproj b/platforms/CommunityToolkit.Labs.Skia.WPF/CommunityToolkit.Labs.Skia.WPF.csproj
index bf587cf0e..b22502731 100644
--- a/platforms/CommunityToolkit.Labs.Skia.WPF/CommunityToolkit.Labs.Skia.WPF.csproj
+++ b/platforms/CommunityToolkit.Labs.Skia.WPF/CommunityToolkit.Labs.Skia.WPF.csproj
@@ -28,7 +28,7 @@
-
+
diff --git a/platforms/CommunityToolkit.Labs.Uwp/CommunityToolkit.Labs.Uwp.csproj b/platforms/CommunityToolkit.Labs.Uwp/CommunityToolkit.Labs.Uwp.csproj
index 07b75845c..1e5e0cce3 100644
--- a/platforms/CommunityToolkit.Labs.Uwp/CommunityToolkit.Labs.Uwp.csproj
+++ b/platforms/CommunityToolkit.Labs.Uwp/CommunityToolkit.Labs.Uwp.csproj
@@ -26,7 +26,7 @@
-
+
CommunityToolkit.Labs.Uwp
CommunityToolkit.Labs.Uwp
diff --git a/platforms/CommunityToolkit.Labs.Wasm/CommunityToolkit.Labs.Wasm.csproj b/platforms/CommunityToolkit.Labs.Wasm/CommunityToolkit.Labs.Wasm.csproj
index b3ab7b929..57e00a533 100644
--- a/platforms/CommunityToolkit.Labs.Wasm/CommunityToolkit.Labs.Wasm.csproj
+++ b/platforms/CommunityToolkit.Labs.Wasm/CommunityToolkit.Labs.Wasm.csproj
@@ -28,7 +28,7 @@
-
+
diff --git a/platforms/CommunityToolkit.Labs.WinAppSdk/CommunityToolkit.Labs.WinAppSdk.csproj b/platforms/CommunityToolkit.Labs.WinAppSdk/CommunityToolkit.Labs.WinAppSdk.csproj
index 5629ae128..f4eb9fe49 100644
--- a/platforms/CommunityToolkit.Labs.WinAppSdk/CommunityToolkit.Labs.WinAppSdk.csproj
+++ b/platforms/CommunityToolkit.Labs.WinAppSdk/CommunityToolkit.Labs.WinAppSdk.csproj
@@ -26,7 +26,7 @@
-
+
CommunityToolkit.Labs.WinAppSdk
diff --git a/platforms/CommunityToolkit.Labs.iOS/CommunityToolkit.Labs.iOS.csproj b/platforms/CommunityToolkit.Labs.iOS/CommunityToolkit.Labs.iOS.csproj
index 1da9167de..8101f32a2 100644
--- a/platforms/CommunityToolkit.Labs.iOS/CommunityToolkit.Labs.iOS.csproj
+++ b/platforms/CommunityToolkit.Labs.iOS/CommunityToolkit.Labs.iOS.csproj
@@ -30,7 +30,7 @@
-
+
Debug
diff --git a/platforms/CommunityToolkit.Labs.macOS/CommunityToolkit.Labs.macOS.csproj b/platforms/CommunityToolkit.Labs.macOS/CommunityToolkit.Labs.macOS.csproj
index 630b320a0..f18bd4145 100644
--- a/platforms/CommunityToolkit.Labs.macOS/CommunityToolkit.Labs.macOS.csproj
+++ b/platforms/CommunityToolkit.Labs.macOS/CommunityToolkit.Labs.macOS.csproj
@@ -30,7 +30,7 @@
-
+
Debug
diff --git a/template/lab/samples/ProjectTemplate.Samples/ProjectTemplate.Samples.csproj b/template/lab/samples/ProjectTemplate.Samples/ProjectTemplate.Samples.csproj
index 7c3187b97..682b5a350 100644
--- a/template/lab/samples/ProjectTemplate.Samples/ProjectTemplate.Samples.csproj
+++ b/template/lab/samples/ProjectTemplate.Samples/ProjectTemplate.Samples.csproj
@@ -5,10 +5,10 @@
-
+
-
+
ProjectTemplateExperiment.Samples
diff --git a/template/lab/src/CommunityToolkit.Labs.WinUI.ProjectTemplate.csproj b/template/lab/src/CommunityToolkit.Labs.WinUI.ProjectTemplate.csproj
index b84b68021..9b0aad71f 100644
--- a/template/lab/src/CommunityToolkit.Labs.WinUI.ProjectTemplate.csproj
+++ b/template/lab/src/CommunityToolkit.Labs.WinUI.ProjectTemplate.csproj
@@ -7,7 +7,7 @@
-
+
CommunityToolkit.Labs.WinUI.ProjectTemplateRns
diff --git a/template/lab/src/MultiTarget.props b/template/lab/src/MultiTarget.props
new file mode 100644
index 000000000..b11c19426
--- /dev/null
+++ b/template/lab/src/MultiTarget.props
@@ -0,0 +1,9 @@
+
+
+
+ uwp;wasdk;wpf;wasm;linuxgtk;macos;ios;android;
+
+
\ No newline at end of file
diff --git a/tests/CommunityToolkit.Labs.Tests.Uwp/CommunityToolkit.Labs.Tests.Uwp.csproj b/tests/CommunityToolkit.Labs.Tests.Uwp/CommunityToolkit.Labs.Tests.Uwp.csproj
index 32d63f6a2..a76a3e9c8 100644
--- a/tests/CommunityToolkit.Labs.Tests.Uwp/CommunityToolkit.Labs.Tests.Uwp.csproj
+++ b/tests/CommunityToolkit.Labs.Tests.Uwp/CommunityToolkit.Labs.Tests.Uwp.csproj
@@ -6,6 +6,21 @@
true
+ false
+ false
+ false
+ false
+ false
+ false
+ false
+ true
+ false
+ false
+ false
+ false
+ false
+ false
+ false
@@ -60,7 +75,7 @@
-
+
diff --git a/tests/CommunityToolkit.Labs.Tests.WinAppSdk/CommunityToolkit.Labs.Tests.WinAppSdk.csproj b/tests/CommunityToolkit.Labs.Tests.WinAppSdk/CommunityToolkit.Labs.Tests.WinAppSdk.csproj
index 4e61f5ca8..90d54d1dc 100644
--- a/tests/CommunityToolkit.Labs.Tests.WinAppSdk/CommunityToolkit.Labs.Tests.WinAppSdk.csproj
+++ b/tests/CommunityToolkit.Labs.Tests.WinAppSdk/CommunityToolkit.Labs.Tests.WinAppSdk.csproj
@@ -3,6 +3,21 @@
true
+ false
+ false
+ false
+ false
+ false
+ false
+ false
+ false
+ true
+ false
+ false
+ false
+ false
+ false
+ false
@@ -41,5 +56,5 @@
-
+