From 1e9e7b9abc954a64f54b1c9c46bd5d8fde55f363 Mon Sep 17 00:00:00 2001 From: Martin Zikmund Date: Fri, 9 Oct 2026 11:01:04 +0200 Subject: [PATCH 01/15] Migrate to Uno.Sdk Squashed recreation of #305 on top of #315. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01E8bkzyS24p8CYDWLUPsaPC --- .github/workflows/build.yml | 66 +++++++-- Build-Toolkit-Components.ps1 | 8 +- Build-Toolkit-Gallery.ps1 | 88 +++++++++-- .../Renderers/Markdown/MarkdownTextBlock.cs | 4 +- GenerateAllSolution.ps1 | 41 ++++-- GenerateSingleSolution.ps1 | 35 ++++- GenerateVSCodeLaunchConfig.ps1 | 33 ++++- MultiTarget/AvailableTargetFrameworks.props | 3 +- MultiTarget/Defaults.props | 2 +- MultiTarget/DefinedConstants.props | 5 +- MultiTarget/EnabledTargetFrameworks.props | 14 +- MultiTarget/Filter-Supported-Components.ps1 | 4 +- MultiTarget/GenerateAllProjectReferences.ps1 | 4 +- ...eMultiTargetAwareProjectReferenceProps.ps1 | 9 +- MultiTarget/Library.props | 6 +- ...TargetAwareProjectReference.props.template | 3 +- ...getAwareSharedProjectImport.props.template | 2 +- MultiTarget/MultiTargetIdentifiers.props | 16 +- MultiTarget/PackageReferences/Uno.props | 52 +++++-- MultiTarget/ReadMe.md | 28 +++- MultiTarget/Test-Component-Support.ps1 | 17 ++- MultiTarget/UseTargetFrameworks.ps1 | 6 +- MultiTarget/UseUnoWinUI.ps1 | 3 - .../AllComponents/Uno/Assets/Icons/icon.svg | 42 ++++++ .../Uno/Assets/Icons/icon_foreground.svg | 137 ++++++++++++++++++ .../AllComponents/Uno/Assets/SharedAssets.md | 32 ++++ .../Uno/Assets/Splash/splash_screen.svg | 137 ++++++++++++++++++ .../Uno/CommunityToolkit.App.Uno.csproj | 127 ++++++++++++++++ .../Uno/Platforms/Android/AndroidManifest.xml | 5 + .../Platforms/Android/Assets/AboutAssets.txt | 5 + .../Uno/Platforms/Android/Main.Android.cs | 23 +++ .../Platforms/Android/MainActivity.Android.cs | 20 +++ .../Android/Resources/values/Strings.xml | 4 + .../Android/Resources/values/Styles.xml | 8 + .../Uno/Platforms/Android/environment.conf | 2 + .../Uno/Platforms/Desktop/Program.cs | 23 +++ .../Platforms/WebAssembly/LinkerConfig.xml | 3 + .../Uno/Platforms/WebAssembly/Program.cs | 19 +++ .../WebAssembly/WasmScripts/AppManifest.js | 3 + .../WebAssembly/manifest.webmanifest | 10 ++ .../Uno/Platforms/iOS/Entitlements.plist | 6 + .../Uno/Platforms/iOS/Info.plist | 43 ++++++ .../Uno/Platforms/iOS/Main.iOS.cs | 21 +++ .../LaunchImages.launchimage/Contents.json | 20 +++ .../Uno/Platforms/iOS/PrivacyInfo.xcprivacy | 31 ++++ ProjectHeads/AllComponents/Wasm/Program.cs | 14 +- ProjectHeads/App.Head.Android.props | 7 + .../App.Head.Uno.UI.Dependencies.props | 2 - .../App.Head.Uno.WinUI.Dependencies.props | 2 +- ProjectHeads/App.Head.Uno.props | 8 +- ProjectHeads/App.Head.Wasm.props | 3 +- ProjectHeads/GenerateSingleSampleHeads.ps1 | 2 +- .../SingleComponent/Uno/Assets/Icons/icon.svg | 42 ++++++ .../Uno/Assets/Icons/icon_foreground.svg | 137 ++++++++++++++++++ .../Uno/Assets/SharedAssets.md | 32 ++++ .../Uno/Assets/Splash/splash_screen.svg | 137 ++++++++++++++++++ .../Uno/Platforms/Android/AndroidManifest.xml | 5 + .../Platforms/Android/Assets/AboutAssets.txt | 5 + .../Uno/Platforms/Android/Main.Android.cs | 23 +++ .../Platforms/Android/MainActivity.Android.cs | 20 +++ .../Android/Resources/values/Strings.xml | 4 + .../Android/Resources/values/Styles.xml | 8 + .../Uno/Platforms/Android/environment.conf | 2 + .../Uno/Platforms/Desktop/Program.cs | 23 +++ .../Platforms/WebAssembly/LinkerConfig.xml | 3 + .../Uno/Platforms/WebAssembly/Program.cs | 19 +++ .../WebAssembly/WasmScripts/AppManifest.js | 3 + .../WebAssembly/manifest.webmanifest | 10 ++ .../Uno/Platforms/iOS/Entitlements.plist | 6 + .../Uno/Platforms/iOS/Info.plist | 43 ++++++ .../Uno/Platforms/iOS/Main.iOS.cs | 21 +++ .../LaunchImages.launchimage/Contents.json | 20 +++ .../Uno/Platforms/iOS/PrivacyInfo.xcprivacy | 31 ++++ .../Uno/ProjectTemplate.Uno.csproj | 119 +++++++++++++++ ProjectHeads/SingleComponent/Wasm/Program.cs | 16 ++ ...AddMultiTargetCompatibleSampleDocs.targets | 12 ++ ProjectHeads/Tasks/CheckMultiTarget.props | 17 ++- ProjectTemplate/src/MultiTarget.props | 2 +- global.json | 5 +- 79 files changed, 1863 insertions(+), 110 deletions(-) create mode 100644 ProjectHeads/AllComponents/Uno/Assets/Icons/icon.svg create mode 100644 ProjectHeads/AllComponents/Uno/Assets/Icons/icon_foreground.svg create mode 100644 ProjectHeads/AllComponents/Uno/Assets/SharedAssets.md create mode 100644 ProjectHeads/AllComponents/Uno/Assets/Splash/splash_screen.svg create mode 100644 ProjectHeads/AllComponents/Uno/CommunityToolkit.App.Uno.csproj create mode 100644 ProjectHeads/AllComponents/Uno/Platforms/Android/AndroidManifest.xml create mode 100644 ProjectHeads/AllComponents/Uno/Platforms/Android/Assets/AboutAssets.txt create mode 100644 ProjectHeads/AllComponents/Uno/Platforms/Android/Main.Android.cs create mode 100644 ProjectHeads/AllComponents/Uno/Platforms/Android/MainActivity.Android.cs create mode 100644 ProjectHeads/AllComponents/Uno/Platforms/Android/Resources/values/Strings.xml create mode 100644 ProjectHeads/AllComponents/Uno/Platforms/Android/Resources/values/Styles.xml create mode 100644 ProjectHeads/AllComponents/Uno/Platforms/Android/environment.conf create mode 100644 ProjectHeads/AllComponents/Uno/Platforms/Desktop/Program.cs create mode 100644 ProjectHeads/AllComponents/Uno/Platforms/WebAssembly/LinkerConfig.xml create mode 100644 ProjectHeads/AllComponents/Uno/Platforms/WebAssembly/Program.cs create mode 100644 ProjectHeads/AllComponents/Uno/Platforms/WebAssembly/WasmScripts/AppManifest.js create mode 100644 ProjectHeads/AllComponents/Uno/Platforms/WebAssembly/manifest.webmanifest create mode 100644 ProjectHeads/AllComponents/Uno/Platforms/iOS/Entitlements.plist create mode 100644 ProjectHeads/AllComponents/Uno/Platforms/iOS/Info.plist create mode 100644 ProjectHeads/AllComponents/Uno/Platforms/iOS/Main.iOS.cs create mode 100644 ProjectHeads/AllComponents/Uno/Platforms/iOS/Media.xcassets/LaunchImages.launchimage/Contents.json create mode 100644 ProjectHeads/AllComponents/Uno/Platforms/iOS/PrivacyInfo.xcprivacy create mode 100644 ProjectHeads/App.Head.Android.props create mode 100644 ProjectHeads/SingleComponent/Uno/Assets/Icons/icon.svg create mode 100644 ProjectHeads/SingleComponent/Uno/Assets/Icons/icon_foreground.svg create mode 100644 ProjectHeads/SingleComponent/Uno/Assets/SharedAssets.md create mode 100644 ProjectHeads/SingleComponent/Uno/Assets/Splash/splash_screen.svg create mode 100644 ProjectHeads/SingleComponent/Uno/Platforms/Android/AndroidManifest.xml create mode 100644 ProjectHeads/SingleComponent/Uno/Platforms/Android/Assets/AboutAssets.txt create mode 100644 ProjectHeads/SingleComponent/Uno/Platforms/Android/Main.Android.cs create mode 100644 ProjectHeads/SingleComponent/Uno/Platforms/Android/MainActivity.Android.cs create mode 100644 ProjectHeads/SingleComponent/Uno/Platforms/Android/Resources/values/Strings.xml create mode 100644 ProjectHeads/SingleComponent/Uno/Platforms/Android/Resources/values/Styles.xml create mode 100644 ProjectHeads/SingleComponent/Uno/Platforms/Android/environment.conf create mode 100644 ProjectHeads/SingleComponent/Uno/Platforms/Desktop/Program.cs create mode 100644 ProjectHeads/SingleComponent/Uno/Platforms/WebAssembly/LinkerConfig.xml create mode 100644 ProjectHeads/SingleComponent/Uno/Platforms/WebAssembly/Program.cs create mode 100644 ProjectHeads/SingleComponent/Uno/Platforms/WebAssembly/WasmScripts/AppManifest.js create mode 100644 ProjectHeads/SingleComponent/Uno/Platforms/WebAssembly/manifest.webmanifest create mode 100644 ProjectHeads/SingleComponent/Uno/Platforms/iOS/Entitlements.plist create mode 100644 ProjectHeads/SingleComponent/Uno/Platforms/iOS/Info.plist create mode 100644 ProjectHeads/SingleComponent/Uno/Platforms/iOS/Main.iOS.cs create mode 100644 ProjectHeads/SingleComponent/Uno/Platforms/iOS/Media.xcassets/LaunchImages.launchimage/Contents.json create mode 100644 ProjectHeads/SingleComponent/Uno/Platforms/iOS/PrivacyInfo.xcprivacy create mode 100644 ProjectHeads/SingleComponent/Uno/ProjectTemplate.Uno.csproj diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 04d96ef4..0415297b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -101,6 +101,12 @@ jobs: with: global-json-file: tooling/global.json + # Run from ./tooling so global.json scopes the install to the pinned SDK feature + # band; otherwise the workloads land on the runner's newer preinstalled SDK. + - name: Install .NET workloads + working-directory: tooling + run: dotnet workload install wasm-tools + - name: .NET Info (if diagnostics) if: ${{ env.ENABLE_DIAGNOSTICS == 'true' }} run: dotnet --info @@ -140,6 +146,14 @@ jobs: # WinUI 3 not supported on uwp - winui: 3 multitarget: uwp + include: + # The Uno.Sdk head replaces the classic Wasm head on WinUI 3, so it rides on the + # existing wasm/winui3 job as a flag rather than a fake entry in the multitarget axis. + # GenerateSingleSampleHeads.ps1 derives the same thing itself (wasm + WinUI 3); this flag + # only drives which CI steps run below (workloads, build command), not the script's own behavior. + - winui: 3 + multitarget: wasm + unoSdkHead: true env: HEADS_DIRECTORY: tooling/ProjectHeads @@ -169,6 +183,13 @@ jobs: with: global-json-file: tooling/global.json + # Run from ./tooling so global.json scopes the install to the pinned SDK feature + # band; otherwise the workloads land on the runner's newer preinstalled SDK. + - name: Install .NET workloads + if: ${{ matrix.multitarget == 'wasm' }} + working-directory: tooling + run: dotnet workload install wasm-tools ${{ matrix.unoSdkHead && 'android ios maui' || '' }} + - name: .NET Info (if diagnostics) if: ${{ env.ENABLE_DIAGNOSTICS == 'true' }} run: dotnet --info @@ -206,8 +227,17 @@ jobs: - name: Add project heads to ${{ env.TEST_PROJECT_NAME }} working-directory: ./${{ env.TEST_PROJECT_DIRECTORY }} - run: ${{ github.workspace }}/${{ env.HEADS_DIRECTORY }}/GenerateSingleSampleHeads.ps1 -MultiTargets ${{ matrix.multitarget }} -winui ${{ matrix.winui }} -componentPath "${{ github.workspace }}/${{ env.TEST_PROJECT_DIRECTORY }}"${{ env.ENABLE_DIAGNOSTICS == 'true' && ' -UseDiagnostics' || '' }} - + run: >- + ${{ github.workspace }}/${{ env.HEADS_DIRECTORY }}/GenerateSingleSampleHeads.ps1 + -MultiTargets ${{ matrix.multitarget }} + -winui ${{ matrix.winui }} + -componentPath "${{ github.workspace }}/${{ env.TEST_PROJECT_DIRECTORY }}" + ${{ env.ENABLE_DIAGNOSTICS == 'true' && ' -UseDiagnostics' || '' }} + + # The generated solution already contains only the head(s) for the requested MultiTarget(s) + # (GenerateSingleSolution.ps1 swaps in the Uno.Sdk head instead of the classic Wasm one for + # WinUI 3 + wasm), so one MSBuild invocation covers the Uno.Sdk head too - msbuild.exe builds + # it fine, verified locally against dotnet build with identical results. - name: MSBuild working-directory: ./${{ env.TEST_PROJECT_DIRECTORY }} run: msbuild.exe ${{ env.TEST_PROJECT_NAME }}.sln /restore /nowarn:MSB4011 -p:Configuration=Release /m ${{ env.ENABLE_DIAGNOSTICS == 'true' && '/bl' || '' }} /v:${{ env.MSBUILD_VERBOSITY }} @@ -238,10 +268,11 @@ jobs: name: new-experiment-logs-${{ matrix.multitarget }}-winui${{ matrix.winui }} path: ./**/*.*log - wasm-linux: + uno-linux: runs-on: ubuntu-latest env: HEADS_DIRECTORY: tooling/ProjectHeads + PROJECT_DIRECTORY: tooling/ProjectTemplate TEST_PROJECT_NAME: CiTestExp steps: @@ -256,6 +287,18 @@ jobs: with: global-json-file: tooling/global.json + # iOS/maccatalyst workloads aren't installable on Linux (Uno.Sdk + # auto-filters those TFMs there). android + wasm-tools are both + # required: even a `-f net9.0-browserwasm` build restores all of the + # head's TargetFrameworks, so the net9.0-android TFM's workload is + # validated during restore. + # Run from ./tooling so global.json scopes the install to the pinned + # SDK feature band; otherwise the workloads land on the runner's newer + # preinstalled SDK and the 9.0.x build can't see them (NETSDK1147). + - name: Install .NET workloads + working-directory: tooling + run: dotnet workload install android wasm-tools + - name: .NET Info (if diagnostics) if: ${{ env.ENABLE_DIAGNOSTICS == 'true' }} run: dotnet --info @@ -284,21 +327,18 @@ jobs: working-directory: ./components run: dotnet new ctk-component -n ${{ env.TEST_PROJECT_NAME }} - - name: Generate solution - shell: pwsh - working-directory: ./ - run: ./tooling/GenerateAllSolution.ps1${{ env.ENABLE_DIAGNOSTICS == 'true' && ' -UseDiagnostics' || '' }} -MultiTargets wasm - - - name: dotnet build + # Build-Toolkit-Gallery.ps1 sets up TFMs/WinUI/project references and builds the Uno head + # directly (components are pulled in transitively as ProjectReferences), so this replaces + # the previous solution-gen + component prebuild + two head builds with one step - the old + # sequence built every component up to 3x over. + - name: Build Uno head (gallery) shell: pwsh working-directory: ./ - run: ./tooling/Build-Toolkit-Components.ps1 -Release -MultiTargets wasm ${{ env.ENABLE_DIAGNOSTICS == 'true' && ' -BinlogOutput ./ -EnableBinLogs' || '' }} - - # TODO: Do we want to run tests here? Can we do that on linux easily? + run: ./tooling/Build-Toolkit-Gallery.ps1 -Heads Uno -Release -MultiTargets wasm,linux ${{ env.ENABLE_DIAGNOSTICS == 'true' && ' -BinlogOutput ./ -EnableBinLogs' || '' }} - name: Artifact - Diagnostic Logs uses: actions/upload-artifact@v4 if: ${{ (env.ENABLE_DIAGNOSTICS == 'true' || env.COREHOST_TRACE != '') && always() }} with: - name: linux-logs + name: uno-linux-logs path: ./**/*.*log diff --git a/Build-Toolkit-Components.ps1 b/Build-Toolkit-Components.ps1 index 6cbc0ec5..4fac8c41 100644 --- a/Build-Toolkit-Components.ps1 +++ b/Build-Toolkit-Components.ps1 @@ -57,11 +57,11 @@ Date: 2/19/2024 #> Param ( - [ValidateSet('all', 'wasm', 'uwp', 'wasdk', 'wpf', 'linuxgtk', 'macos', 'ios', 'android', 'netstandard')] + [ValidateSet('all', 'wasm', 'uwp', 'wasdk', 'wpf', 'win32', 'linux', 'macos', 'ios', 'android', 'netstandard')] [Alias("mt")] [string[]]$MultiTargets = @('uwp', 'wasm', 'wasdk'), # default settings - - [ValidateSet('wasm', 'uwp', 'wasdk', 'wpf', 'linuxgtk', 'macos', 'ios', 'android', 'netstandard')] + + [ValidateSet('wasm', 'uwp', 'wasdk', 'wpf', 'win32', 'linux', 'macos', 'ios', 'android', 'netstandard')] [string[]]$ExcludeMultiTargets = @(), # default settings [Alias("c")] @@ -97,7 +97,7 @@ Param ( if ($MultiTargets -eq 'all') { - $MultiTargets = @('wasm', 'uwp', 'wasdk', 'wpf', 'linuxgtk', 'macos', 'ios', 'android', 'netstandard') + $MultiTargets = @('wasm', 'uwp', 'wasdk', 'wpf', 'win32', 'linux', 'macos', 'ios', 'android', 'netstandard') } if ($null -eq $ExcludeMultiTargets) diff --git a/Build-Toolkit-Gallery.ps1 b/Build-Toolkit-Gallery.ps1 index 7d92154e..cf27564c 100644 --- a/Build-Toolkit-Gallery.ps1 +++ b/Build-Toolkit-Gallery.ps1 @@ -9,7 +9,7 @@ Specifies the MultiTarget TFM(s) to include for building the components. The default value is 'all'. .PARAMETER ExcludeMultiTargets - Specifies the MultiTarget TFM(s) to exclude for building the components. The default value excludes targets that require additional tooling or workloads to build: 'wpf', 'linuxgtk', 'macos', 'ios', and 'android'. Run uno-check to install the required workloads. + Specifies the MultiTarget TFM(s) to exclude for building the components. The default value excludes targets that require additional tooling or workloads to build: 'wpf', 'linux', 'macos', 'ios', and 'android'. Run uno-check to install the required workloads. .PARAMETER Heads The heads to include in the build. Default is 'Uwp', 'Wasdk', 'Wasm'. @@ -46,17 +46,17 @@ Date: 2/19/2024 #> Param ( - [ValidateSet('all', 'wasm', 'uwp', 'wasdk', 'wpf', 'linuxgtk', 'macos', 'ios', 'android', 'netstandard')] + [ValidateSet('all', 'wasm', 'uwp', 'wasdk', 'wpf', 'win32', 'linux', 'macos', 'ios', 'android', 'netstandard')] [Alias("mt")] [string[]]$MultiTargets = @('uwp', 'wasdk', 'wasm'), # default settings - - [ValidateSet('wasm', 'uwp', 'wasdk', 'wpf', 'linuxgtk', 'macos', 'ios', 'android', 'netstandard')] + + [ValidateSet('wasm', 'uwp', 'wasdk', 'wpf', 'win32', 'linux', 'macos', 'ios', 'android', 'netstandard')] [string[]]$ExcludeMultiTargets = @(), # default settings - [ValidateSet('all', 'Uwp', 'Wasdk', 'Wasm', 'Tests.Uwp', 'Tests.Wasdk')] + [ValidateSet('all', 'Uwp', 'Wasdk', 'Wasm', 'Uno', 'Tests.Uwp', 'Tests.Wasdk')] [string[]]$Heads = @('Uwp', 'Wasdk', 'Wasm'), - [ValidateSet('Uwp', 'Wasdk', 'Wasm', 'Tests.Uwp', 'Tests.Wasdk')] + [ValidateSet('Uwp', 'Wasdk', 'Wasm', 'Uno', 'Tests.Uwp', 'Tests.Wasdk')] [string[]]$ExcludeHeads, [Alias("bl")] @@ -102,7 +102,7 @@ if ($MultiTargets.Contains('uwp') -and $MultiTargets.Contains('wasdk')) } if ($MultiTargets -eq 'all') { - $MultiTargets = @('wasm', 'uwp', 'wasdk', 'wpf', 'linuxgtk', 'macos', 'ios', 'android', 'netstandard') + $MultiTargets = @('wasm', 'uwp', 'wasdk', 'wpf', 'win32', 'linux', 'macos', 'ios', 'android', 'netstandard') } if ($ExcludeMultiTargets) { @@ -131,17 +131,31 @@ if ($Components -notcontains 'Converters') { & $PSScriptRoot\MultiTarget\GenerateAllProjectReferences.ps1 -MultiTarget $MultiTargets -Components $Components if ($Heads -eq 'all') { - $Heads = @('Uwp', 'Wasdk', 'Wasm', 'Tests.Uwp', 'Tests.Wasdk') + $Heads = @('Uwp', 'Wasdk', 'Wasm', 'Uno', 'Tests.Uwp', 'Tests.Wasdk') } function Invoke-MSBuildWithBinlog { param ( - [string]$TargetHeadPath + [string]$TargetHeadPath, + [string]$TargetFramework ) # Reset build args to default $msbuildArgs = @("-r", "-m", "-t:Clean,Build") + if ($TargetFramework) { + # dotnet build's "-f" does a scoped inner-build restore for just that TFM; plain + # "/p:TargetFramework=" on a multi-targeted project restores the outer project's full TFM + # closure first, which fails for components that don't support every TFM the head declares. + # msbuild.exe has no "-f" equivalent, so this only reliably supports one TFM at a time there. + if ($($PSVersionTable.Platform) -eq "Unix") { + $msbuildArgs += "-f:$TargetFramework" + } + else { + $msbuildArgs += "/p:TargetFramework=$TargetFramework" + } + } + # Add additional properties to the msbuild arguments if ($AdditionalProperties) { foreach ($property in $AdditionalProperties.GetEnumerator()) { @@ -153,12 +167,13 @@ function Invoke-MSBuildWithBinlog { if ($EnableBinLogs) { # Get binlog filename and output path $csprojFileName = [System.IO.Path]::GetFileNameWithoutExtension($TargetHeadPath) - $defaultBinlogFilename = "$csprojFileName.msbuild.binlog" + $binlogSuffix = $TargetFramework ? ".$TargetFramework" : "" + $defaultBinlogFilename = "$csprojFileName$binlogSuffix.msbuild.binlog" $finalBinlogPath = $defaultBinlogFilename; # Set default binlog output location if not provided if ($BinlogOutput) { - $finalBinlogPath = "$BinlogOutput/$defaultBinlogFilename" + $finalBinlogPath = "$BinlogOutput/$defaultBinlogFilename" } $msbuildArgs += "/bl:$finalBinlogPath" @@ -172,7 +187,40 @@ function Invoke-MSBuildWithBinlog { $msbuildArgs += "/verbosity:detailed" } - msbuild $msbuildArgs $TargetHeadPath + # On Linux there's no msbuild.exe on PATH; dotnet build is the only option there anyway. + if ($($PSVersionTable.Platform) -eq "Unix") { + dotnet build $msbuildArgs $TargetHeadPath + } + else { + msbuild $msbuildArgs $TargetHeadPath + } +} + +# The Uno.Sdk head covers several MultiTargets from one multi-TFM csproj (see +# ProjectHeads/AllComponents/Uno/CommunityToolkit.App.Uno.csproj). Building all of its enabled TFMs +# in one invocation isn't reliable across every combination, so - matching what CI already does - +# build it one TFM at a time via `-f`, only for the TFMs the requested $MultiTargets actually enable. +function Get-UnoSdkHeadTargetFrameworks { + param ( + [string[]]$MultiTargets + ) + + $targetFrameworks = [System.Collections.ArrayList]::new() + + if (($MultiTargets | Where-Object { @('win32', 'linux', 'macos') -contains $_ }).Count -gt 0) { + [void]$targetFrameworks.Add('net9.0-desktop') + } + if ($MultiTargets -contains 'wasm') { + [void]$targetFrameworks.Add('net9.0-browserwasm') + } + if ($MultiTargets -contains 'android') { + [void]$targetFrameworks.Add('net9.0-android') + } + if ($MultiTargets -contains 'ios') { + [void]$targetFrameworks.Add('net9.0-ios') + } + + return $targetFrameworks } foreach ($head in $Heads) { @@ -182,5 +230,19 @@ foreach ($head in $Heads) { $targetHeadPath = Get-ChildItem "$PSScriptRoot/ProjectHeads/AllComponents/$head/*.csproj" - Invoke-MSBuildWithBinlog $targetHeadPath $EnableBinLogs $BinlogOutput + if ($head -eq 'Uno') { + $unoTargetFrameworks = Get-UnoSdkHeadTargetFrameworks -MultiTargets $MultiTargets + + if ($unoTargetFrameworks.Count -eq 0) { + Write-Warning "None of the requested MultiTargets ($MultiTargets) are served by the Uno.Sdk head. Skipping." + continue + } + + foreach ($targetFramework in $unoTargetFrameworks) { + Invoke-MSBuildWithBinlog $targetHeadPath $targetFramework + } + } + else { + Invoke-MSBuildWithBinlog $targetHeadPath + } } diff --git a/CommunityToolkit.App.Shared/Renderers/Markdown/MarkdownTextBlock.cs b/CommunityToolkit.App.Shared/Renderers/Markdown/MarkdownTextBlock.cs index 2b0d3293..76ef5e8d 100644 --- a/CommunityToolkit.App.Shared/Renderers/Markdown/MarkdownTextBlock.cs +++ b/CommunityToolkit.App.Shared/Renderers/Markdown/MarkdownTextBlock.cs @@ -16,7 +16,7 @@ #endif #endif -#if HAS_UNO_WASM +#if HAS_UNO_WASM && !WINUI3 using Markdig; using Uno.Foundation.Interop; using Uno.UI.Runtime.WebAssembly; @@ -27,7 +27,7 @@ namespace CommunityToolkit.App.Shared.Renderers; /// /// Provide an abstraction around the Toolkit MarkdownTextBlock for both UWP and WinUI 3 in the same namespace (until 8.0) as well as a polyfill for WebAssembly/WASM. /// -#if HAS_UNO_WASM +#if HAS_UNO_WASM && !WINUI3 [HtmlElement("div")] public partial class MarkdownTextBlock : TextBlock { diff --git a/GenerateAllSolution.ps1 b/GenerateAllSolution.ps1 index 72eb9bac..f2ea256f 100644 --- a/GenerateAllSolution.ps1 +++ b/GenerateAllSolution.ps1 @@ -38,11 +38,11 @@ Date: April 27, 2022 #> Param ( - [ValidateSet('all', 'wasm', 'uwp', 'wasdk', 'wpf', 'linuxgtk', 'macos', 'ios', 'android', 'netstandard')] + [ValidateSet('all', 'wasm', 'uwp', 'wasdk', 'wpf', 'win32', 'linux', 'macos', 'ios', 'android', 'netstandard')] [Alias("mt")] - [string[]]$MultiTargets = @('uwp', 'wasm', 'wasdk'), + [string[]]$MultiTargets = @('uwp', 'wasm', 'wasdk', 'win32'), - [ValidateSet('wasm', 'uwp', 'wasdk', 'wpf', 'linuxgtk', 'macos', 'ios', 'android', 'netstandard')] + [ValidateSet('wasm', 'uwp', 'wasdk', 'wpf', 'win32', 'linux', 'macos', 'ios', 'android', 'netstandard')] [string[]]$ExcludeMultiTargets = @(), # default settings [Alias("c")] @@ -54,12 +54,12 @@ Param ( [string[]]$ExcludeComponents, [switch]$UseDiagnostics = $false, - + [bool]$Launch = $true ) if ($MultiTargets.Contains('all')) { - $MultiTargets = @('wasm', 'uwp', 'wasdk', 'wpf', 'linuxgtk', 'macos', 'ios', 'android', 'netstandard') + $MultiTargets = @('wasm', 'uwp', 'wasdk', 'wpf', 'win32', 'linux', 'macos', 'ios', 'android', 'netstandard') } if ($null -eq $ExcludeMultiTargets) @@ -150,11 +150,25 @@ foreach ($componentName in $Components) { # Deployable sample gallery heads # Only include heads for requested MultiTargets if components were included that use them. -# === -# TODO: this handles separate project heads, but won't directly handle the unified Skia head from Uno. -# Once we have that, just do a transform on the csproj filename inside this loop to decide the same csproj for those separate MultiTargets. -# === +# These have no head project of their own - they're served by the unified Uno.Sdk head added below. +$unoSdkHeadMultiTargets = @('win32', 'linux', 'macos', 'ios', 'android') + +# The Uno.Sdk head is implied by the requested MultiTargets, not a separate switch: it's the only +# head that can serve win32/linux/macos/ios/android, and for wasm it replaces the classic Wasm head +# once WinUI 3 is requested (WinUI 2 + wasm keeps using the classic head). +$includeUnoSdkHead = (($allUsedMultiTargetPrefs | Where-Object { $unoSdkHeadMultiTargets -contains $_ }).Count -gt 0) -or ` + ($allUsedMultiTargetPrefs.Contains('wasm') -and $WinUIMajorVersion -eq 3) + foreach ($multitarget in $allUsedMultiTargetPrefs) { + if ($unoSdkHeadMultiTargets -contains $multitarget) { + continue + } + + # When using the Uno.Sdk head, skip the traditional Wasm head (Uno.Sdk covers wasm for WinUI 3) + if ($multitarget -eq 'wasm' -and $includeUnoSdkHead) { + continue + } + # capitalize first letter, avoid case sensitivity issues on linux $csprojFileNamePartForMultiTarget = $multitarget.substring(0,1).ToUpper() + $multitarget.Substring(1).ToLower() @@ -168,6 +182,15 @@ foreach ($multitarget in $allUsedMultiTargetPrefs) { } } +if ($includeUnoSdkHead) { + $unoHeadPath = "./tooling/ProjectHeads/AllComponents/Uno/CommunityToolkit.App.Uno.csproj" + if (Test-Path $unoHeadPath) { + [void]$projects.Add($unoHeadPath) + } else { + Write-Warning "Uno.Sdk head project not found at $unoHeadPath." + } +} + if ($UseDiagnostics.IsPresent) { $sdkoptions = "-d" diff --git a/GenerateSingleSolution.ps1 b/GenerateSingleSolution.ps1 index e0e73d7d..a3294ad4 100644 --- a/GenerateSingleSolution.ps1 +++ b/GenerateSingleSolution.ps1 @@ -33,7 +33,7 @@ Date: Feb 9, 2023 #> Param ( - [ValidateSet('all', 'wasm', 'uwp', 'wasdk', 'wpf', 'linuxgtk', 'macos', 'ios', 'android')] + [ValidateSet('all', 'wasm', 'uwp', 'wasdk', 'wpf', 'win32', 'linux', 'macos', 'ios', 'android')] [Alias("mt")] [string[]]$MultiTargets = @('uwp', 'wasm', 'wasdk'), @@ -98,7 +98,7 @@ if (-not (Test-Path "$componentPath/src" -PathType Container)) # ----------------- if ($MultiTargets.Contains('all')) { - $MultiTargets = @('wasm', 'uwp', 'wasdk', 'wpf', 'linuxgtk', 'macos', 'ios', 'android') + $MultiTargets = @('wasm', 'uwp', 'wasdk', 'wpf', 'win32', 'linux', 'macos', 'ios', 'android') } if ($null -eq $ExcludeMultiTargets) @@ -188,9 +188,25 @@ Write-Output "Generating solution for $componentName in $generatedSolutionFilePa # All heads are included by default since they reside in the same folder as the component. # Remove any heads that are not required for the solution. -# TODO: this handles separate project heads, but won't directly handle the unified Skia head from Uno. -# Once we have that, just do a transform on the csproj filename inside this loop to decide the same csproj for those separate MultiTargets. +# These have no head project of their own - they're served by the unified Uno.Sdk head added below. +$unoSdkHeadMultiTargets = @('win32', 'linux', 'macos', 'ios', 'android') + +# The Uno.Sdk head is implied by the requested MultiTargets, not a separate switch: it's the only +# head that can serve win32/linux/macos/ios/android, and for wasm it replaces the classic Wasm head +# once WinUI 3 is requested (WinUI 2 + wasm keeps using the classic head). +$includeUnoSdkHead = (($MultiTargets | Where-Object { $unoSdkHeadMultiTargets -contains $_ }).Count -gt 0) -or ` + ($MultiTargets.Contains('wasm') -and $WinUIMajorVersion -eq 3) + foreach ($multitarget in $MultiTargets) { + if ($unoSdkHeadMultiTargets -contains $multitarget) { + continue + } + + # When using the Uno.Sdk head, skip the traditional Wasm head (Uno.Sdk covers wasm for WinUI 3) + if ($multitarget -eq 'wasm' -and $includeUnoSdkHead) { + continue + } + # capitalize first letter, avoid case sensitivity issues on linux $csprojFileNamePartForMultiTarget = $multitarget.substring(0,1).ToUpper() + $multitarget.Substring(1).ToLower() @@ -208,6 +224,17 @@ foreach ($multitarget in $MultiTargets) { } } +if ($includeUnoSdkHead) { + $unoHeadPath = "$outputHeadsDir\Uno\*Uno.csproj" + if (Test-Path $unoHeadPath) { + foreach ($foundItem in Get-ChildItem $unoHeadPath) { + $projects = $projects + $foundItem.FullName + } + } else { + Write-Warning "Uno.Sdk head project not found at $unoHeadPath." + } +} + # Include common dependencies required for solution to build $projects = $projects + "$PSScriptRoot\CommunityToolkit.App.Shared\**\*.*proj" $projects = $projects + "$PSScriptRoot\CommunityToolkit.Tests.Shared\**\*.*proj" diff --git a/GenerateVSCodeLaunchConfig.ps1 b/GenerateVSCodeLaunchConfig.ps1 index 58ced9ed..f8809ea2 100644 --- a/GenerateVSCodeLaunchConfig.ps1 +++ b/GenerateVSCodeLaunchConfig.ps1 @@ -9,7 +9,7 @@ function CreateVsCodeLaunchConfigJson { ) return "{ - `"name`": `"$projectName`", + `"name`": `"$projectName (Wasm)`", `"type`": `"coreclr`", `"request`": `"launch`", `"program`": `"dotnet`", @@ -29,6 +29,32 @@ function CreateVsCodeLaunchConfigJson { }"; } +function CreateUnoVsCodeLaunchConfigJson { + param ( + [string]$projectName + ) + + return "{ + `"name`": `"$projectName (Uno)`", + `"type`": `"coreclr`", + `"request`": `"launch`", + `"program`": `"dotnet`", + `"args`": [ + `"run`", + `"build`", + `"/r`", + `"/p:UnoSourceGeneratorUseGenerationHost=true`", + `"/p:UnoSourceGeneratorUseGenerationController=false`", + `"/p:UnoRemoteControlPort=443`", + `"--project=`$`{workspaceFolder`}/components/$projectName/heads/Uno/$projectName.Uno.csproj`" + ], + `"presentation`": { + `"group`": `"2`" + }, + `"cwd`": `"`$`{workspaceFolder`}/components/$projectName/heads/Uno`" + }"; +} + $launchConfigJson = Get-Content -Path "$PSScriptRoot/../.vscode/launch.json" -ErrorAction Stop; $launchConfig = $launchConfigJson | ConvertFrom-Json; @@ -46,8 +72,11 @@ foreach ($projectPath in Get-ChildItem -Directory -Depth 0 -Path "$PSScriptRoot/ $configJson = CreateVsCodeLaunchConfigJson $projectName; $config = $configJson | ConvertFrom-Json; - $launchConfig.configurations += $config; + + $unoConfigJson = CreateUnoVsCodeLaunchConfigJson $projectName; + $unoConfig = $unoConfigJson | ConvertFrom-Json; + $launchConfig.configurations += $unoConfig; } if ($allowGitChanges.IsPresent) { diff --git a/MultiTarget/AvailableTargetFrameworks.props b/MultiTarget/AvailableTargetFrameworks.props index 1c02bc51..fbf0a593 100644 --- a/MultiTarget/AvailableTargetFrameworks.props +++ b/MultiTarget/AvailableTargetFrameworks.props @@ -15,7 +15,7 @@ net9.0; net9.0; net9.0; - + net9.0-android; net9.0-maccatalyst; net9.0-ios; @@ -24,6 +24,7 @@ net9.0; net9.0; net9.0; + net9.0; netstandard2.0; diff --git a/MultiTarget/Defaults.props b/MultiTarget/Defaults.props index 86e5e82f..fbf71733 100644 --- a/MultiTarget/Defaults.props +++ b/MultiTarget/Defaults.props @@ -1,5 +1,5 @@ - uwp;wasdk;wpf;wasm;linuxgtk;macos;ios;android; + uwp;wasdk;wpf;win32;wasm;linux;macos;ios;android; \ No newline at end of file diff --git a/MultiTarget/DefinedConstants.props b/MultiTarget/DefinedConstants.props index b5c8c2c9..6152d9e8 100644 --- a/MultiTarget/DefinedConstants.props +++ b/MultiTarget/DefinedConstants.props @@ -13,7 +13,10 @@ $(DefineConstants);__IOS__; $(DefineConstants);__MACOS__; $(DefineConstants);HAS_UNO_SKIA;__SKIA__;WINDOWS_WPF; - $(DefineConstants);HAS_UNO_SKIA;__SKIA__;__GTK__; + $(DefineConstants);HAS_UNO_SKIA;__SKIA__;__GTK__; + $(DefineConstants);HAS_UNO_SKIA;__SKIA__; + + $(DefineConstants);HAS_UNO_SKIA;__SKIA__; $(DefineConstants);NET9_0_OR_GREATER $(DefineConstants);NET8_0_OR_GREATER diff --git a/MultiTarget/EnabledTargetFrameworks.props b/MultiTarget/EnabledTargetFrameworks.props index 6f1c0ab9..e321af61 100644 --- a/MultiTarget/EnabledTargetFrameworks.props +++ b/MultiTarget/EnabledTargetFrameworks.props @@ -10,14 +10,20 @@ $(TargetFrameworks);$(WinAppSdkTargetFrameworks) - true - true + true + true $(TargetFrameworks);$(DotnetCommonTargetFramework) - $(TargetFrameworks);$(MacOSLibTargetFrameworks) + + $(TargetFrameworks);$(MacOSLibTargetFrameworks) $(TargetFrameworks);$(iOSLibTargetFrameworks) $(TargetFrameworks);$(AndroidLibTargetFrameworks) diff --git a/MultiTarget/Filter-Supported-Components.ps1 b/MultiTarget/Filter-Supported-Components.ps1 index bc187e85..2ba1a0bb 100644 --- a/MultiTarget/Filter-Supported-Components.ps1 +++ b/MultiTarget/Filter-Supported-Components.ps1 @@ -17,7 +17,7 @@ Date: 6/6/2025 #> Param ( - [ValidateSet('all', 'wasm', 'uwp', 'wasdk', 'wpf', 'linuxgtk', 'macos', 'ios', 'android', 'netstandard')] + [ValidateSet('all', 'wasm', 'uwp', 'wasdk', 'wpf', 'win32', 'linux', 'macos', 'ios', 'android', 'netstandard')] [Alias("mt")] [Parameter(Mandatory=$true)] [string[]]$MultiTargets, @@ -32,7 +32,7 @@ Param ( ) if ($MultiTargets -eq 'all') { - $MultiTargets = @('wasm', 'uwp', 'wasdk', 'wpf', 'linuxgtk', 'macos', 'ios', 'android', 'netstandard') + $MultiTargets = @('wasm', 'uwp', 'wasdk', 'wpf', 'win32', 'linux', 'macos', 'ios', 'android', 'netstandard') } $supportedComponents = @(); diff --git a/MultiTarget/GenerateAllProjectReferences.ps1 b/MultiTarget/GenerateAllProjectReferences.ps1 index 62ca3b02..ab495bf4 100644 --- a/MultiTarget/GenerateAllProjectReferences.ps1 +++ b/MultiTarget/GenerateAllProjectReferences.ps1 @@ -4,8 +4,8 @@ Param ( [Parameter(HelpMessage = "Only projects that support these targets will have references generated for use by deployable heads.")] [Alias("mt")] - [ValidateSet('wasm', 'uwp', 'wasdk', 'wpf', 'linuxgtk', 'macos', 'ios', 'android', 'netstandard')] - [string[]]$MultiTargets = @("uwp", "wasdk", "wpf", "wasm", "linuxgtk", "macos", "ios", "android", "netstandard"), + [ValidateSet('wasm', 'uwp', 'wasdk', 'wpf', 'win32', 'linux', 'macos', 'ios', 'android', 'netstandard')] + [string[]]$MultiTargets = @("uwp", "wasdk", "wpf", "win32", "wasm", "linux", "macos", "ios", "android", "netstandard"), [Parameter(HelpMessage = "The names of the components to generate references for. Defaults to all components.")] [string[]]$Components = @("all"), diff --git a/MultiTarget/GenerateMultiTargetAwareProjectReferenceProps.ps1 b/MultiTarget/GenerateMultiTargetAwareProjectReferenceProps.ps1 index dbbd6728..461ca388 100644 --- a/MultiTarget/GenerateMultiTargetAwareProjectReferenceProps.ps1 +++ b/MultiTarget/GenerateMultiTargetAwareProjectReferenceProps.ps1 @@ -15,9 +15,9 @@ Param ( [string]$projectRootPlaceholder = "[ProjectRoot]", [Parameter(HelpMessage = "Only projects that support these targets will have references generated for use by deployable heads.")] - [ValidateSet("uwp", "wasdk", "wpf", "wasm", "linuxgtk", "macos", "ios", "android", "netstandard")] + [ValidateSet("uwp", "wasdk", "wpf", "win32", "wasm", "linux", "macos", "ios", "android", "netstandard")] [Alias("mt")] - [string[]] $MultiTargets = @("uwp", "wasdk", "wpf", "wasm", "linuxgtk", "macos", "ios", "android", "netstandard") + [string[]] $MultiTargets = @("uwp", "wasdk", "wpf", "win32", "wasm", "linux", "macos", "ios", "android", "netstandard") ) if ($projectPath.EndsWith(".projitems")) { @@ -74,7 +74,7 @@ function ShouldMultiTargetMsBuildValue([string] $target) { return $(ShouldMultiTarget $target).ToString().ToLower() } -$targeted = @("uwp", "wasdk", "wpf", "wasm", "linuxgtk", "macos", "ios", "android", "netstandard").Where({ ShouldMultiTarget $_ }) +$targeted = @("uwp", "wasdk", "wpf", "win32", "wasm", "linux", "macos", "ios", "android", "netstandard").Where({ ShouldMultiTarget $_ }) if ($targeted.Count -gt 0) { Write-Host "Generating project references for $([System.IO.Path]::GetFileNameWithoutExtension($projectFileName)): $($targeted -Join ', ')" @@ -84,7 +84,8 @@ $templateContents = $templateContents -replace [regex]::escape("[CanTargetWasm]" $templateContents = $templateContents -replace [regex]::escape("[CanTargetUwp]"), "'$(ShouldMultiTargetMsBuildValue "uwp")'"; $templateContents = $templateContents -replace [regex]::escape("[CanTargetWasdk]"), "'$(ShouldMultiTargetMsBuildValue "wasdk")'"; $templateContents = $templateContents -replace [regex]::escape("[CanTargetWpf]"), "'$(ShouldMultiTargetMsBuildValue "wpf")'"; -$templateContents = $templateContents -replace [regex]::escape("[CanTargetLinuxGtk]"), "'$(ShouldMultiTargetMsBuildValue "linuxgtk")'"; +$templateContents = $templateContents -replace [regex]::escape("[CanTargetWin32]"), "'$(ShouldMultiTargetMsBuildValue "win32")'"; +$templateContents = $templateContents -replace [regex]::escape("[CanTargetLinux]"), "'$(ShouldMultiTargetMsBuildValue "linux")'"; $templateContents = $templateContents -replace [regex]::escape("[CanTargetMacOS]"), "'$(ShouldMultiTargetMsBuildValue "macos")'"; $templateContents = $templateContents -replace [regex]::escape("[CanTargetiOS]"), "'$(ShouldMultiTargetMsBuildValue "ios")'"; $templateContents = $templateContents -replace [regex]::escape("[CanTargetDroid]"), "'$(ShouldMultiTargetMsBuildValue "android")'"; diff --git a/MultiTarget/Library.props b/MultiTarget/Library.props index 61ab36c8..99e59e36 100644 --- a/MultiTarget/Library.props +++ b/MultiTarget/Library.props @@ -7,13 +7,15 @@ + + + - - diff --git a/MultiTarget/MultiTargetAwareProjectReference.props.template b/MultiTarget/MultiTargetAwareProjectReference.props.template index 86b3c4d8..9ab42496 100644 --- a/MultiTarget/MultiTargetAwareProjectReference.props.template +++ b/MultiTarget/MultiTargetAwareProjectReference.props.template @@ -11,7 +11,8 @@ ($(IsUwp) == 'true' AND [CanTargetUwp] == 'true') OR ($(IsWinAppSdk) == 'true' AND [CanTargetWasdk] == 'true') OR ($(IsWpf) == 'true' AND [CanTargetWpf] == 'true') OR - ($(IsGtk) == 'true' AND [CanTargetLinuxGtk] == 'true') OR + ($(IsWin32) == 'true' AND [CanTargetWin32] == 'true') OR + ($(IsLinux) == 'true' AND [CanTargetLinux] == 'true') OR ($(IsMacOS) == 'true' AND [CanTargetMacOS] == 'true') OR ($(IsiOS) == 'true' AND [CanTargetiOS] == 'true') OR ($(IsDroid) == 'true' AND [CanTargetDroid] == 'true') OR diff --git a/MultiTarget/MultiTargetAwareSharedProjectImport.props.template b/MultiTarget/MultiTargetAwareSharedProjectImport.props.template index 06c9c8e0..0108d531 100644 --- a/MultiTarget/MultiTargetAwareSharedProjectImport.props.template +++ b/MultiTarget/MultiTargetAwareSharedProjectImport.props.template @@ -7,7 +7,7 @@ ($(IsUwp) == 'true' AND 'false' == 'true') OR ($(IsWinAppSdk) == 'true' AND 'true' == 'true') OR ($(IsWpf) == 'true' AND 'false' == 'true') OR - ($(IsGtk) == 'true' AND 'false' == 'true') OR + ($(IsLinux) == 'true' AND 'false' == 'true') OR ($(IsMacOS) == 'true' AND 'false' == 'true') OR ($(IsiOS) == 'true' AND 'false' == 'true') OR ($(IsDroid) == 'true' AND 'false' == 'true') OR diff --git a/MultiTarget/MultiTargetIdentifiers.props b/MultiTarget/MultiTargetIdentifiers.props index 47c8eb48..37fdfca2 100644 --- a/MultiTarget/MultiTargetIdentifiers.props +++ b/MultiTarget/MultiTargetIdentifiers.props @@ -17,7 +17,8 @@ true true - true + true + true true true true @@ -33,9 +34,14 @@ true true - true - true - true + + true + true + + true + true + true true true @@ -47,7 +53,7 @@ true true - true + true + 5.5.87 + + 6.4.229 + + $(UnoUIPackageVersion) + $(UnoWinUIPackageVersion) - - - + + - + + + + + + + + true - - + + + + + + + + - - + + + - - + + @@ -45,7 +68,12 @@ $(NoWarn);CS1570; - + + + + + + diff --git a/MultiTarget/ReadMe.md b/MultiTarget/ReadMe.md index fd8d7f19..d6ad1704 100644 --- a/MultiTarget/ReadMe.md +++ b/MultiTarget/ReadMe.md @@ -17,7 +17,7 @@ By default, all available targets are enabled: ```xml - uwp;wasdk;wpf;wasm;linuxgtk;macos;ios;android; + uwp;wasdk;wpf;win32;wasm;linux;macos;ios;android; ``` @@ -32,6 +32,32 @@ For example, to only target UWP, WASM and Android: ``` +### Available targets + +A MultiTarget names a *platform your component runs on*, not a TFM. The TFMs and the deployable +head it maps to depend on which WinUI version is selected, since Uno 5.x (WinUI 2, `Uno.UI`) and +Uno 6.x (WinUI 3, `Uno.WinUI`) ship different heads. + +| MultiTarget | Platform | WinUI 2 (Uno 5.x) | WinUI 3 (Uno 6.x) | +| --- | --- | --- | --- | +| `uwp` | Windows, UWP XAML | `uap10.0.17763`, `net{x}-windows10.0.26100` | n/a | +| `wasdk` | Windows, Windows App SDK | n/a | `net{x}-windows10.0.19041` | +| `wasm` | WebAssembly | `net{x}`, Wasm head | `net{x}`, `net{x}-browserwasm` head | +| `wpf` | Windows desktop, Skia WPF | `net{x}`, Skia WPF head | n/a — use `win32` | +| `win32` | Windows desktop, Skia Win32 | n/a — use `wpf` | `net{x}`, `net{x}-desktop` head | +| `linux` | Linux desktop | `net{x}`, Skia GTK head | `net{x}`, `net{x}-desktop` head | +| `macos` | macOS | `net{x}-maccatalyst` | `net{x}`, `net{x}-desktop` head | +| `ios` | iOS | `net{x}-ios` | `net{x}-ios` | +| `android` | Android | `net{x}-android` | `net{x}-android` | +| `netstandard` | .NET Standard, no WinUI | `netstandard2.0` | `netstandard2.0` | + +`win32`, `linux` and `macos` all deploy from the same build output on WinUI 3: Uno 6 replaced the +per-OS Skia heads with a single cross-platform `net{x}-desktop` head that picks its backend at +runtime. They stay separate MultiTargets so a component can declare — and solution generation and +CI can request — only the desktop platforms that are actually supported. + +Mac Catalyst is WinUI 2 only. Uno 7 removes support for it, and on WinUI 3 macOS is reached through +the Skia desktop head instead, so `net{x}-maccatalyst` is not part of the WinUI 3 package surface. ## ProjectReference Generation diff --git a/MultiTarget/Test-Component-Support.ps1 b/MultiTarget/Test-Component-Support.ps1 index 3844dedd..1ef8f054 100644 --- a/MultiTarget/Test-Component-Support.ps1 +++ b/MultiTarget/Test-Component-Support.ps1 @@ -32,11 +32,11 @@ Date: 6/6/2025 #> Param ( - [ValidateSet('wasm', 'uwp', 'wasdk', 'wpf', 'linuxgtk', 'macos', 'ios', 'android', 'netstandard')] + [ValidateSet('wasm', 'uwp', 'wasdk', 'wpf', 'win32', 'linux', 'macos', 'ios', 'android', 'netstandard')] [Alias("smt")] [string[]]$SupportedMultiTargets, - [ValidateSet('all', 'wasm', 'uwp', 'wasdk', 'wpf', 'linuxgtk', 'macos', 'ios', 'android', 'netstandard')] + [ValidateSet('all', 'wasm', 'uwp', 'wasdk', 'wpf', 'win32', 'linux', 'macos', 'ios', 'android', 'netstandard')] [Alias("rmt")] [Parameter(Mandatory=$true)] [string[]]$RequestedMultiTargets, @@ -51,17 +51,20 @@ Param ( ) if ($RequestedMultiTargets -eq 'all') { - $RequestedMultiTargets = @('wasm', 'uwp', 'wasdk', 'wpf', 'linuxgtk', 'macos', 'ios', 'android', 'netstandard') + $RequestedMultiTargets = @('wasm', 'uwp', 'wasdk', 'wpf', 'win32', 'linux', 'macos', 'ios', 'android', 'netstandard') } # List of WinUI-0 (non-WinUI) compatible multitargets $WinUI0MultiTargets = @('netstandard') -# List of WinUI-2 compatible multitargets -$WinUI2MultiTargets = @('uwp', 'wasm', 'wpf', 'linuxgtk', 'macos', 'ios', 'android') +# List of WinUI-2 (Uno 5.x / Uno.UI) compatible multitargets. +# 'linux' is the Skia GTK head there; 'wpf' is the Skia WPF head. +$WinUI2MultiTargets = @('uwp', 'wasm', 'wpf', 'linux', 'macos', 'ios', 'android') -# List of WinUI-3 compatible multitargets -$WinUI3MultiTargets = @('wasdk', 'wasm', 'wpf', 'linuxgtk', 'macos', 'ios', 'android') +# List of WinUI-3 (Uno 6.x / Uno.WinUI) compatible multitargets. +# win32, linux and macos are the desktop surface, all served by the single net9.0-desktop head that +# replaced Uno 5's per-OS Skia heads. 'wpf' stays WinUI 2 only, since Uno 6 dropped Uno.UI.Skia.Wpf. +$WinUI3MultiTargets = @('wasdk', 'wasm', 'win32', 'linux', 'macos', 'ios', 'android') # If WinUI 0 is requested, the component must not support WinUI 2 or WinUI 3 to be built. # If WinUI 2 or 3 is requested, the component must have a target that supports WinUI 2 or 3 to be built. diff --git a/MultiTarget/UseTargetFrameworks.ps1 b/MultiTarget/UseTargetFrameworks.ps1 index 1fa00ae4..927df5dc 100644 --- a/MultiTarget/UseTargetFrameworks.ps1 +++ b/MultiTarget/UseTargetFrameworks.ps1 @@ -22,19 +22,19 @@ #> Param ( [Parameter(HelpMessage = "The target frameworks to enable.")] - [ValidateSet('all', 'wasm', 'uwp', 'wasdk', 'wpf', 'linuxgtk', 'macos', 'ios', 'android', 'netstandard')] + [ValidateSet('all', 'wasm', 'uwp', 'wasdk', 'wpf', 'win32', 'linux', 'macos', 'ios', 'android', 'netstandard')] [Alias("mt")] [string[]]$MultiTargets = @('uwp', 'wasdk', 'wasm'), # default settings [Parameter(HelpMessage = "The target frameworks to disable.")] - [ValidateSet('wasm', 'uwp', 'wasdk', 'wpf', 'linuxgtk', 'macos', 'ios', 'android', 'netstandard')] + [ValidateSet('wasm', 'uwp', 'wasdk', 'wpf', 'win32', 'linux', 'macos', 'ios', 'android', 'netstandard')] [string[]]$ExcludeMultiTargets = @() # default settings ) $fileContents = Get-Content -Path $PSScriptRoot/EnabledMultiTargets.props $newFileContents = $fileContents; -$AllMultiTargets = @('wasm', 'uwp', 'wasdk', 'wpf', 'linuxgtk', 'macos', 'ios', 'android', 'netstandard') +$AllMultiTargets = @('wasm', 'uwp', 'wasdk', 'wpf', 'win32', 'linux', 'macos', 'ios', 'android', 'netstandard') # Exclude as needed foreach ($excluded in $ExcludeMultiTargets) { diff --git a/MultiTarget/UseUnoWinUI.ps1 b/MultiTarget/UseUnoWinUI.ps1 index 7b419a43..e260c3dd 100644 --- a/MultiTarget/UseUnoWinUI.ps1 +++ b/MultiTarget/UseUnoWinUI.ps1 @@ -11,14 +11,12 @@ function ApplyWinUISwap([string] $filePath) { $fileContents = $fileContents -replace '2', '3'; $fileContents = $fileContents -replace 'Uwp', 'WinUI'; $fileContents = $fileContents -replace 'Uwp', 'WinUI'; - $fileContents = $fileContents -replace 'Uno.UI', 'Uno.WinUI'; } if ($winUIMajorVersion -eq "2") { $fileContents = $fileContents -replace '3', '2'; $fileContents = $fileContents -replace 'WinUI', 'Uwp'; $fileContents = $fileContents -replace 'WinUI', 'Uwp'; - $fileContents = $fileContents -replace 'Uno.WinUI', 'Uno.UI'; } Set-Content -Force -Path $filePath -Value $fileContents; @@ -27,7 +25,6 @@ function ApplyWinUISwap([string] $filePath) { Write-Output "Switching Uno to WinUI $winUIMajorVersion"; -ApplyWinUISwap $PSScriptRoot/../ProjectHeads/App.Head.Uno.props ApplyWinUISwap $PSScriptRoot/PackageReferences/Uno.props ApplyWinUISwap $PSScriptRoot/WinUI.TargetVersion.props diff --git a/ProjectHeads/AllComponents/Uno/Assets/Icons/icon.svg b/ProjectHeads/AllComponents/Uno/Assets/Icons/icon.svg new file mode 100644 index 00000000..a15af53a --- /dev/null +++ b/ProjectHeads/AllComponents/Uno/Assets/Icons/icon.svg @@ -0,0 +1,42 @@ + + + + + + diff --git a/ProjectHeads/AllComponents/Uno/Assets/Icons/icon_foreground.svg b/ProjectHeads/AllComponents/Uno/Assets/Icons/icon_foreground.svg new file mode 100644 index 00000000..8ffc41ae --- /dev/null +++ b/ProjectHeads/AllComponents/Uno/Assets/Icons/icon_foreground.svg @@ -0,0 +1,137 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ProjectHeads/AllComponents/Uno/Assets/SharedAssets.md b/ProjectHeads/AllComponents/Uno/Assets/SharedAssets.md new file mode 100644 index 00000000..b1cc4e76 --- /dev/null +++ b/ProjectHeads/AllComponents/Uno/Assets/SharedAssets.md @@ -0,0 +1,32 @@ +# Shared Assets + +See documentation about assets here: https://github.com/unoplatform/uno/blob/master/doc/articles/features/working-with-assets.md + +## Here is a cheat sheet + +1. Add the image file to the `Assets` directory of a shared project. +2. Set the build action to `Content`. +3. (Recommended) Provide an asset for various scales/dpi + +### Examples + +```text +\Assets\Images\logo.scale-100.png +\Assets\Images\logo.scale-200.png +\Assets\Images\logo.scale-400.png + +\Assets\Images\scale-100\logo.png +\Assets\Images\scale-200\logo.png +\Assets\Images\scale-400\logo.png +``` + +### Table of scales + +| Scale | WinUI | iOS | Android | +|-------|:-----------:|:---------------:|:-------:| +| `100` | scale-100 | @1x | mdpi | +| `125` | scale-125 | N/A | N/A | +| `150` | scale-150 | N/A | hdpi | +| `200` | scale-200 | @2x | xhdpi | +| `300` | scale-300 | @3x | xxhdpi | +| `400` | scale-400 | N/A | xxxhdpi | diff --git a/ProjectHeads/AllComponents/Uno/Assets/Splash/splash_screen.svg b/ProjectHeads/AllComponents/Uno/Assets/Splash/splash_screen.svg new file mode 100644 index 00000000..8ffc41ae --- /dev/null +++ b/ProjectHeads/AllComponents/Uno/Assets/Splash/splash_screen.svg @@ -0,0 +1,137 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ProjectHeads/AllComponents/Uno/CommunityToolkit.App.Uno.csproj b/ProjectHeads/AllComponents/Uno/CommunityToolkit.App.Uno.csproj new file mode 100644 index 00000000..8e8965b2 --- /dev/null +++ b/ProjectHeads/AllComponents/Uno/CommunityToolkit.App.Uno.csproj @@ -0,0 +1,127 @@ + + + + + + + + true + + + $(TargetFrameworks)net9.0-desktop; + $(TargetFrameworks)net9.0-browserwasm; + $(TargetFrameworks)net9.0-android; + $(TargetFrameworks)net9.0-ios; + + + + Exe + + + SkiaRenderer; + + + false + true + CommunityToolkit.App.Uno + + + true + true + true + true + true + true + true + true + true + true + 3 + true + WinUI + + $(DefineConstants);WINUI3 + + + + + + + + + + + + net9.0 + net9.0-android + net9.0-ios + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SourceAssets/%(RecursiveDir)%(FileName)%(Extension) + + + SourceAssets/%(RecursiveDir)%(FileName)%(Extension) + + + SourceAssets/%(RecursiveDir)%(FileName)%(Extension).dat + + + + + + $(NoWarn);IL2026;Uno0006 + + + + diff --git a/ProjectHeads/AllComponents/Uno/Platforms/Android/AndroidManifest.xml b/ProjectHeads/AllComponents/Uno/Platforms/Android/AndroidManifest.xml new file mode 100644 index 00000000..24ee4aea --- /dev/null +++ b/ProjectHeads/AllComponents/Uno/Platforms/Android/AndroidManifest.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/ProjectHeads/AllComponents/Uno/Platforms/Android/Assets/AboutAssets.txt b/ProjectHeads/AllComponents/Uno/Platforms/Android/Assets/AboutAssets.txt new file mode 100644 index 00000000..6b8fc66e --- /dev/null +++ b/ProjectHeads/AllComponents/Uno/Platforms/Android/Assets/AboutAssets.txt @@ -0,0 +1,5 @@ +Any raw assets you want to be deployed with your application can be placed in this +directory (and child directories). Deployment of the asset to your application is done +using the IDE or by using the following MSBuild property in your .csproj: + + diff --git a/ProjectHeads/AllComponents/Uno/Platforms/Android/Main.Android.cs b/ProjectHeads/AllComponents/Uno/Platforms/Android/Main.Android.cs new file mode 100644 index 00000000..31d89a6f --- /dev/null +++ b/ProjectHeads/AllComponents/Uno/Platforms/Android/Main.Android.cs @@ -0,0 +1,23 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Android.App; +using Android.Runtime; + +namespace CommunityToolkit.App.Uno; + +[global::Android.App.ApplicationAttribute( + Label = "@string/ApplicationName", + Icon = "@mipmap/icon", + LargeHeap = true, + HardwareAccelerated = true, + Theme = "@style/AppTheme" +)] +public class Application : Microsoft.UI.Xaml.NativeApplication +{ + public Application(IntPtr javaReference, JniHandleOwnership transfer) + : base(() => new CommunityToolkit.App.Shared.App(), javaReference, transfer) + { + } +} \ No newline at end of file diff --git a/ProjectHeads/AllComponents/Uno/Platforms/Android/MainActivity.Android.cs b/ProjectHeads/AllComponents/Uno/Platforms/Android/MainActivity.Android.cs new file mode 100644 index 00000000..ad38d011 --- /dev/null +++ b/ProjectHeads/AllComponents/Uno/Platforms/Android/MainActivity.Android.cs @@ -0,0 +1,20 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Android.App; +using Android.Content.PM; +using Android.OS; +using Android.Views; +using Android.Widget; + +namespace CommunityToolkit.App.Uno; + +[Activity( + MainLauncher = true, + ConfigurationChanges = global::Uno.UI.ActivityHelper.AllConfigChanges, + WindowSoftInputMode = SoftInput.AdjustNothing | SoftInput.StateHidden +)] +public class MainActivity : Microsoft.UI.Xaml.ApplicationActivity +{ +} \ No newline at end of file diff --git a/ProjectHeads/AllComponents/Uno/Platforms/Android/Resources/values/Strings.xml b/ProjectHeads/AllComponents/Uno/Platforms/Android/Resources/values/Strings.xml new file mode 100644 index 00000000..ee06a129 --- /dev/null +++ b/ProjectHeads/AllComponents/Uno/Platforms/Android/Resources/values/Strings.xml @@ -0,0 +1,4 @@ + + + CommunityToolkit + diff --git a/ProjectHeads/AllComponents/Uno/Platforms/Android/Resources/values/Styles.xml b/ProjectHeads/AllComponents/Uno/Platforms/Android/Resources/values/Styles.xml new file mode 100644 index 00000000..2c3bf24a --- /dev/null +++ b/ProjectHeads/AllComponents/Uno/Platforms/Android/Resources/values/Styles.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/ProjectHeads/AllComponents/Uno/Platforms/Android/environment.conf b/ProjectHeads/AllComponents/Uno/Platforms/Android/environment.conf new file mode 100644 index 00000000..9d9709a9 --- /dev/null +++ b/ProjectHeads/AllComponents/Uno/Platforms/Android/environment.conf @@ -0,0 +1,2 @@ +## Mono GC tuning params +MONO_GC_PARAMS=soft-heap-limit=512m,nursery-size=64m,evacuation-threshold=66,major=marksweep,concurrent-sweep diff --git a/ProjectHeads/AllComponents/Uno/Platforms/Desktop/Program.cs b/ProjectHeads/AllComponents/Uno/Platforms/Desktop/Program.cs new file mode 100644 index 00000000..2f5400b3 --- /dev/null +++ b/ProjectHeads/AllComponents/Uno/Platforms/Desktop/Program.cs @@ -0,0 +1,23 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Uno.UI.Hosting; +using CommunityToolkit.App.Shared; + +internal class Program +{ + [STAThread] + public static void Main(string[] args) + { + var host = UnoPlatformHostBuilder.Create() + .App(() => new CommunityToolkit.App.Shared.App()) + .UseX11() + .UseLinuxFrameBuffer() + .UseMacOS() + .UseWin32() + .Build(); + + host.Run(); + } +} \ No newline at end of file diff --git a/ProjectHeads/AllComponents/Uno/Platforms/WebAssembly/LinkerConfig.xml b/ProjectHeads/AllComponents/Uno/Platforms/WebAssembly/LinkerConfig.xml new file mode 100644 index 00000000..cc3e5cdd --- /dev/null +++ b/ProjectHeads/AllComponents/Uno/Platforms/WebAssembly/LinkerConfig.xml @@ -0,0 +1,3 @@ + + + diff --git a/ProjectHeads/AllComponents/Uno/Platforms/WebAssembly/Program.cs b/ProjectHeads/AllComponents/Uno/Platforms/WebAssembly/Program.cs new file mode 100644 index 00000000..f07914ec --- /dev/null +++ b/ProjectHeads/AllComponents/Uno/Platforms/WebAssembly/Program.cs @@ -0,0 +1,19 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Uno.UI.Hosting; +using CommunityToolkit.App.Shared; + +public class Program +{ + public static async Task Main(string[] args) + { + var host = UnoPlatformHostBuilder.Create() + .App(() => new CommunityToolkit.App.Shared.App()) + .UseWebAssembly() + .Build(); + + await host.RunAsync(); + } +} \ No newline at end of file diff --git a/ProjectHeads/AllComponents/Uno/Platforms/WebAssembly/WasmScripts/AppManifest.js b/ProjectHeads/AllComponents/Uno/Platforms/WebAssembly/WasmScripts/AppManifest.js new file mode 100644 index 00000000..8018667f --- /dev/null +++ b/ProjectHeads/AllComponents/Uno/Platforms/WebAssembly/WasmScripts/AppManifest.js @@ -0,0 +1,3 @@ +var UnoAppManifest = { + displayName: "CommunityToolkit" +} diff --git a/ProjectHeads/AllComponents/Uno/Platforms/WebAssembly/manifest.webmanifest b/ProjectHeads/AllComponents/Uno/Platforms/WebAssembly/manifest.webmanifest new file mode 100644 index 00000000..8d6e55be --- /dev/null +++ b/ProjectHeads/AllComponents/Uno/Platforms/WebAssembly/manifest.webmanifest @@ -0,0 +1,10 @@ +{ + "name": "CommunityToolkit", + "description": "CommunityToolkit", + "short_name": "CommunityToolkit", + "start_url": "/index.html", + "display": "standalone", + "background_color": "#FFFFFF", + "theme_color": "#FFFFFF", + "scope": "/" +} diff --git a/ProjectHeads/AllComponents/Uno/Platforms/iOS/Entitlements.plist b/ProjectHeads/AllComponents/Uno/Platforms/iOS/Entitlements.plist new file mode 100644 index 00000000..6631ffa6 --- /dev/null +++ b/ProjectHeads/AllComponents/Uno/Platforms/iOS/Entitlements.plist @@ -0,0 +1,6 @@ + + + + + + diff --git a/ProjectHeads/AllComponents/Uno/Platforms/iOS/Info.plist b/ProjectHeads/AllComponents/Uno/Platforms/iOS/Info.plist new file mode 100644 index 00000000..8f81dd88 --- /dev/null +++ b/ProjectHeads/AllComponents/Uno/Platforms/iOS/Info.plist @@ -0,0 +1,43 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + + CFBundleIdentifier + com.companyname.CommunityToolkit + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + CommunityToolkit + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + MinimumOSVersion + 16.0 + UIDeviceFamily + + 1 + 2 + + UILaunchStoryboardName + LaunchScreen + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/ProjectHeads/AllComponents/Uno/Platforms/iOS/Main.iOS.cs b/ProjectHeads/AllComponents/Uno/Platforms/iOS/Main.iOS.cs new file mode 100644 index 00000000..b163d7dd --- /dev/null +++ b/ProjectHeads/AllComponents/Uno/Platforms/iOS/Main.iOS.cs @@ -0,0 +1,21 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Uno.UI.Hosting; +using CommunityToolkit.App.Shared; + +namespace CommunityToolkit.App.Uno; + +public class EntryPoint +{ + public static void Main(string[] args) + { + var host = UnoPlatformHostBuilder.Create() + .App(() => new CommunityToolkit.App.Shared.App()) + .UseAppleUIKit() + .Build(); + + host.Run(); + } +} \ No newline at end of file diff --git a/ProjectHeads/AllComponents/Uno/Platforms/iOS/Media.xcassets/LaunchImages.launchimage/Contents.json b/ProjectHeads/AllComponents/Uno/Platforms/iOS/Media.xcassets/LaunchImages.launchimage/Contents.json new file mode 100644 index 00000000..4103a707 --- /dev/null +++ b/ProjectHeads/AllComponents/Uno/Platforms/iOS/Media.xcassets/LaunchImages.launchimage/Contents.json @@ -0,0 +1,20 @@ +{ + "images": [ + { + "idiom": "universal", + "scale": "1x" + }, + { + "idiom": "universal", + "scale": "2x" + }, + { + "idiom": "universal", + "scale": "3x" + } + ], + "info": { + "version": 1, + "author": "xcode" + } +} diff --git a/ProjectHeads/AllComponents/Uno/Platforms/iOS/PrivacyInfo.xcprivacy b/ProjectHeads/AllComponents/Uno/Platforms/iOS/PrivacyInfo.xcprivacy new file mode 100644 index 00000000..1d00d2f5 --- /dev/null +++ b/ProjectHeads/AllComponents/Uno/Platforms/iOS/PrivacyInfo.xcprivacy @@ -0,0 +1,31 @@ + + + + + NSPrivacyTracking + + NSPrivacyTrackingDomains + + NSPrivacyCollectedDataTypes + + NSPrivacyAccessedAPITypes + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategorySystemBootTime + NSPrivacyAccessedAPITypeReasons + + 35F9.1 + + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryFileTimestamp + NSPrivacyAccessedAPITypeReasons + + C617.1 + + + + + diff --git a/ProjectHeads/AllComponents/Wasm/Program.cs b/ProjectHeads/AllComponents/Wasm/Program.cs index 43e990c1..a7aae2ee 100644 --- a/ProjectHeads/AllComponents/Wasm/Program.cs +++ b/ProjectHeads/AllComponents/Wasm/Program.cs @@ -5,7 +5,7 @@ using CommunityToolkit.App.Shared; #if WINAPPSDK -using Microsoft.UI.Xaml; +using Uno.UI.Hosting; #else using Windows.UI.Xaml; #endif @@ -14,6 +14,17 @@ namespace CommunityToolkit.App.Wasm; public class Program { +#if WINAPPSDK + static async Task Main(string[] args) + { + var host = UnoPlatformHostBuilder.Create() + .App(() => new CommunityToolkit.App.Shared.App()) + .UseWebAssembly() + .Build(); + + await host.RunAsync(); + } +#else private static CommunityToolkit.App.Shared.App? _app; static int Main(string[] args) @@ -22,4 +33,5 @@ static int Main(string[] args) return 0; } +#endif } diff --git a/ProjectHeads/App.Head.Android.props b/ProjectHeads/App.Head.Android.props new file mode 100644 index 00000000..2a864dec --- /dev/null +++ b/ProjectHeads/App.Head.Android.props @@ -0,0 +1,7 @@ + + + + + false + + diff --git a/ProjectHeads/App.Head.Uno.UI.Dependencies.props b/ProjectHeads/App.Head.Uno.UI.Dependencies.props index 361463b9..49fe326c 100644 --- a/ProjectHeads/App.Head.Uno.UI.Dependencies.props +++ b/ProjectHeads/App.Head.Uno.UI.Dependencies.props @@ -6,5 +6,3 @@ - - diff --git a/ProjectHeads/App.Head.Uno.WinUI.Dependencies.props b/ProjectHeads/App.Head.Uno.WinUI.Dependencies.props index d18fbfb5..77c9bc88 100644 --- a/ProjectHeads/App.Head.Uno.WinUI.Dependencies.props +++ b/ProjectHeads/App.Head.Uno.WinUI.Dependencies.props @@ -4,6 +4,6 @@ - + diff --git a/ProjectHeads/App.Head.Uno.props b/ProjectHeads/App.Head.Uno.props index 865ea717..6f5cafab 100644 --- a/ProjectHeads/App.Head.Uno.props +++ b/ProjectHeads/App.Head.Uno.props @@ -1,6 +1,7 @@ - WinUI + WinUI + Uwp @@ -25,8 +26,9 @@ - + + diff --git a/ProjectHeads/App.Head.Wasm.props b/ProjectHeads/App.Head.Wasm.props index ed7c9705..32487037 100644 --- a/ProjectHeads/App.Head.Wasm.props +++ b/ProjectHeads/App.Head.Wasm.props @@ -2,6 +2,7 @@ Exe $(WasmHeadTargetFramework.Split(';')[0]) + false + + + + + true + + + $(TargetFrameworks)net9.0-desktop; + $(TargetFrameworks)net9.0-browserwasm; + $(TargetFrameworks)net9.0-android; + $(TargetFrameworks)net9.0-ios; + + + + Exe + ProjectTemplate.Samples + ProjectTemplate.Samples.Uno + + + SkiaRenderer; + + + false + true + + + true + true + true + true + true + true + true + true + true + true + 3 + true + WinUI + + $(DefineConstants);WINUI3 + + + + + + + + net9.0 + net9.0-android + net9.0-ios + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SourceAssets/%(RecursiveDir)%(FileName)%(Extension).dat + + + + + + + $(NoWarn);IL2026;Uno0006 + + + + diff --git a/ProjectHeads/SingleComponent/Wasm/Program.cs b/ProjectHeads/SingleComponent/Wasm/Program.cs index 9522ede6..91bd1b52 100644 --- a/ProjectHeads/SingleComponent/Wasm/Program.cs +++ b/ProjectHeads/SingleComponent/Wasm/Program.cs @@ -4,10 +4,25 @@ using CommunityToolkit.App.Shared; +#if WINAPPSDK +using Uno.UI.Hosting; +#endif + namespace ProjectTemplateExperiment.Samples.Wasm; public class Program { +#if WINAPPSDK + static async Task Main(string[] args) + { + var host = UnoPlatformHostBuilder.Create() + .App(() => new App()) + .UseWebAssembly() + .Build(); + + await host.RunAsync(); + } +#else private static App? _app; static int Main(string[] args) @@ -16,4 +31,5 @@ static int Main(string[] args) return 0; } +#endif } diff --git a/ProjectHeads/Targets/AddMultiTargetCompatibleSampleDocs.targets b/ProjectHeads/Targets/AddMultiTargetCompatibleSampleDocs.targets index 02d0ea88..bda9cdc7 100644 --- a/ProjectHeads/Targets/AddMultiTargetCompatibleSampleDocs.targets +++ b/ProjectHeads/Targets/AddMultiTargetCompatibleSampleDocs.targets @@ -8,10 +8,22 @@ uwp wasm wasdk + wpf + win32 + linux macos ios android netstandard + + + + $(MultiTargetIdentifier)win32; + $(MultiTargetIdentifier)linux; + $(MultiTargetIdentifier)macos; diff --git a/ProjectHeads/Tasks/CheckMultiTarget.props b/ProjectHeads/Tasks/CheckMultiTarget.props index 812b68fe..2b9c581b 100644 --- a/ProjectHeads/Tasks/CheckMultiTarget.props +++ b/ProjectHeads/Tasks/CheckMultiTarget.props @@ -120,7 +120,22 @@ multiTargetIdentifier = ExtractMultiTargetIdentifier(multiTargetPropsContent); } - IsSupported = multiTargetIdentifier.Split(';').Contains(MultiTargetIdentifier); + // MultiTargetIdentifier may be a ';' separated list: the unified Uno desktop head covers + // several MultiTargets with a single build, so a doc matching any one of them is supported. + string[] componentMultiTargets = multiTargetIdentifier.Split(';'); + IsSupported = false; + + foreach (string headMultiTarget in MultiTargetIdentifier.Split(';')) + { + string trimmedHeadMultiTarget = headMultiTarget.Trim(); + + if (trimmedHeadMultiTarget.Length > 0 && componentMultiTargets.Contains(trimmedHeadMultiTarget)) + { + IsSupported = true; + break; + } + } + FilePath.SetMetadata("IsSupported", IsSupported.ToString()); ]]> diff --git a/ProjectTemplate/src/MultiTarget.props b/ProjectTemplate/src/MultiTarget.props index b11c1942..7d1e11c3 100644 --- a/ProjectTemplate/src/MultiTarget.props +++ b/ProjectTemplate/src/MultiTarget.props @@ -4,6 +4,6 @@ MultiTarget is a custom property that indicates which target a project is designed to be built for / run on. Used to create project references, generate solution files, enable/disable TargetFrameworks, and build nuget packages. --> - uwp;wasdk;wpf;wasm;linuxgtk;macos;ios;android; + uwp;wasdk;wpf;win32;wasm;linux;macos;ios;android; \ No newline at end of file diff --git a/global.json b/global.json index c71c5732..9637c215 100644 --- a/global.json +++ b/global.json @@ -3,8 +3,9 @@ "version": "10.0.402", "rollForward": "latestFeature" }, - "msbuild-sdks": + "msbuild-sdks": { - "MSBuild.Sdk.Extras":"3.0.44" + "MSBuild.Sdk.Extras":"3.0.44", + "Uno.Sdk": "7.0.0-dev.51" } } From 8ba29560a977a2ee91107ed907c1de15c1dd50cf Mon Sep 17 00:00:00 2001 From: Martin Zikmund Date: Fri, 9 Oct 2026 11:01:05 +0200 Subject: [PATCH 02/15] Target Uno Platform 7.0 for WinUI 3 Uno.Sdk 7.0.0-dev.51 / Uno.WinUI 7.0.0-dev.1656, which require .NET 10. WinUI 2 (Uno.UI 5.x) stays on .NET 9. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01E8bkzyS24p8CYDWLUPsaPC --- .github/workflows/build.yml | 4 +-- Build-Toolkit-Gallery.ps1 | 8 ++--- MultiTarget/AvailableTargetFrameworks.props | 26 ++++++++------ MultiTarget/DefinedConstants.props | 3 +- MultiTarget/EnabledTargetFrameworks.props | 6 ++-- MultiTarget/MultiTargetIdentifiers.props | 2 +- MultiTarget/PackageReferences/Uno.props | 6 ++-- MultiTarget/ReadMe.md | 7 ++-- MultiTarget/Test-Component-Support.ps1 | 4 +-- .../Uno/CommunityToolkit.App.Uno.csproj | 34 +++++++++---------- .../Wasm/CommunityToolkit.App.Wasm.csproj | 3 +- .../App.Head.Uno.WinUI.Dependencies.props | 2 +- .../Uno/ProjectTemplate.Uno.csproj | 30 ++++++++-------- ...AddMultiTargetCompatibleSampleDocs.targets | 2 +- 14 files changed, 72 insertions(+), 65 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0415297b..0ab31a34 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -289,8 +289,8 @@ jobs: # iOS/maccatalyst workloads aren't installable on Linux (Uno.Sdk # auto-filters those TFMs there). android + wasm-tools are both - # required: even a `-f net9.0-browserwasm` build restores all of the - # head's TargetFrameworks, so the net9.0-android TFM's workload is + # required: even a `-f net10.0-browserwasm` build restores all of the + # head's TargetFrameworks, so the net10.0-android TFM's workload is # validated during restore. # Run from ./tooling so global.json scopes the install to the pinned # SDK feature band; otherwise the workloads land on the runner's newer diff --git a/Build-Toolkit-Gallery.ps1 b/Build-Toolkit-Gallery.ps1 index cf27564c..81a706c3 100644 --- a/Build-Toolkit-Gallery.ps1 +++ b/Build-Toolkit-Gallery.ps1 @@ -208,16 +208,16 @@ function Get-UnoSdkHeadTargetFrameworks { $targetFrameworks = [System.Collections.ArrayList]::new() if (($MultiTargets | Where-Object { @('win32', 'linux', 'macos') -contains $_ }).Count -gt 0) { - [void]$targetFrameworks.Add('net9.0-desktop') + [void]$targetFrameworks.Add('net10.0-desktop') } if ($MultiTargets -contains 'wasm') { - [void]$targetFrameworks.Add('net9.0-browserwasm') + [void]$targetFrameworks.Add('net10.0-browserwasm') } if ($MultiTargets -contains 'android') { - [void]$targetFrameworks.Add('net9.0-android') + [void]$targetFrameworks.Add('net10.0-android') } if ($MultiTargets -contains 'ios') { - [void]$targetFrameworks.Add('net9.0-ios') + [void]$targetFrameworks.Add('net10.0-ios') } return $targetFrameworks diff --git a/MultiTarget/AvailableTargetFrameworks.props b/MultiTarget/AvailableTargetFrameworks.props index fbf0a593..47ddf644 100644 --- a/MultiTarget/AvailableTargetFrameworks.props +++ b/MultiTarget/AvailableTargetFrameworks.props @@ -12,22 +12,26 @@ uap10.0.17763;net8.0-windows10.0.26100.0;net9.0-windows10.0.26100.0; net9.0-windows10.0.26100.0;net8.0-windows10.0.26100.0; - net9.0; - net9.0; - net9.0; + + net10.0 + net9.0 - net9.0-android; - net9.0-maccatalyst; - net9.0-ios; + $(UnoDotNetTargetFramework); + $(UnoDotNetTargetFramework); + $(UnoDotNetTargetFramework); + + $(UnoDotNetTargetFramework)-android; + $(UnoDotNetTargetFramework)-maccatalyst; + $(UnoDotNetTargetFramework)-ios; - net9.0; - net9.0; - net9.0; - net9.0; + $(UnoDotNetTargetFramework); + $(UnoDotNetTargetFramework); + $(UnoDotNetTargetFramework); + $(UnoDotNetTargetFramework); netstandard2.0; - net9.0; + $(UnoDotNetTargetFramework); \ No newline at end of file diff --git a/MultiTarget/DefinedConstants.props b/MultiTarget/DefinedConstants.props index 6152d9e8..d890e153 100644 --- a/MultiTarget/DefinedConstants.props +++ b/MultiTarget/DefinedConstants.props @@ -15,9 +15,10 @@ $(DefineConstants);HAS_UNO_SKIA;__SKIA__;WINDOWS_WPF; $(DefineConstants);HAS_UNO_SKIA;__SKIA__;__GTK__; $(DefineConstants);HAS_UNO_SKIA;__SKIA__; - + $(DefineConstants);HAS_UNO_SKIA;__SKIA__; + $(DefineConstants);NET10_0_OR_GREATER $(DefineConstants);NET9_0_OR_GREATER $(DefineConstants);NET8_0_OR_GREATER $(DefineConstants);NET7_0_OR_GREATER diff --git a/MultiTarget/EnabledTargetFrameworks.props b/MultiTarget/EnabledTargetFrameworks.props index e321af61..ce94724e 100644 --- a/MultiTarget/EnabledTargetFrameworks.props +++ b/MultiTarget/EnabledTargetFrameworks.props @@ -12,15 +12,15 @@ true true $(TargetFrameworks);$(DotnetCommonTargetFramework) $(TargetFrameworks);$(MacOSLibTargetFrameworks) diff --git a/MultiTarget/MultiTargetIdentifiers.props b/MultiTarget/MultiTargetIdentifiers.props index 37fdfca2..60f16dfa 100644 --- a/MultiTarget/MultiTargetIdentifiers.props +++ b/MultiTarget/MultiTargetIdentifiers.props @@ -34,7 +34,7 @@ true true - true true diff --git a/MultiTarget/PackageReferences/Uno.props b/MultiTarget/PackageReferences/Uno.props index d303c601..2b086f3f 100644 --- a/MultiTarget/PackageReferences/Uno.props +++ b/MultiTarget/PackageReferences/Uno.props @@ -2,8 +2,8 @@ 5.5.87 - - 6.4.229 + + 7.0.0-dev.1656 $(UnoUIPackageVersion) $(UnoWinUIPackageVersion) @@ -40,7 +40,7 @@ - + diff --git a/MultiTarget/ReadMe.md b/MultiTarget/ReadMe.md index d6ad1704..7c304f33 100644 --- a/MultiTarget/ReadMe.md +++ b/MultiTarget/ReadMe.md @@ -36,9 +36,10 @@ For example, to only target UWP, WASM and Android: A MultiTarget names a *platform your component runs on*, not a TFM. The TFMs and the deployable head it maps to depend on which WinUI version is selected, since Uno 5.x (WinUI 2, `Uno.UI`) and -Uno 6.x (WinUI 3, `Uno.WinUI`) ship different heads. +Uno 7.x (WinUI 3, `Uno.WinUI`) ship different heads and .NET versions: `net{x}` is `net9.0` on WinUI 2 and +`net10.0` on WinUI 3, since Uno 7 requires .NET 10. -| MultiTarget | Platform | WinUI 2 (Uno 5.x) | WinUI 3 (Uno 6.x) | +| MultiTarget | Platform | WinUI 2 (Uno 5.x) | WinUI 3 (Uno 7.x) | | --- | --- | --- | --- | | `uwp` | Windows, UWP XAML | `uap10.0.17763`, `net{x}-windows10.0.26100` | n/a | | `wasdk` | Windows, Windows App SDK | n/a | `net{x}-windows10.0.19041` | @@ -51,7 +52,7 @@ Uno 6.x (WinUI 3, `Uno.WinUI`) ship different heads. | `android` | Android | `net{x}-android` | `net{x}-android` | | `netstandard` | .NET Standard, no WinUI | `netstandard2.0` | `netstandard2.0` | -`win32`, `linux` and `macos` all deploy from the same build output on WinUI 3: Uno 6 replaced the +`win32`, `linux` and `macos` all deploy from the same build output on WinUI 3: Uno 6+ replaced the per-OS Skia heads with a single cross-platform `net{x}-desktop` head that picks its backend at runtime. They stay separate MultiTargets so a component can declare — and solution generation and CI can request — only the desktop platforms that are actually supported. diff --git a/MultiTarget/Test-Component-Support.ps1 b/MultiTarget/Test-Component-Support.ps1 index 1ef8f054..a78c756f 100644 --- a/MultiTarget/Test-Component-Support.ps1 +++ b/MultiTarget/Test-Component-Support.ps1 @@ -61,8 +61,8 @@ $WinUI0MultiTargets = @('netstandard') # 'linux' is the Skia GTK head there; 'wpf' is the Skia WPF head. $WinUI2MultiTargets = @('uwp', 'wasm', 'wpf', 'linux', 'macos', 'ios', 'android') -# List of WinUI-3 (Uno 6.x / Uno.WinUI) compatible multitargets. -# win32, linux and macos are the desktop surface, all served by the single net9.0-desktop head that +# List of WinUI-3 (Uno 7.x / Uno.WinUI) compatible multitargets. +# win32, linux and macos are the desktop surface, all served by the single net10.0-desktop head that # replaced Uno 5's per-OS Skia heads. 'wpf' stays WinUI 2 only, since Uno 6 dropped Uno.UI.Skia.Wpf. $WinUI3MultiTargets = @('wasdk', 'wasm', 'win32', 'linux', 'macos', 'ios', 'android') diff --git a/ProjectHeads/AllComponents/Uno/CommunityToolkit.App.Uno.csproj b/ProjectHeads/AllComponents/Uno/CommunityToolkit.App.Uno.csproj index 8e8965b2..f9614f99 100644 --- a/ProjectHeads/AllComponents/Uno/CommunityToolkit.App.Uno.csproj +++ b/ProjectHeads/AllComponents/Uno/CommunityToolkit.App.Uno.csproj @@ -6,16 +6,16 @@ - + true - $(TargetFrameworks)net9.0-desktop; - $(TargetFrameworks)net9.0-browserwasm; - $(TargetFrameworks)net9.0-android; - $(TargetFrameworks)net9.0-ios; + $(TargetFrameworks)net10.0-desktop; + $(TargetFrameworks)net10.0-browserwasm; + $(TargetFrameworks)net10.0-android; + $(TargetFrameworks)net10.0-ios; @@ -38,13 +38,13 @@ (Uno.Sdk defines IsDesktop identically; set here too so the head stays self-describing.) --> true true - true - true - true - true - true - true - true + true + true + true + true + true + true + true true 3 true @@ -60,12 +60,12 @@ - - net9.0 - net9.0-android - net9.0-ios + net10.0 + net10.0-android + net10.0-ios diff --git a/ProjectHeads/AllComponents/Wasm/CommunityToolkit.App.Wasm.csproj b/ProjectHeads/AllComponents/Wasm/CommunityToolkit.App.Wasm.csproj index ad0e0d70..3510eeed 100644 --- a/ProjectHeads/AllComponents/Wasm/CommunityToolkit.App.Wasm.csproj +++ b/ProjectHeads/AllComponents/Wasm/CommunityToolkit.App.Wasm.csproj @@ -11,11 +11,12 @@ wasm + + - diff --git a/ProjectHeads/App.Head.Uno.WinUI.Dependencies.props b/ProjectHeads/App.Head.Uno.WinUI.Dependencies.props index 77c9bc88..e10bff86 100644 --- a/ProjectHeads/App.Head.Uno.WinUI.Dependencies.props +++ b/ProjectHeads/App.Head.Uno.WinUI.Dependencies.props @@ -4,6 +4,6 @@ - + diff --git a/ProjectHeads/SingleComponent/Uno/ProjectTemplate.Uno.csproj b/ProjectHeads/SingleComponent/Uno/ProjectTemplate.Uno.csproj index c063d6d7..7c534824 100644 --- a/ProjectHeads/SingleComponent/Uno/ProjectTemplate.Uno.csproj +++ b/ProjectHeads/SingleComponent/Uno/ProjectTemplate.Uno.csproj @@ -4,15 +4,15 @@ + macos all share Uno's single cross-platform Skia desktop TFM. --> true - $(TargetFrameworks)net9.0-desktop; - $(TargetFrameworks)net9.0-browserwasm; - $(TargetFrameworks)net9.0-android; - $(TargetFrameworks)net9.0-ios; + $(TargetFrameworks)net10.0-desktop; + $(TargetFrameworks)net10.0-browserwasm; + $(TargetFrameworks)net10.0-android; + $(TargetFrameworks)net10.0-ios; @@ -35,13 +35,13 @@ ProjectReference gating) that needs to know which one(s), not just "some desktop target". --> true true - true - true - true - true - true - true - true + true + true + true + true + true + true + true true 3 true @@ -55,9 +55,9 @@ - net9.0 - net9.0-android - net9.0-ios + net10.0 + net10.0-android + net10.0-ios diff --git a/ProjectHeads/Targets/AddMultiTargetCompatibleSampleDocs.targets b/ProjectHeads/Targets/AddMultiTargetCompatibleSampleDocs.targets index bda9cdc7..6f16a26e 100644 --- a/ProjectHeads/Targets/AddMultiTargetCompatibleSampleDocs.targets +++ b/ProjectHeads/Targets/AddMultiTargetCompatibleSampleDocs.targets @@ -16,7 +16,7 @@ android netstandard - From 6e1735e9f7eff10cbdeadb5ca70f92304514a515 Mon Sep 17 00:00:00 2001 From: Martin Zikmund Date: Fri, 9 Oct 2026 11:52:07 +0200 Subject: [PATCH 03/15] Work around MSBuild.Sdk.Extras inferring net10.0 as .NETFramework See https://github.com/novotnyllc/MSBuildSdkExtras/issues/305 Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01E8bkzyS24p8CYDWLUPsaPC --- MultiTarget/Library.props | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/MultiTarget/Library.props b/MultiTarget/Library.props index 99e59e36..60904221 100644 --- a/MultiTarget/Library.props +++ b/MultiTarget/Library.props @@ -16,6 +16,11 @@ + + + .NETCoreApp + + From 0ce5baf857e560bf349a6e6ce776c494fa65a777 Mon Sep 17 00:00:00 2001 From: Martin Zikmund Date: Fri, 9 Oct 2026 11:52:08 +0200 Subject: [PATCH 04/15] Align Uno.Fonts.Fluent with Uno.WinUI 7 Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01E8bkzyS24p8CYDWLUPsaPC --- MultiTarget/PackageReferences/Uno.props | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/MultiTarget/PackageReferences/Uno.props b/MultiTarget/PackageReferences/Uno.props index 2b086f3f..96be9e3a 100644 --- a/MultiTarget/PackageReferences/Uno.props +++ b/MultiTarget/PackageReferences/Uno.props @@ -23,7 +23,9 @@ - + + + From 22741bf57fe501e01b48187c34b5bdfede3a3f21 Mon Sep 17 00:00:00 2001 From: Martin Zikmund Date: Fri, 9 Oct 2026 11:52:08 +0200 Subject: [PATCH 05/15] Disable Hot Design and App MCP on Uno 7 heads The versions pinned by Uno.Sdk 7.0.0-dev still reference pre-7.0 Uno assemblies (unoplatform/uno#24297). Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01E8bkzyS24p8CYDWLUPsaPC --- .../AllComponents/Uno/CommunityToolkit.App.Uno.csproj | 4 ++++ ProjectHeads/SingleComponent/Uno/ProjectTemplate.Uno.csproj | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/ProjectHeads/AllComponents/Uno/CommunityToolkit.App.Uno.csproj b/ProjectHeads/AllComponents/Uno/CommunityToolkit.App.Uno.csproj index f9614f99..27259efc 100644 --- a/ProjectHeads/AllComponents/Uno/CommunityToolkit.App.Uno.csproj +++ b/ProjectHeads/AllComponents/Uno/CommunityToolkit.App.Uno.csproj @@ -27,6 +27,10 @@ false true + + + true + true CommunityToolkit.App.Uno + true + true + + + From a46ea4ff2d0535aaadca5f1af1a09cfc49daf32a Mon Sep 17 00:00:00 2001 From: Martin Zikmund Date: Fri, 9 Oct 2026 12:08:58 +0200 Subject: [PATCH 08/15] Render docs with the Labs MarkdownTextBlock on Uno 7 Uno 7 supports RichTextBlock, so the Uno WinUI 3 heads can use the Labs MarkdownTextBlock instead of showing raw Markdown. Opt-in through LabsMarkdownTextBlockVersion until Labs publishes a build with Uno targets. Links now open through the same handler as on Windows. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01E8bkzyS24p8CYDWLUPsaPC --- .../Renderers/Markdown/MarkdownTextBlock.cs | 53 +++++++++++++++++-- .../ToolkitDocumentationRenderer.xaml.cs | 4 +- .../App.Head.Uno.WinUI.Dependencies.props | 8 +++ 3 files changed, 59 insertions(+), 6 deletions(-) diff --git a/CommunityToolkit.App.Shared/Renderers/Markdown/MarkdownTextBlock.cs b/CommunityToolkit.App.Shared/Renderers/Markdown/MarkdownTextBlock.cs index 76ef5e8d..0a6c0d5a 100644 --- a/CommunityToolkit.App.Shared/Renderers/Markdown/MarkdownTextBlock.cs +++ b/CommunityToolkit.App.Shared/Renderers/Markdown/MarkdownTextBlock.cs @@ -2,7 +2,10 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#if HAS_UNO +#if HAS_LABS_MARKDOWNTEXTBLOCK + using CommunityToolkit.WinUI.Controls; + using ToolkitMTB = CommunityToolkit.WinUI.Controls.MarkdownTextBlock; +#elif HAS_UNO #if WINAPPSDK using ToolkitMTB = Microsoft.UI.Xaml.Controls.TextBlock; #else @@ -27,7 +30,45 @@ namespace CommunityToolkit.App.Shared.Renderers; /// /// Provide an abstraction around the Toolkit MarkdownTextBlock for both UWP and WinUI 3 in the same namespace (until 8.0) as well as a polyfill for WebAssembly/WASM. /// -#if HAS_UNO_WASM && !WINUI3 +#if HAS_LABS_MARKDOWNTEXTBLOCK +public partial class MarkdownTextBlock : ToolkitMTB +{ + public MarkdownTextBlock() + { + IsTextSelectionEnabled = true; + + // Matches the Windows typography from ToolkitDocumentationRenderer.xaml + Config = new MarkdownConfig + { + Themes = new MarkdownThemes + { + H1FontSize = 28, + H1Margin = new Thickness(0, 20, 0, 4), + H2FontSize = 18, + H2Margin = new Thickness(0, 20, 0, 0), + H3FontSize = 16, + H4FontSize = 14, + H5FontSize = 14, + H5FontWeight = FontWeights.Normal, + H6FontSize = 14, + ParagraphMargin = new Thickness(0, 0, 0, 12), + ParagraphLineHeight = 20, + }, + }; + + OnLinkClicked += (_, e) => + { + LinkClicked?.Invoke(this, new LinkClickedEventArgs(e.Uri.ToString())); + e.Handled = true; + }; + } + + // RichTextBlock always wraps, kept so the shared XAML can set it + public TextWrapping TextWrapping { get; set; } + + public event EventHandler? LinkClicked; +} +#elif HAS_UNO_WASM && !WINUI3 [HtmlElement("div")] public partial class MarkdownTextBlock : TextBlock { @@ -108,6 +149,10 @@ public MarkdownTextBlock() #endif #if HAS_UNO -//// Polyfill dummy for event callback -public class LinkClickedEventArgs : EventArgs { } +public class LinkClickedEventArgs : EventArgs +{ + public LinkClickedEventArgs(string link) => Link = link; + + public string Link { get; } +} #endif diff --git a/CommunityToolkit.App.Shared/Renderers/ToolkitDocumentationRenderer.xaml.cs b/CommunityToolkit.App.Shared/Renderers/ToolkitDocumentationRenderer.xaml.cs index ddbcd721..3c30e82c 100644 --- a/CommunityToolkit.App.Shared/Renderers/ToolkitDocumentationRenderer.xaml.cs +++ b/CommunityToolkit.App.Shared/Renderers/ToolkitDocumentationRenderer.xaml.cs @@ -188,13 +188,13 @@ private static async Task GetDocumentationFileContents(ToolkitFrontMatte } } -#if HAS_UNO +#if HAS_UNO && !HAS_LABS_MARKDOWNTEXTBLOCK private void MarkdownTextBlock_LinkClicked(object sender, LinkClickedEventArgs e) { // No-op - WASM handles via browser 'a' tag, Windows has handler below. // TODO: For other platforms } -#elif !HAS_UNO +#else private async void MarkdownTextBlock_LinkClicked(object sender, LinkClickedEventArgs e) { if (!Uri.IsWellFormedUriString(e.Link, UriKind.Absolute)) diff --git a/ProjectHeads/App.Head.Uno.WinUI.Dependencies.props b/ProjectHeads/App.Head.Uno.WinUI.Dependencies.props index c7a00104..172299f4 100644 --- a/ProjectHeads/App.Head.Uno.WinUI.Dependencies.props +++ b/ProjectHeads/App.Head.Uno.WinUI.Dependencies.props @@ -8,4 +8,12 @@ + + + + $(DefineConstants);HAS_LABS_MARKDOWNTEXTBLOCK + + + + From 7e489b144ca8ed92067df52e9f31571274e30911 Mon Sep 17 00:00:00 2001 From: Martin Zikmund Date: Fri, 9 Oct 2026 12:27:41 +0200 Subject: [PATCH 09/15] Fix the Labs MarkdownTextBlock wrapper build and inline code size FontWeights lives in Microsoft.UI.Text on WinUI 3, and the Labs default inline code size (10) is too small next to 14px body text. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01E8bkzyS24p8CYDWLUPsaPC --- .../Renderers/Markdown/MarkdownTextBlock.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CommunityToolkit.App.Shared/Renderers/Markdown/MarkdownTextBlock.cs b/CommunityToolkit.App.Shared/Renderers/Markdown/MarkdownTextBlock.cs index 0a6c0d5a..bb2e1cd7 100644 --- a/CommunityToolkit.App.Shared/Renderers/Markdown/MarkdownTextBlock.cs +++ b/CommunityToolkit.App.Shared/Renderers/Markdown/MarkdownTextBlock.cs @@ -4,6 +4,7 @@ #if HAS_LABS_MARKDOWNTEXTBLOCK using CommunityToolkit.WinUI.Controls; + using Microsoft.UI.Text; using ToolkitMTB = CommunityToolkit.WinUI.Controls.MarkdownTextBlock; #elif HAS_UNO #if WINAPPSDK @@ -53,6 +54,7 @@ public MarkdownTextBlock() H6FontSize = 14, ParagraphMargin = new Thickness(0, 0, 0, 12), ParagraphLineHeight = 20, + InlineCodeFontSize = 12, }, }; From d3a60e46ec4905f68145b3cae350af366e4bddf7 Mon Sep 17 00:00:00 2001 From: Martin Zikmund Date: Tue, 27 Oct 2026 06:08:13 +0000 Subject: [PATCH 10/15] Update to Uno.Sdk 7.0.0-dev.89 Bump Uno.WinUI to 7.0.0-dev.2428 to match the Core version pinned by the SDK. Drop the Uno.WinUI.Lottie reference: Lottie is now built into Uno.WinUI and the standalone package stopped at 7.0.0-dev.1663, which would pull in an older Uno.WinUI. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01TXMNu1DnHGnhiqjJz6RnRw --- MultiTarget/PackageReferences/Uno.props | 2 +- ProjectHeads/App.Head.Uno.WinUI.Dependencies.props | 1 - global.json | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/MultiTarget/PackageReferences/Uno.props b/MultiTarget/PackageReferences/Uno.props index 96be9e3a..b9d9a6d6 100644 --- a/MultiTarget/PackageReferences/Uno.props +++ b/MultiTarget/PackageReferences/Uno.props @@ -3,7 +3,7 @@ 5.5.87 - 7.0.0-dev.1656 + 7.0.0-dev.2428 $(UnoUIPackageVersion) $(UnoWinUIPackageVersion) diff --git a/ProjectHeads/App.Head.Uno.WinUI.Dependencies.props b/ProjectHeads/App.Head.Uno.WinUI.Dependencies.props index 172299f4..72fcc9b0 100644 --- a/ProjectHeads/App.Head.Uno.WinUI.Dependencies.props +++ b/ProjectHeads/App.Head.Uno.WinUI.Dependencies.props @@ -4,7 +4,6 @@ - diff --git a/global.json b/global.json index 9637c215..8594f4d5 100644 --- a/global.json +++ b/global.json @@ -6,6 +6,6 @@ "msbuild-sdks": { "MSBuild.Sdk.Extras":"3.0.44", - "Uno.Sdk": "7.0.0-dev.51" + "Uno.Sdk": "7.0.0-dev.89" } } From 8817e1667c4cab0a4bad947e9540784dc792ada7 Mon Sep 17 00:00:00 2001 From: Martin Zikmund Date: Tue, 27 Oct 2026 06:23:42 +0000 Subject: [PATCH 11/15] Don't pass -r to dotnet build in Build-Toolkit-Gallery dotnet build reads -r as --runtime, so on Linux the following -m became the RuntimeIdentifier (NETSDK1083). It also restores implicitly, scoped to -f, while an explicit -restore restores the whole graph with the head's TFM. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01TXMNu1DnHGnhiqjJz6RnRw --- Build-Toolkit-Gallery.ps1 | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Build-Toolkit-Gallery.ps1 b/Build-Toolkit-Gallery.ps1 index 81a706c3..e54e9ed2 100644 --- a/Build-Toolkit-Gallery.ps1 +++ b/Build-Toolkit-Gallery.ps1 @@ -141,7 +141,12 @@ function Invoke-MSBuildWithBinlog { ) # Reset build args to default - $msbuildArgs = @("-r", "-m", "-t:Clean,Build") + $msbuildArgs = @("-m", "-t:Clean,Build") + + # dotnet build restores implicitly (scoped to "-f" below) and reads "-r" as --runtime + if ($($PSVersionTable.Platform) -ne "Unix") { + $msbuildArgs = @("-r") + $msbuildArgs + } if ($TargetFramework) { # dotnet build's "-f" does a scoped inner-build restore for just that TFM; plain From f7d5d558af34ee77850c5c3c2e9fed63d263a01d Mon Sep 17 00:00:00 2001 From: Martin Zikmund Date: Tue, 27 Oct 2026 06:23:42 +0000 Subject: [PATCH 12/15] Use the Uno 7 build of Uno.Microsoft.Xaml.Behaviors.Interactivity.WinUI 3.0.3 is built against Uno.WinUI 5, so EventTriggerBehavior wasn't a WinUI 3 DependencyObject on Uno 7 (CS1503). 4.0.0-dev.10 targets Uno.WinUI 7. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01TXMNu1DnHGnhiqjJz6RnRw --- ProjectHeads/App.Head.Uno.WinUI.Dependencies.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProjectHeads/App.Head.Uno.WinUI.Dependencies.props b/ProjectHeads/App.Head.Uno.WinUI.Dependencies.props index 72fcc9b0..c82250c5 100644 --- a/ProjectHeads/App.Head.Uno.WinUI.Dependencies.props +++ b/ProjectHeads/App.Head.Uno.WinUI.Dependencies.props @@ -3,7 +3,7 @@ - + From e47c8fc41c5f0741446f926ef9e96c5a8eb27204 Mon Sep 17 00:00:00 2001 From: Martin Zikmund Date: Tue, 27 Oct 2026 07:12:50 +0000 Subject: [PATCH 13/15] Don't reference System.Collections.Immutable from net10.0 sample projects It's part of the shared framework from .NET 10, so the explicit reference fails with NU1510 under warnings-as-errors on the Uno 7 (net10.0) sample builds. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01TXMNu1DnHGnhiqjJz6RnRw --- ToolkitComponent.SampleProject.props | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ToolkitComponent.SampleProject.props b/ToolkitComponent.SampleProject.props index 9bc7df84..3c94b2b6 100644 --- a/ToolkitComponent.SampleProject.props +++ b/ToolkitComponent.SampleProject.props @@ -11,7 +11,8 @@ - + + From 178d10f169aef70d010bdcf7824948cb24910976 Mon Sep 17 00:00:00 2001 From: Martin Zikmund Date: Tue, 27 Oct 2026 07:12:50 +0000 Subject: [PATCH 14/15] Share the gallery's Toolkit dependencies with the Uno.Sdk heads The Uno.Sdk heads referenced the published 8.2.250402 Toolkit packages, which are built against Uno 5 and fail to compile on Uno 7 (CS0012). They now use the same logic as the other heads: the local component projects when the repository provides them, packages otherwise. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01TXMNu1DnHGnhiqjJz6RnRw --- .../Uno/CommunityToolkit.App.Uno.csproj | 7 +-- .../App.Head.ToolkitDependencies.props | 56 +++++++++++++++++++ ProjectHeads/App.Head.props | 54 +----------------- .../Uno/ProjectTemplate.Uno.csproj | 7 +-- 4 files changed, 59 insertions(+), 65 deletions(-) create mode 100644 ProjectHeads/App.Head.ToolkitDependencies.props diff --git a/ProjectHeads/AllComponents/Uno/CommunityToolkit.App.Uno.csproj b/ProjectHeads/AllComponents/Uno/CommunityToolkit.App.Uno.csproj index 27259efc..c6ffb5f1 100644 --- a/ProjectHeads/AllComponents/Uno/CommunityToolkit.App.Uno.csproj +++ b/ProjectHeads/AllComponents/Uno/CommunityToolkit.App.Uno.csproj @@ -96,12 +96,7 @@ - - - - - - + diff --git a/ProjectHeads/App.Head.ToolkitDependencies.props b/ProjectHeads/App.Head.ToolkitDependencies.props new file mode 100644 index 00000000..7e6b67d2 --- /dev/null +++ b/ProjectHeads/App.Head.ToolkitDependencies.props @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ProjectHeads/App.Head.props b/ProjectHeads/App.Head.props index 3ae36d27..7a382403 100644 --- a/ProjectHeads/App.Head.props +++ b/ProjectHeads/App.Head.props @@ -29,59 +29,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + diff --git a/ProjectHeads/SingleComponent/Uno/ProjectTemplate.Uno.csproj b/ProjectHeads/SingleComponent/Uno/ProjectTemplate.Uno.csproj index cc3bc1ea..960a1251 100644 --- a/ProjectHeads/SingleComponent/Uno/ProjectTemplate.Uno.csproj +++ b/ProjectHeads/SingleComponent/Uno/ProjectTemplate.Uno.csproj @@ -89,12 +89,7 @@ - - - - - - + From 8a865b0c25fe8d4b61c6214d4e9aceadfb05f579 Mon Sep 17 00:00:00 2001 From: Martin Zikmund Date: Tue, 27 Oct 2026 07:22:08 +0000 Subject: [PATCH 15/15] Build the gallery's Toolkit dependencies from source in the Uno.Sdk CI jobs The published Converters, SettingsControls, Extensions and Triggers packages are built against Uno 5 and fail to compile in the Uno 7 heads (CS0012). Until Uno 7 builds are published, the uno-linux and new-experiment (Uno.Sdk head) jobs check those components out of CommunityToolkit/Windows at a pinned commit that ports them to Uno 7. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01TXMNu1DnHGnhiqjJz6RnRw --- .github/workflows/build.yml | 42 +++++++++++++++++++ .../workflows/config/Directory.Build.props | 8 ++++ 2 files changed, 50 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0ab31a34..574a4d59 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -20,6 +20,12 @@ env: MSBUILD_VERBOSITY: diagnostic #COREHOST_TRACE: 1 COREHOST_TRACEFILE: corehosttrace.log + # The Uno.Sdk heads depend on the Converters, SettingsControls, Extensions and Triggers components + # (and Helpers, used by Triggers). Their published packages are built against Uno 5 and don't compile + # on Uno 7 (CS0012), so the Uno.Sdk jobs build them from source at this CommunityToolkit/Windows + # commit, which ports them to Uno 7 (CommunityToolkit/Windows#880). + # TODO: Remove once Uno 7 builds of those packages are published. + TOOLKIT_COMPONENTS_REF: 6bf8e8280f5d126c043002e9af08e6a39cce72ff # A workflow run is made up of one or more jobs that can run sequentially or in parallel jobs: @@ -204,6 +210,25 @@ jobs: copy ./tooling/.config/dotnet-tools.json ./.config/dotnet-tools.json mkdir ./components + - name: Checkout Toolkit components the gallery depends on + if: ${{ matrix.unoSdkHead }} + uses: actions/checkout@v4 + with: + repository: CommunityToolkit/Windows + ref: ${{ env.TOOLKIT_COMPONENTS_REF }} + path: windows + sparse-checkout: | + components/Converters + components/Extensions + components/Helpers + components/SettingsControls + components/Triggers + + - name: Copy Toolkit components next to the experiment + if: ${{ matrix.unoSdkHead }} + shell: pwsh + run: Move-Item ./windows/components/* ./components/ + - name: Install Windows SDKs shell: pwsh run: ./tooling/Install-WindowsSdk.ps1 @@ -313,6 +338,23 @@ jobs: copy ./tooling/.config/dotnet-tools.json ./.config/dotnet-tools.json mkdir ./components + - name: Checkout Toolkit components the gallery depends on + uses: actions/checkout@v4 + with: + repository: CommunityToolkit/Windows + ref: ${{ env.TOOLKIT_COMPONENTS_REF }} + path: windows + sparse-checkout: | + components/Converters + components/Extensions + components/Helpers + components/SettingsControls + components/Triggers + + - name: Copy Toolkit components next to the experiment + shell: pwsh + run: Move-Item ./windows/components/* ./components/ + # Restore Tools from Manifest list in the Repository - name: Restore dotnet tools working-directory: ./ diff --git a/.github/workflows/config/Directory.Build.props b/.github/workflows/config/Directory.Build.props index 8d6b473b..4f29ddc9 100644 --- a/.github/workflows/config/Directory.Build.props +++ b/.github/workflows/config/Directory.Build.props @@ -3,6 +3,14 @@ $([MSBuild]::EnsureTrailingSlash('$(MSBuildThisFileDirectory)')) $(RepositoryDirectory)tooling + + $(RepositoryDirectory)components\Converters\src\CommunityToolkit.WinUI.Converters.csproj + $(RepositoryDirectory)components\Extensions\src\CommunityToolkit.WinUI.Extensions.csproj + $(RepositoryDirectory)components\Triggers\src\CommunityToolkit.WinUI.Triggers.csproj + $(RepositoryDirectory)components\Helpers\src\CommunityToolkit.WinUI.Helpers.csproj + $(RepositoryDirectory)components\SettingsControls\src\CommunityToolkit.WinUI.Controls.SettingsControls.csproj + 1 0