Add Avalonia.Controls.Maui support to templates - #35950
Conversation
|
Hey there @@drasticactions! Thank you so much for your PR! Someone from the team will get assigned to your PR shortly and we'll get it reviewed. |
|
Hey there @drasticactions! Thank you so much for your PR! Someone from the team will get assigned to your PR shortly and we'll get it reviewed. |
|
🚀 Dogfood this PR with:
curl -fsSL https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.sh | bash -s -- 35950Or
iex "& { $(irm https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.ps1) } 35950" |
kubaflo
left a comment
There was a problem hiding this comment.
PR #35950 — Add Avalonia.Controls.Maui support to templates
Verdict: NEEDS_CHANGES (confidence: high). Nice addition — the new --with-avalonia option is structurally well-wired through template.json symbols, dotnetcli.host.json, the csproj (desktop head + Avalonia.Controls.Maui package refs), and there's an integration test. But the generated project doesn't compile in the Avalonia-on case.
Blocking (inline)
- ❌
MauiProgram.cs:27—UseAvaloniaEmbedding<AvaloniaApp>()references an undefinedAvaloniaApp. On the mobile heads the embedding path needs an AvaloniaApplicationtype that the template never generates, so--with-avaloniaproduces a project that fails to build (CS0246). Generate theAvaloniaApptype as template content (or target an existing type). (3 models + code-confirmed.)
Suggestions (not blocking)
- Integration test coverage (
SimpleTemplateTest.cs):WithAvaloniaAddsHandlersAndDesktopHeadcurrently mostly asserts generated content rather than building the Avalonia-on project. A build assertion would have caught theAvaloniaAppissue above — consider compiling the generated project with the option enabled. (gemini) template.jsonversion default (~line 202): the11.0.0-preview.*floating range is reasonable for a preview-stage integration but pins consumers to whatever floats at restore time; consider a fixed version or document the intent. (opus-4.6)template.json:199parameterdataType— minor convention nit per gemini; worth a glance.
CI
Check Build/*Templates* integration legs once the AvaloniaApp issue is fixed — the template-generation tests are the relevant signal here.
Solid groundwork; the one real blocker is the missing AvaloniaApp in the generated output. Happy to re-review.
Re-review PR #35950 — Add Avalonia.Controls.Maui to templates (new head
|
|
With the pinning of versions, I'm fine with it. I'm not sure what's the right way for us to handling bumping the templates for new versions and what the other dependencies do. I'm open to discussions on that. |
Redth
left a comment
There was a problem hiding this comment.
Local validation on macOS — all four heads build and run ✅
I generated the template out of this branch and exercised it end-to-end rather than just eyeballing the diff. Emulated the pack-time token substitution (DOTNET_TFM_VALUE etc.) into a temp copy of maui-mobile, dotnet new install'd it, generated all three variants, then restored / built / deployed.
Environment: SDK 11.0.100-preview.6.26359.118, maui workload 11.0.0-preview.6.26360.8. Avalonia.Controls.Maui resolved to 11.0.0-preview.6.26198.1455.
| Check | Result |
|---|---|
Generation: --with-avalonia, plain, --with-avalonia --sample-content |
✅ all correct |
Gating — --sample-content suppresses all Avalonia content |
✅ |
| Restore (4 TFMs) | ✅ correct lib folders: net11.0, -android37.0, -ios26.5, -maccatalyst26.5 |
Debug build: net11.0 / -android / -ios / -maccatalyst |
✅ |
Release + TrimMode=partial + -warnaserror |
✅ 0 warnings, all 4 |
Full multi-TFM dotnet build (what the CI Build theory does) |
✅ |
| Runtime | ✅ desktop head renders MAUI through Avalonia; iOS sim, Android emulator, and MacCatalyst all launch and render |
--avaloniaControlsMauiVersion override |
✅ works, correctly hidden from CLI help |
| Default create (with restore post-action) | ✅ |
I also confirmed the AvaloniaControlsMauiGenerateBootstrap commit is genuinely needed, not just belt-and-braces: the Core package's props only auto-sets it when UseMaui == true, and NuGet props are imported before the project body sets that. Removing the explicit property fails the platform heads with CS0246: The type or namespace name 'AvaloniaApp' could not be found. Good catch.
So the functional core of this is solid. Comments below are about plumbing and long-term maintenance rather than correctness.
Not tied to a specific line
Component governance. eng/scripts/update-cgmanifest.ps1 drives src/Templates/src/cgmanifest.json from a hardcoded $packageMap. Avalonia.Controls.Maui and Avalonia.Controls.Maui.Desktop aren't in it, so they won't be registered. Every other third-party package referenced by these templates (CommunityToolkit.Maui, CommunityToolkit.Mvvm, Syncfusion.Maui.Toolkit, Microsoft.Data.Sqlite.Core, SQLitePCLRaw.bundle_green) is. These need adding before this ships.
Description drift. template.json says "embedding Avalonia on mobile and Windows"; templatestrings.en.json says "embedding Avalonia on the mobile and Windows heads". The loc file wins at runtime — worth syncing so the strings don't diverge further.
Missing loc entry. symbols/avaloniaControlsMauiVersion/description isn't in templatestrings.en.json, unlike every other symbol. Low impact since it's isHidden for the CLI, but other hosts may surface it unlocalized.
VS wizard UX. WithAvalonia has a displayName, so it renders as a checkbox in the VS project wizard alongside "Include sample content". Checking both silently produces a project with no Avalonia in it. Either make it CLI-only or find a way to surface the conflict.
dotnet run needs -f. The generated project has 4-5 TFMs, so plain dotnet run fails with "Your project targets multiple frameworks". The Avalonia README's "run with dotnet run" story doesn't hold out of the box, and launchSettings.json only has a "Windows Machine" profile. Pre-existing MAUI behaviour so not a blocker, but a desktop profile would make the new head much more discoverable.
Untested: the Windows head — I'm on macOS. On Windows the project ends up with both net11.0 and net11.0-windows10.0.19041.0; worth someone running it there before merge.
Product question: this puts a third-party preview dependency into the first-party dotnet new maui template. Assuming that's already agreed, but flagging in case it needs explicit sign-off.
There was a problem hiding this comment.
Pull request overview
Adds an opt-in --with-avalonia switch to the maui-mobile (maui) template to wire up Avalonia.Controls.Maui, including a non-platform DOTNET_TFM desktop head and corresponding app-builder configuration. Also updates template packaging/version substitution and adds integration-test coverage to validate the template output.
Changes:
- Add
--with-avalonia(gated off when--sample-contentis used) and update the generatedMauiProgramto use Avalonia app/embedding setup. - Extend the template project to add a
DOTNET_TFMdesktop target and Avalonia package references (with template-replaced version token). - Add integration tests for
--with-avalonia, plus introduce Avalonia package version plumbing and cgmanifest version mapping.
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| src/TestUtils/src/Microsoft.Maui.IntegrationTests/SimpleTemplateTest.cs | Adds build matrix entries and new assertions validating Avalonia template output + gating behavior. |
| src/Templates/src/templates/maui-mobile/MauiProgram.cs | Conditionally alters CreateMauiApp signature and wires Avalonia app/embedding calls when enabled. |
| src/Templates/src/templates/maui-mobile/MauiApp.1.csproj | Adds DOTNET_TFM desktop head, bootstrap property, and Avalonia package references behind a computed template symbol. |
| src/Templates/src/templates/maui-mobile/.template.config/template.json | Defines WithAvalonia, computed UseAvaloniaHandlers, and version token replacement symbol. |
| src/Templates/src/templates/maui-mobile/.template.config/localize/templatestrings.en.json | Adds localized strings for the new template option and version override. |
| src/Templates/src/templates/maui-mobile/.template.config/ide.host.json | Hides the Avalonia-related symbols from IDE host UI. |
| src/Templates/src/templates/maui-mobile/.template.config/dotnetcli.host.json | Maps WithAvalonia to --with-avalonia and hides the version override symbol. |
| src/Templates/src/Microsoft.Maui.Templates.csproj | Adds template-time replacement plumbing for AVALONIA_CONTROLS_MAUI_VERSION_VALUE. |
| src/Templates/src/cgmanifest.json | Adds Avalonia package registrations (noted issue: file is generator-owned). |
| eng/Versions.props | Introduces AvaloniaControlsMauiPackageVersion for consistent versioning. |
| eng/scripts/update-cgmanifest.ps1 | Maps Avalonia packages to the new version property for cgmanifest generation. |
The Avalonia registrations are produced automatically by eng/scripts/update-cgmanifest.ps1 from the AvaloniaControlsMauiPackageVersion property in eng/Versions.props, both of which this PR already adds. eng/CgManifest.targets is imported by Microsoft.Maui.Templates.csproj and its UpdateCgManifest target runs BeforeTargets="BeforeBuild" (enabled by default), so src/Templates/src/cgmanifest.json is rewritten on every build of the templates project. Component Governance only needs the manifest present on disk at build time, which that regeneration guarantees, and the file is not packed into the nupkg (no pipeline sets GenerateCgManifest=true). Committing a hand-edited copy therefore adds diff noise that is overwritten on the next build, so drop it and keep only the generator inputs. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 53749cde-edca-4995-aac1-33d30bc2d2fc
|
Follow-up: all of my review threads are now resolved, and I am withdrawing the two remaining loose ends from my original review body.
The only caveat left is that I validated from a macOS host, so the For the record, my final re-validation ran against the actual packed template rather than a hand-emulated substitution:
(One unrelated snag worth knowing about if you hit it locally: Nice work — this looks good to me from a template-mechanics standpoint. |
(I know it says "MAKE SURE THIS PR IS TARGETING MAIN" but since these packages only run in net11.0, I think it's right to target it there, since it shouldn't be in net10 builds, but we can always retarget it)
Description of Change
This PR adds the command
--with-avaloniato the templates, which addsAvalonia.Controls.Mauidesktop support the generated MAUI app.app.mp4
This updates the basic template so it
Avalonia.Controls.MauiandAvalonia.Controls.Maui.Desktopnugetsnet11.0TFM as a deployable platform.useSingleAppLifetimeis a parameter value that would get passed in from the Avalonia builder for which lifetime to use.UseAvaloniaAppis where the Avalonia handlers are registered. It's if-defed out for the existing MAUI platforms so they render with native controls by default, since we're still working in this repo to enable running these handlers on those platforms.UseAvaloniaEmbeddingis enabled for those platforms to allow for "Embedded" Avalonia Maui controls and handlers, which is our existing Avalonia Maui Hybrid platform and lets you intergrate native and drawn controls together, with the native controls being the default.This is our first run of getting a template change in, so we're keeping it simple.
maui-mobiletemplate for Desktop support. It doesn't changemaui-blazor, which we don't support. I can addmaui-multiplatformsupport if we want now, or that can be another PR, I don't have a preference.11.0.0-...) but, of course, we can't align onMauiVersion. I can pin to a version if that's best.