Skip to content

Fix MauiXaml will generate source for every xaml file without respect to its condition by configuration/target - #37176

Merged
kubaflo merged 3 commits into
dotnet:inflight/currentfrom
KarthikRajaKalaimani:fix-36951-2
Aug 15, 2026
Merged

kubaflo merged 3 commits into
dotnet:inflight/currentfrom
KarthikRajaKalaimani:fix-36951-2

Conversation

@KarthikRajaKalaimani

Copy link
Copy Markdown
Contributor

Note

Are you waiting for the changes in this PR to be merged?
It would be very helpful if you could test the resulting artifacts from this PR and let us know in a comment if this change resolves your issue. Thank you!

Issue Details

MauiXaml will generate source for every xaml file without respect to its condition by configuration/target

Root Cause

• Microsoft.Maui.Controls.Globs.props globs ***.xaml into the MauiXaml item group unconditionally for every inner build/TFM.
• Microsoft.Maui.Controls.SingleProject.targets correctly gates Compile ( .cs ) items under Platforms// via %(Compile.ExcludeFromCurrentConfiguration) , but its XAML-removal logic only ever stripped Windows .xaml (WinUI markup) out of MauiXaml . It never removed non-active-platform .xaml under Platforms/Android , Platforms/iOS , Platforms/MacCatalyst , or Platforms/Tizen .
• Consequence: the XAML SourceGen consumes MauiXaml as AdditionalFiles regardless of platform, so every platform's xaml leaked into every inner build — producing duplicate InitializeComponent /attribute/field declarations whenever multiple platforms reused the same class name (a standard, supported pattern).

Description of Change

src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.SingleProject.targets (shipped via buildTransitive in Microsoft.Maui.Controls.Build.Tasks → applies to every MAUI app)

Extended the _MauiRemovePlatformCompileItems target's _MauiXamlToRemove computation (previously Windows-only) to also cover Android/iOS/MacCatalyst/Tizen: for each built-in platform folder, its .xaml files are queued for removal from MauiXaml / EmbeddedResource unless it matches the currently active $(TargetPlatformIdentifier) . The pre-existing unconditional Windows-folder removal (WinUI markup, not MAUI XAML) is left unchanged.

Issues Fixed

Fixes #36951

Tested the behavior in the following platforms.

  • Android
  • Windows
  • iOS
  • Mac
Before After
image

@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.sh | bash -s -- 37176

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.ps1) } 37176"

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).
There may be pipelines that require an authorized user to comment /azp run to run.

@dotnet-policy-service dotnet-policy-service Bot added the community ✨ Community Contribution label Aug 7, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Hey there @@KarthikRajaKalaimani! Thank you so much for your PR! Someone from the team will get assigned to your PR shortly and we'll get it reviewed.

@vishnumenon2684

Copy link
Copy Markdown
Contributor

/azp run maui-pr-uitests , maui-pr-devicetests

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 2 pipeline(s).

@sheiksyedm
sheiksyedm marked this pull request as ready for review August 7, 2026 11:21
Copilot AI lite review requested due to automatic review settings August 7, 2026 11:21
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).
There may be pipelines that require an authorized user to comment /azp run to run.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes a .NET MAUI Single Project MSBuild issue where MauiXaml default globs (**/*.xaml) cause XAML source generation to see platform-specific XAML from all Platforms/<Platform> folders in every inner build, leading to duplicate generated members when the same x:Class is used per platform. The change updates the SingleProject filtering target to remove non-active-platform XAML from MauiXaml (and corresponding EmbeddedResource) based on $(TargetPlatformIdentifier), and adds MSBuild-based regression tests to validate the behavior.

Changes:

  • Extend _MauiRemovePlatformCompileItems to also remove non-active-platform XAML under Platforms/Android, Platforms/iOS, Platforms/MacCatalyst, and Platforms/Tizen from MauiXaml.
  • Add an MSBuild regression test that asserts only the active platform’s Platforms/<Platform>/*.xaml remains in @(MauiXaml) (plus shared XAML), and that Platforms/Windows/*.xaml is always removed.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.SingleProject.targets Remove non-active platform Platforms/<Platform>/*.xaml from MauiXaml based on $(TargetPlatformIdentifier) to prevent cross-platform sourcegen duplicates.
src/Controls/tests/Xaml.UnitTests/MSBuild/MSBuildTests.cs Add MSBuild regression tests that log and assert the post-filter @(MauiXaml) identities (active platform retained; Windows always removed).
Suppressed comments (1)

src/Controls/tests/Xaml.UnitTests/MSBuild/MSBuildTests.cs:699

  • To make the added Tizen InlineData meaningful, include the Tizen folder in the platformFolders array so the test creates a Platforms/Tizen/TestPage.xaml variant to validate retain/remove behavior.
			var platformFolders = new[] { "Android", "iOS", "MacCatalyst" };

Comment thread src/Controls/tests/Xaml.UnitTests/MSBuild/MSBuildTests.cs Outdated
@kubaflo

This comment has been minimized.

@github-actions github-actions Bot added the s/agent-review-in-progress AI review is currently running for this PR label Aug 7, 2026
@MauiBot MauiBot added s/agent-changes-requested AI agent recommends changes - found a better alternative or issues s/agent-gate-failed AI could not verify tests catch the bug s/agent-fix-pr-picked AI could not beat the PR fix - PR is the best among all candidates s/agent-reviewed PR was reviewed by AI agent workflow (full 4-phase review) labels Aug 7, 2026

@MauiBot MauiBot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Expert Review — 5 findings

See inline comments for details.

Comment thread src/Controls/tests/Xaml.UnitTests/MSBuild/MSBuildTests.cs Outdated
Comment thread src/Controls/tests/Xaml.UnitTests/MSBuild/MSBuildTests.cs Outdated
Comment thread src/Controls/tests/Xaml.UnitTests/MSBuild/MSBuildTests.cs Outdated
Comment thread src/Controls/tests/Xaml.UnitTests/MSBuild/MSBuildTests.cs
https://github.com/dotnet/maui/issues/36951.
-->
<_MauiXamlToRemove
Condition="'$(AndroidProjectFolder)' != '' and '$(TargetPlatformIdentifier)' != 'android'"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔍 AI-Generated Review (multi-model)

[minor] Complexity Reduction — The '$(AndroidProjectFolder)' != '' guard (and its iOS/MacCatalyst/Tizen siblings on lines 72, 75, 78) can never be false. Microsoft.Maui.Controls.SingleProject.Before.targets lines 11-28 unconditionally default every *ProjectFolder property and then run $([MSBuild]::EnsureTrailingSlash(...)) over it, so all five are guaranteed non-empty by the time this target evaluates. The guard mirrors the pre-existing Windows line so it is not a bug, but it reads as a meaningful precondition when it is dead.

Separately, Before.targets line 32 already defines a MauiPlatformSpecificFolder item carrying TargetPlatformIdentifier metadata per folder. Driving these four near-identical blocks off that item (e.g. a single _MauiXamlToRemove Include="%(MauiPlatformSpecificFolder.Identity)**/*.xaml" Condition="'%(MauiPlatformSpecificFolder.TargetPlatformIdentifier)' != '$(TargetPlatformIdentifier)'") would collapse them into one rule and mean a future platform folder does not need a fifth hand-written copy. Non-blocking.

MauiBot

This comment was marked as outdated.

@MauiBot MauiBot removed the s/agent-review-in-progress AI review is currently running for this PR label Aug 7, 2026

@kubaflo kubaflo left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please check the ai's suggestions?

@vishnumenon2684 vishnumenon2684 added the do-not-merge Don't merge this PR label Aug 13, 2026
Copilot AI review requested due to automatic review settings August 13, 2026 13:45

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

Suppressed comments (2)

src/Controls/tests/Xaml.UnitTests/MSBuild/MSBuildTests.cs:684

  • BuildMauiXamlFilterProject() calls SetUp() without passing a test name, so the temp directory is based on the helper method name rather than the calling test. This makes all callers (and all Theory iterations) share the same temp/obj directories, which can cause state bleed and makes failures harder to diagnose.
		string BuildMauiXamlFilterProject(string targetPlatformIdentifier, string[] platformFolders)
		{
			SetUp();

src/Controls/tests/Xaml.UnitTests/MSBuild/MSBuildTests.cs:51

  • The comment about sharing the same x:Class across all Platforms/ variants appears unrelated to the Xaml.CustomView constant (which is only used for CustomView.xaml in this test file). As written it’s likely to mislead future readers about what this constant is validating.

			// Deliberately shares the same x:Class across all Platforms/<Platform> variants, to
			// mirror the common per-platform partial-page pattern from https://github.com/dotnet/maui/issues/36951.
			}

@vishnumenon2684

Copy link
Copy Markdown
Contributor

/azp run maui-pr-uitests , maui-pr-devicetests

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 2 pipeline(s).

@KarthikRajaKalaimani

Copy link
Copy Markdown
Contributor Author

AI Review Summary

@KarthikRajaKalaimani — new AI review results are available based on this last commit: 5fa9c6f.

Gate Inconclusive Confidence High Platform Android

🗂️ Review Sessions — click to expand

🚦 Gate — Test Before & After Fix

Gate Result: ⚠️ INCONCLUSIVE

Platform: ANDROID · Base: main · Merge base: f27ca83a

🧰 Platform workload unavailable on this gate host — inconclusive — every remaining failed test case stopped with NETSDK1178 because it targets an SDK pack this operating system cannot provide (for example, iOS/MacCatalyst cases on the Linux Android gate). Those cases never executed their assertions, so this is not a fix failure. Re-running on the same host cannot help; verify the affected cases on a compatible platform agent.

Test Without Fix (expect FAIL) With Fix (expect PASS)
📄 MSBuildTests MSBuildTests ✅ FAIL — 223s ⚠️ ENV ERROR
🔴 Without fix — 📄 MSBuildTests: FAIL ✅ · 223s
Error-relevant lines (filtered from the build log):

          /home/vsts/work/1/s/artifacts/bin/Controls.Xaml.UnitTests/Debug/net10.0/temp/SingleProject_RemovePlatformCompileItems_RemovesNonActivePlatformMauiXamlItems/obj/Debug/net10.0/Microsoft.Maui.Controls.SourceGen/Microsoft.Maui.Controls.SourceGen.XamlGenerator/Platforms_MacCatalyst_TestPage.xaml.sg.cs(21,74): error CS0229: Ambiguity between 'TestPage.label0' and 'TestPage.label0' [/home/vsts/work/1/s/artifacts/bin/Controls.Xaml.UnitTests/Debug/net10.0/temp/SingleProject_RemovePlatformCompileItems_RemovesNonActivePlatformMauiXamlItems/test.csproj]
[xUnit.net 00:00:32.33]              1>/home/vsts/work/1/s/.dotnet/sdk/10.0.100/Sdks/Microsoft.NET.Sdk/targets/Microsoft.NET.Sdk.ImportWorkloads.targets(38,5): error NETSDK1178: The project depends on the following workload packs that do not exist in any of the workloads available in this installation: Microsoft.MacCatalyst.Sdk.net10.0_26.0 [/home/vsts/work/1/s/artifacts/bin/Controls.Xaml.UnitTests/Debug/net10.0/temp/SingleProject_RemovePlatformCompileItems_RemovesNonActivePlatformMauiXamlItems/test.csproj]
[xUnit.net 00:00:32.33]         /home/vsts/work/1/s/.dotnet/sdk/10.0.100/Sdks/Microsoft.NET.Sdk/targets/Microsoft.NET.Sdk.ImportWorkloads.targets(38,5): error NETSDK1178: You may need to build the project on another operating system or architecture, or update the .NET SDK. [/home/vsts/work/1/s/artifacts/bin/Controls.Xaml.UnitTests/Debug/net10.0/temp/SingleProject_RemovePlatformCompileItems_RemovesNonActivePlatformMauiXamlItems/test.csproj]
[xUnit.net 00:00:32.33]         Build FAILED.
[xUnit.net 00:00:32.33]                  /home/vsts/work/1/s/.dotnet/sdk/10.0.100/Sdks/Microsoft.NET.Sdk/targets/Microsoft.NET.Sdk.ImportWorkloads.targets(38,5): error NETSDK1178: The project depends on the following workload packs that do not exist in any of the workloads available in this installation: Microsoft.MacCatalyst.Sdk.net10.0_26.0 [/home/vsts/work/1/s/artifacts/bin/Controls.Xaml.UnitTests/Debug/net10.0/temp/SingleProject_RemovePlatformCompileItems_RemovesNonActivePlatformMauiXamlItems/test.csproj]
[xUnit.net 00:00:32.33]                /home/vsts/work/1/s/.dotnet/sdk/10.0.100/Sdks/Microsoft.NET.Sdk/targets/Microsoft.NET.Sdk.ImportWorkloads.targets(38,5): error NETSDK1178: You may need to build the project on another operating system or architecture, or update the .NET SDK. [/home/vsts/work/1/s/artifacts/bin/Controls.Xaml.UnitTests/Debug/net10.0/temp/SingleProject_RemovePlatformCompileItems_RemovesNonActivePlatformMauiXamlItems/test.csproj]
      1>/home/vsts/work/1/s/.dotnet/sdk/10.0.100/Sdks/Microsoft.NET.Sdk/targets/Microsoft.NET.Sdk.ImportWorkloads.targets(38,5): error NETSDK1178: The project depends on the following workload packs that do not exist in any of the workloads available in this installation: Microsoft.MacCatalyst.Sdk.net10.0_26.0 [/home/vsts/work/1/s/artifacts/bin/Controls.Xaml.UnitTests/Debug/net10.0/temp/SingleProject_RemovePlatformCompileItems_RemovesNonActivePlatformMauiXamlItems/test.csproj]
          /home/vsts/work/1/s/.dotnet/sdk/10.0.100/Sdks/Microsoft.NET.Sdk/targets/Microsoft.NET.Sdk.ImportWorkloads.targets(38,5): error NETSDK1178: The project depends on the following workload packs that do not exist in any of the workloads available in this installation: Microsoft.MacCatalyst.Sdk.net10.0_26.0 [/home/vsts/work/1/s/artifacts/bin/Controls.Xaml.UnitTests/Debug/net10.0/temp/SingleProject_RemovePlatformCompileItems_RemovesNonActivePlatformMauiXamlItems/test.csproj]

🟢 With fix — 📄 MSBuildTests: ⚠️ ENV ERROR · 83s
Error-relevant lines (filtered from the build log):

 Build FAILED.
          /home/vsts/work/1/s/.dotnet/sdk/10.0.100/Sdks/Microsoft.NET.Sdk/targets/Microsoft.NET.Sdk.ImportWorkloads.targets(38,5): error NETSDK1178: The project depends on the following workload packs that do not exist in any of the workloads available in this installation: Microsoft.iOS.Sdk.net10.0_26.0 [/home/vsts/work/1/s/artifacts/bin/Controls.Xaml.UnitTests/Debug/net10.0/temp/SingleProject_RemovePlatformCompileItems_RemovesNonActivePlatformMauiXamlItems/test.csproj]
[xUnit.net 00:00:22.52]              1>/home/vsts/work/1/s/.dotnet/sdk/10.0.100/Sdks/Microsoft.NET.Sdk/targets/Microsoft.NET.Sdk.ImportWorkloads.targets(38,5): error NETSDK1178: The project depends on the following workload packs that do not exist in any of the workloads available in this installation: Microsoft.MacCatalyst.Sdk.net10.0_26.0 [/home/vsts/work/1/s/artifacts/bin/Controls.Xaml.UnitTests/Debug/net10.0/temp/SingleProject_RemovePlatformCompileItems_RemovesNonActivePlatformMauiXamlItems/test.csproj]
[xUnit.net 00:00:22.52]         /home/vsts/work/1/s/.dotnet/sdk/10.0.100/Sdks/Microsoft.NET.Sdk/targets/Microsoft.NET.Sdk.ImportWorkloads.targets(38,5): error NETSDK1178: You may need to build the project on another operating system or architecture, or update the .NET SDK. [/home/vsts/work/1/s/artifacts/bin/Controls.Xaml.UnitTests/Debug/net10.0/temp/SingleProject_RemovePlatformCompileItems_RemovesNonActivePlatformMauiXamlItems/test.csproj]
[xUnit.net 00:00:22.52]         Build FAILED.
[xUnit.net 00:00:22.52]                  /home/vsts/work/1/s/.dotnet/sdk/10.0.100/Sdks/Microsoft.NET.Sdk/targets/Microsoft.NET.Sdk.ImportWorkloads.targets(38,5): error NETSDK1178: The project depends on the following workload packs that do not exist in any of the workloads available in this installation: Microsoft.MacCatalyst.Sdk.net10.0_26.0 [/home/vsts/work/1/s/artifacts/bin/Controls.Xaml.UnitTests/Debug/net10.0/temp/SingleProject_RemovePlatformCompileItems_RemovesNonActivePlatformMauiXamlItems/test.csproj]
[xUnit.net 00:00:22.52]                /home/vsts/work/1/s/.dotnet/sdk/10.0.100/Sdks/Microsoft.NET.Sdk/targets/Microsoft.NET.Sdk.ImportWorkloads.targets(38,5): error NETSDK1178: You may need to build the project on another operating system or architecture, or update the .NET SDK. [/home/vsts/work/1/s/artifacts/bin/Controls.Xaml.UnitTests/Debug/net10.0/temp/SingleProject_RemovePlatformCompileItems_RemovesNonActivePlatformMauiXamlItems/test.csproj]
   at InvokeStub_MSBuildTests.SingleProject_RemovePlatformCompileItems_RemovesNonActivePlatformMauiXamlItems(Object, Span`1)
   at System.Reflection.MethodBaseInvoker.InvokeWithFewArgs(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
      1>/home/vsts/work/1/s/.dotnet/sdk/10.0.100/Sdks/Microsoft.NET.Sdk/targets/Microsoft.NET.Sdk.ImportWorkloads.targets(38,5): error NETSDK1178: The project depends on the following workload packs that do not exist in any of the workloads available in this installation: Microsoft.MacCatalyst.Sdk.net10.0_26.0 [/home/vsts/work/1/s/artifacts/bin/Controls.Xaml.UnitTests/Debug/net10.0/temp/SingleProject_RemovePlatformCompileItems_RemovesNonActivePlatformMauiXamlItems/test.csproj]
          /home/vsts/work/1/s/.dotnet/sdk/10.0.100/Sdks/Microsoft.NET.Sdk/targets/Microsoft.NET.Sdk.ImportWorkloads.targets(38,5): error NETSDK1178: The project depends on the following workload packs that do not exist in any of the workloads available in this installation: Microsoft.MacCatalyst.Sdk.net10.0_26.0 [/home/vsts/work/1/s/artifacts/bin/Controls.Xaml.UnitTests/Debug/net10.0/temp/SingleProject_RemovePlatformCompileItems_RemovesNonActivePlatformMauiXamlItems/test.csproj]

⚠️ Failure Details

  • ⚠️ MSBuildTests with fix: Gate host limitation: all 2 failing test case(s) require .NET workload SDK packs unavailable on this operating system (unavailable: Microsoft.iOS.Sdk.net10.0_26.0, Microsoft.MacCatalyst.Sdk.net10.0_26.0) (NETSDK1178). Those cases could not execute, so the fix is unverifiable here; run them on a compatible host.

📁 Fix files reverted (1 files)

  • src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.SingleProject.targets

📋 Pre-Flight — Context & Validation

PR #37176 Pre-Flight

Context

Issue #36951 reports that XAML SourceGen processes MauiXaml items which should be excluded for the active configuration or target. A common reproduction places XAML files with the same x:Class under multiple Platforms/<Platform> folders. Non-active files remain in SourceGen's AdditionalFiles, producing duplicate attributes, fields, and InitializeComponent methods (CS0579, CS0111, and related ambiguity errors).

Existing PR Approach

The PR changes:

  1. src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.SingleProject.targets
  2. src/Controls/tests/Xaml.UnitTests/MSBuild/MSBuildTests.cs

The production change extends _MauiRemovePlatformCompileItems. It builds _MauiXamlToRemove from the Android, iOS, MacCatalyst, and Tizen project-folder globs whenever each folder is not the active $(TargetPlatformIdentifier), then removes those items from both EmbeddedResource and MauiXaml. Existing unconditional removal of Windows XAML remains unchanged.

The test change creates same-x:Class XAML files in Android, iOS, and MacCatalyst folders, plus shared XAML, and asserts only the active platform item and shared item survive. A separate Windows regression test asserts WinUI XAML remains absent from MauiXaml.

Relevant Existing Infrastructure

Microsoft.Maui.Controls.SingleProject.Before.targets already creates @(MauiPlatformSpecificFolder) entries with Include equal to each platform folder and TargetPlatformIdentifier metadata. This may support an alternative data-driven implementation rather than one condition per platform. Any candidate must also account for the issue's broader claim about conditionally excluded MauiXaml outside standard platform folders; the PR's current fix only addresses built-in platform folders.

Test Contract

Use only this targeted unit-test invocation; do not run the gate or a full suite:

dotnet test src/Controls/tests/Xaml.UnitTests/Controls.Xaml.UnitTests.csproj --filter "FullyQualifiedName~MSBuildTests.SingleProject_RemovePlatformCompileItems_RemovesNonActivePlatformMauiXamlItems|FullyQualifiedName~MSBuildTests.SingleProject_RemovePlatformCompileItems_AlwaysRemovesWindowsMauiXamlItems"

Both named tests are mandatory for each candidate. One implementation/test pass and at most one focused correction/retest are allowed.

Gate Evidence

The prior gate is INCONCLUSIVE, not a fix failure. Without the production fix, the regression test reached duplicate generated members, including ambiguity between duplicate TestPage.label0 fields. With the fix, remaining iOS and MacCatalyst cases stopped before assertions with NETSDK1178 because this Linux/Android host lacks Microsoft.iOS.Sdk.net10.0_26.0 and Microsoft.MacCatalyst.Sdk.net10.0_26.0. Do not rerun gate verification and do not modify gate/content.md.

Working-Tree Safety

The worktree contains many pre-existing modifications under .github/ and eng/ unrelated to PR #37176. Candidates must preserve them, use EstablishBrokenBaseline.ps1 exactly as required by the try-fix skill, and limit candidate changes to the PR problem.

🔬 Code Review — Deep Analysis

Expert Code Review — dotnet/maui PR #37176

Title: Fix MauiXaml will generate source for every xaml file without respect to its condition by configuration/target Issue: #36951 Reviewed commit: 3eb73f87e2 (raw submitted PR HEAD, /home/vsts/work/1/s) Scope: submitted PR HEAD only — no try-fix / pr-plus-reviewer candidate was reviewed. Actions taken: read-only. Nothing posted to GitHub; no source or worktree modified.

1. Independent Assessment (code before narrative)

Diff surface is small — 2 files, +222/-0:

File Change
src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.SingleProject.targets +23: four new _MauiXamlToRemove includes inside _MauiRemovePlatformCompileItems
src/Controls/tests/Xaml.UnitTests/MSBuild/MSBuildTests.cs +199: a WriteFile helper, two XAML fixtures, one 3-case [Theory], one [Fact]

What the production change does

Inside the existing _MauiRemovePlatformCompileItems target (condition: EnableDefaultItems == true and SingleProject == true), it adds four globs to the pre-existing _MauiXamlToRemove item, one per platform folder (Android, iOS, MacCatalyst, Tizen), each gated on '$(<X>ProjectFolder)' != '' and '$(TargetPlatformIdentifier)' != '<x>'. Those items were already fed into EmbeddedResource Remove and MauiXaml Remove. The pre-existing unconditional $(WindowsProjectFolder) removal is untouched.

Verified supporting facts

  • AndroidProjectFolder / iOSProjectFolder / MacCatalystProjectFolder / WindowsProjectFolder / TizenProjectFolder are always defaulted in Microsoft.Maui.Controls.SingleProject.Before.targets (lines 5-28), so the != '' guards are effectively always true — they are dead guards, not a real safety net, but harmless.
  • MSBuild ==/!= string comparison is case-insensitive, so lowercase 'android'/'ios'/... matches the SDK-computed identity, consistent with the existing Compile conditions in the same file.
  • The .xaml.cs code-behind of a non-active platform is already excluded from Compile by the block at lines 5-52, so removing the matching .xaml restores symmetry rather than creating an orphan-partial hazard.
  • Empty TargetPlatformIdentifier (platform-neutral inner build) removes all platform XAML — matches the Compile behaviour, correct.
  • EmbeddedResource Remove widening is intentional and safe: only non-active-platform files are affected.

Verdict on the core idea

The direction is right and the abstraction layer is right (single-project targets, not SourceGen). The defect is real, the diagnosis in the comment (MauiXaml has no ExcludeFromCurrentConfiguration gating) is factually accurate, and the change is well-commented with the issue link. The problem is that the implementation shape diverges from the adjacent Compile logic in a way that is both incomplete and, in one configuration, actively harmful.

2. Findings

All four are written to PRAgent/inline-findings.json with exact path/line/side=RIGHT.

F1 — [major] Hard-coded platform enumeration: over-removes on shared folders, under-removes on custom folders

Microsoft.Maui.Controls.SingleProject.targets:69

The adjacent Compile logic is last-write-wins metadata: stamp ExcludeFromCurrentConfiguration=true on all of Platforms/**, then stamp false on the active folder. The new XAML logic is additive removal. Two consequences:

  1. Over-blocking (regression risk). The *ProjectFolder properties are user-overridable (Before.targets defaults them only Condition=" '$(X)' == '' "). A project that points MacCatalyst at the iOS folder (<MacCatalystProjectFolder>Platforms\iOS\</MacCatalystProjectFolder> — a documented, supported redirect and a real sharing pattern) and builds maccatalyst satisfies the iOS rule (!= 'ios' is true), so the active platform's XAML is added to _MauiXamlToRemove and stripped. There is no re-add step in an additive-removal design. The Compile block is immune to this because the MacCatalyst Update runs last and wins. Failure mode is silent: the page loses generated InitializeComponent and fails to compile or renders empty.
  2. Under-blocking (fix is incomplete). Compile excludes $(PlatformsProjectFolder)** wholesale, so .cs under a non-standard folder such as Platforms/Shared/ is excluded from every inner build, while its .xaml is not in any of the four new globs and still reaches SourceGen AdditionalFiles. The CS0579/CS0111 duplication from MauiXaml will generate source for every xaml file without respect it's condition by configuration/target #36951 therefore still reproduces there.

Recommended correction (single edit, fixes both): catch-all include $(PlatformsProjectFolder)**/*.xaml with Exclude of the active folder resolved from the existing @(MauiPlatformSpecificFolder) mapping (Before.targets:31-37), keeping Windows unconditional. Full snippet is in the inline finding.

F2 — [major] iOS/MacCatalyst theory cases require the real Apple SDK packs, contradicting their own comment

MSBuildTests.cs:669

// Fake the active platform without requiring the real platform TFM/workload to be installed. is wrong. Setting TargetPlatformIdentifier as a project property is sufficient for the SDK's ProcessFrameworkReferences/restore to demand the matching workload pack. Build(projectFile) defaults to shouldSucceed: true and asserts ExitCode == 0, so the ios and maccatalyst cases abort with NETSDK1178 (Microsoft.iOS.Sdk.net10.0_26.0, Microsoft.MacCatalyst.Sdk.net10.0_26.0) before reaching a single assertion on any host lacking those packs. This was reproduced twice independently in this PR's own pipeline (gate verification and try-fix candidate 1). dotnet build -t: still restores, so a target filter alone does not avoid it. Net effect: 1 of 3 theory cases is genuinely green, the rest are environment-dependent CI failures.

Recommended correction: add DisableImplicitFrameworkReferences=true and TargetPlatformVersion=0.0 alongside the faked identity so no platform pack is materialized; if that is insufficient, drive item evaluation only (-t:_TestDumpMauiXamlItems --no-restore). Re-run all four cases on a host without Apple packs.

F3 — [moderate] Windows [Fact] has the same pack-resolution dependency

MSBuildTests.cs:759

TargetPlatformIdentifier=windows on a plain netX.0 TFM pulls Microsoft.Windows.SDK.NET.Ref, which is absent on the Linux/macOS legs that run Xaml.UnitTests. Same ExitCode == 0 assertion, same portability failure. Same correction as F2.

F4 — [minor] [Theory] cases share one temp directory

MSBuildTests.cs:660

SetUp() derives tempDirectory from [CallerMemberName], which for a [Theory] is the bare method name — all three cases share one directory, one obj/, one msbuild.binlog. It survives only because xUnit does not parallelize within a class and Dispose() wipes between cases. The sanitizedName scrubbing of ", (, ) shows the helper was written expecting parameterized names. Pass the platform explicitly into SetUp(...).

3. Failure-Mode Probing (what I checked and cleared)

Probe Result
Do the != '' folder guards ever suppress the fix? No — all five properties are unconditionally defaulted in Before.targets. Dead guards only.
Case sensitivity of TargetPlatformIdentifier comparisons Clear — MSBuild conditions are case-insensitive; consistent with existing Compile conditions.
Orphaned code-behind partials when XAML is removed Clear — the matching .xaml.cs is already removed by the Compile block for the same configuration.
Platform-neutral inner build (TargetPlatformIdentifier == '') Clear — removes everything, matching Compile semantics.
Widening EmbeddedResource Remove Clear — affects non-active platforms only; no runtime LoadFromXaml regression for the active platform.
Regression against previously fixed code Clear — regression-check/risks.json is CLEAN with zero REVERT/OVERLAP entries; the Windows removal predating #36951 is preserved verbatim, and the new [Fact] pins that behaviour.
Is the target reached in the tests (non-vacuous assertions)? Yes — the dump target's AfterTargets fires even if the body is condition-skipped, so a no-op fix would surface all items and trip Assert.DoesNotContain. The android case is a genuine discriminating test.
Public API / trimming / threading / memory dimensions Not applicable — build-infrastructure and test-only change.

4. Prior-Review Reconciliation

Pre-flight (pre-flight/content.md). Agrees on scope and independently flags the same gap I found in F1's second half: "the PR's current fix only addresses built-in platform folders" and points at @(MauiPlatformSpecificFolder) as the data-driven alternative. It does not identify the shared-folder over-removal (F1 part 1) or the platform-pack test-portability defects (F2/F3). My review supersets it.

Try-fix (try-fix/content.md). Read for reconciliation only; individual candidates were not inspected and are not compared here. Two signals are relevant as corroboration of my independent findings:

  • Candidate 1 independently converged on the $(PlatformsProjectFolder) catch-all + @(MauiPlatformSpecificFolder) active-folder resolution — the same structural correction as F1. Two independent derivations of the same shape raise confidence that F1 is a design defect, not a preference.
  • Candidate 1's run table records the iOS and MacCatalyst cases as "Blocked by missing Microsoft.iOS.Sdk / Microsoft.MacCatalyst.Sdk" against an unmodified copy of the PR's own tests. Combined with the gate's identical NETSDK1178, this is a second independent reproduction of F2 and confirms it is a property of the PR's test code, not of the candidate patches. Candidate 2 produced no diff.

Regression check (regression-check/). CLEAN, no REVERT entries — no author acknowledgment required.

Existing GitHub PR review comments. Not fetched (gh unauthenticated in this environment); no duplicate-suppression could be applied. All four findings are grounded in the diff itself, so any overlap with an existing comment is coincidental, not derived.

5. CI / Gate Context

The user-supplied Gate result is INCONCLUSIVE due to build/environment error — the iOS/MacCatalyst legs could not install Microsoft.iOS.Sdk.net10.0_26.0 / Microsoft.MacCatalyst.Sdk.net10.0_26.0 on this Linux host. Per instruction I did not rerun gate verification and do not treat it as a failing fix.

One important reading, however: the gate's own evidence is substantive input to F2 rather than pure environment noise. The gate confirmed the intended behaviour on the path it could execute — without the fix the regression test reached duplicate generated members including ambiguous TestPage.label0 fields, and with the fix the android case passes. That is meaningful positive evidence that the core mechanism works. But the reason the Apple cases could not run is a property of the PR's test design (faked TargetPlatformIdentifier triggering real platform-pack resolution), which will follow the tests into CI on every leg without those packs. F2/F3 are therefore raised as review findings, not as gate outcomes.

No required-check inspection beyond this was necessary.

6. Verdict

Request changes.

The production fix is directionally correct, correctly layered, and well documented, and the regression tests are real (not vacuous). But two [major] issues must be resolved before merge:

  • F1 — the hard-coded four-glob shape both over-removes (active-platform XAML dropped when iOSProjectFolder/MacCatalystProjectFolder are redirected to a shared folder) and under-removes (non-standard Platforms/<Folder> still reproduces MauiXaml will generate source for every xaml file without respect it's condition by configuration/target #36951). One structural edit mirroring the adjacent Compile logic fixes both.
  • F2/F3 — the new tests assert ExitCode == 0 on builds that require Apple/Windows platform SDK packs, so 3 of the 4 new cases are CI failures on legs without them. Confirmed by two independent reproductions.

F4 is minor and may be folded into the same patch. All four findings fit in a single consolidated patch touching the same two files.

Confidence: High on F2/F3 (twice independently reproduced against unmodified PR test code, and directly evidenced by the gate log). High on F1's under-removal half (structural, directly readable from the two adjacent blocks in the same file, and independently identified by pre-flight). Medium-high on F1's over-removal half — the mechanism is certain from MSBuild semantics; what is not directly observable in this environment is how common the shared-folder redirect is in the wild, so the severity rather than the existence carries the uncertainty. Medium on F4 (depends on xUnit parallelization configuration remaining as-is).

🛠️ Try-Fix — Analysis & Comparison

PR #37176 Try-Fix Aggregate

Candidate 1 — Data-Driven Platform Filtering

  • Model: claude-opus-5
  • Result: Blocked
  • Candidate narrative: ../try-fix-1/content.md
  • Standard artifacts: attempt-1/
  • Production file: src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.SingleProject.targets
  • Self-review: 3 recorded findings: one major fixed before final testing, one moderate verified as intended, and one minor documenting cross-file coupling. No unresolved critical or major finding.

Approach

Replace the PR's four hard-coded non-active-platform globs with one data-driven rule. The candidate resolves the active folder from the existing @(MauiPlatformSpecificFolder) mapping, removes $(PlatformsProjectFolder)**/*.xaml except that active folder, and additionally removes MauiXaml items carrying ExcludeFromCurrentConfiguration=true. This differs from the PR by treating the defect as a missing configuration-exclusion contract rather than an incomplete platform enumeration.

The initial implementation attempted in-target metadata stamping with Update globs. Testing showed that in-target Update="glob" applies to every item rather than glob-matching, so the true/false stamps cancelled. The one permitted correction retained the data-driven design but switched to an Include/Exclude glob and kept metadata-based removal as an additive extension point.

Final Candidate Diff

diff --git a/src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.SingleProject.targets b/src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.SingleProject.targets
index 898d105d79..51b5a704a1 100644
--- a/src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.SingleProject.targets
+++ b/src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.SingleProject.targets
@@ -44,6 +44,19 @@
           BeforeTargets="_MauiInjectXamlCssAdditionalFiles;GenerateMSBuildEditorConfigFileShouldRun"
           Condition=" '$(EnableDefaultItems)' == 'true' and '$(SingleProject)' == 'true' ">
 
+    <!--
+      Resolve the single Platforms\<Platform>\ folder that belongs to this inner build, driven by the
+      @(MauiPlatformSpecificFolder) mapping declared in Microsoft.Maui.Controls.SingleProject.Before.targets.
+      Both properties stay empty when building a platform-neutral TargetFramework, in which case no
+      platform folder is active and every Platforms\ XAML file is excluded.
+    -->
+    <PropertyGroup>
+      <_MauiActivePlatformFolder
+          Condition=" '$(TargetPlatformIdentifier)' != '' ">@(MauiPlatformSpecificFolder->WithMetadataValue('TargetPlatformIdentifier', '$(TargetPlatformIdentifier)'))</_MauiActivePlatformFolder>
+      <_MauiActivePlatformXaml
+          Condition=" '$(_MauiActivePlatformFolder)' != '' ">$(_MauiActivePlatformFolder)**/*.xaml</_MauiActivePlatformXaml>
+    </PropertyGroup>
+
   <!-- Removals -->
     <ItemGroup>
       <!-- Remove everything that isn't part of this platform -->
@@ -57,26 +70,28 @@
           Include="$(WindowsProjectFolder)**/*.xaml" />
 
       <!--
-        Remove non-active-platform MAUI XAML files under Platforms/<Platform>. Unlike Compile
-        items, MauiXaml has no ExcludeFromCurrentConfiguration gating, so without this every
-        platform's *.xaml stayed in the MauiXaml item group (and therefore in the XAML SourceGen's
-        AdditionalFiles) for every inner build/TFM, causing files that reuse the same class name
-        per platform (a standard per-platform partial-page pattern) to generate duplicate
-        InitializeComponent/attribute definitions (CS0579/CS0111). See
-        https://github.com/dotnet/maui/issues/36951.
+        Give MauiXaml the same "not part of the current configuration" treatment Compile already
+        gets above: everything under the Platforms folder is excluded and only the active platform's
+        folder is kept. Without this, every platform's *.xaml stayed in the MauiXaml item group (and
+        therefore in the XAML SourceGen's AdditionalFiles) for every inner build/TFM, so files
+        reusing the same x:Class per platform generated duplicate InitializeComponent/attribute
+        definitions (CS0579/CS0111). See https://github.com/dotnet/maui/issues/36951.
+
+        The active folder is resolved from the @(MauiPlatformSpecificFolder) mapping instead of a
+        hard-coded per-platform glob list, so folders for platforms this file does not know about
+        (and projects that redirect a *ProjectFolder property) are handled without further edits.
       -->
       <_MauiXamlToRemove
-          Condition="'$(AndroidProjectFolder)' != '' and '$(TargetPlatformIdentifier)' != 'android'"
-          Include="$(AndroidProjectFolder)**/*.xaml" />
-      <_MauiXamlToRemove
-          Condition="'$(iOSProjectFolder)' != '' and '$(TargetPlatformIdentifier)' != 'ios'"
-          Include="$(iOSProjectFolder)**/*.xaml" />
-      <_MauiXamlToRemove
-          Condition="'$(MacCatalystProjectFolder)' != '' and '$(TargetPlatformIdentifier)' != 'maccatalyst'"
-          Include="$(MacCatalystProjectFolder)**/*.xaml" />
+          Condition="'$(PlatformsProjectFolder)' != ''"
+          Include="$(PlatformsProjectFolder)**/*.xaml"
+          Exclude="$(_MauiActivePlatformXaml)" />
+
+      <!-- Honour explicit configuration exclusion for MauiXaml outside Platforms as well. -->
       <_MauiXamlToRemove
-          Condition="'$(TizenProjectFolder)' != '' and '$(TargetPlatformIdentifier)' != 'tizen'"
-          Include="$(TizenProjectFolder)**/*.xaml" />
+          Include="@(MauiXaml->WithMetadataValue('ExcludeFromCurrentConfiguration', 'true'))" />
 
       <EmbeddedResource Remove="@(_MauiXamlToRemove)" />
       <MauiXaml Remove="@(_MauiXamlToRemove)" />

Tests and Failure Analysis

The mandatory targeted command ran twice, once for the implementation and once after the focused correction. Final results were 2 passed and 2 environment-blocked:

Case Result
Android non-active-platform filtering Pass
Existing Windows removal behavior Pass
iOS non-active-platform filtering Blocked by missing Microsoft.iOS.Sdk.net10.0_26.0
MacCatalyst non-active-platform filtering Blocked by missing Microsoft.MacCatalyst.Sdk.net10.0_26.0
The overall result is Blocked, not Pass or Fail, because the required Apple cases could not reach assertions on this Linux host. EstablishBrokenBaseline.ps1 was invoked but its dirty-worktree safety gate rejected the unrelated pre-existing .github/ and eng/ changes. The agent used an equivalent targeted edit without destructive Git commands, restored the materialized PR source exactly, and left src/ clean.

Candidate 2 — Baseline Blocked

  • Model: gpt-5.6-sol
  • Result: Blocked before design or implementation
  • Candidate narrative: ../try-fix-2/content.md
  • Standard artifacts: attempt-2/
  • Files changed: None
  • Diff: Empty
  • Tests: Not run
  • Self-review: 0 findings because there was no candidate diff

Attempt Result

Candidate 2 first consumed candidate 1's recorded result and excluded its @(MauiPlatformSpecificFolder) resolution, broad $(PlatformsProjectFolder) sweep, and ExcludeFromCurrentConfiguration metadata mechanism from consideration. It did not reopen or rerun candidate 1.

The mandatory EstablishBrokenBaseline.ps1 invocation then stopped at its dirty-working-directory safety gate because of the pre-existing unrelated .github/ and eng/ modifications. Under the bounded contract, candidate 2 did not bypass the script, manually reconstruct a baseline, speculate a SourceGen-boundary implementation, or run tests against the unchanged PR.

(empty — no candidate source or test changes)

The restore invocation reported that no baseline state existed, as expected because establishment failed before creating one. Targeted status checks confirm the Build.Tasks and XAML test paths remain clean and the unrelated working-tree changes remain preserved.

STEP 5a Outcome

Two sequential attempts were made, in the required model order. Candidate 1 yielded one concrete alternative whose Android and Windows regressions pass but whose complete mandatory test result is blocked by unavailable Apple workload packs. Candidate 2 yielded no implementation because the mandatory baseline could not be established. No candidate is recorded as fully verified.

📝 PR Finalize — Recommended Title & Description

Assessment: ✏️ Recommend updating — the current title is grammatically unclear and lacks a scope/component prefix, while the description omits the submitted regression-test changes.

Recommended title

[All Platforms] MauiXaml: Exclude non-active platform XAML from source generation

Recommended description

### Issue Details

MauiXaml source generation processes every platform-specific XAML file without respecting the active target platform, which can generate duplicate members when platform variants reuse the same `x:Class`.

### Root Cause

- `Microsoft.Maui.Controls.Globs.props` globs `**/*.xaml` into the `MauiXaml` item group unconditionally for every inner build/TFM.
- `Microsoft.Maui.Controls.SingleProject.targets` correctly gates `Compile` (`.cs`) items under `Platforms/<Platform>/` through `%(Compile.ExcludeFromCurrentConfiguration)`, but its XAML-removal logic only stripped Windows `.xaml` (WinUI markup) from `MauiXaml`.
- XAML under `Platforms/Android`, `Platforms/iOS`, `Platforms/MacCatalyst`, and `Platforms/Tizen` therefore leaked into non-active inner builds. Because XAML SourceGen consumes `MauiXaml` as `AdditionalFiles`, platform variants using the same class name produced duplicate `InitializeComponent`, attribute, and field declarations.

### Description of Change

Updated `src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.SingleProject.targets`, shipped through `buildTransitive` in `Microsoft.Maui.Controls.Build.Tasks`, to queue Android, iOS, MacCatalyst, and Tizen XAML for removal from `MauiXaml` and `EmbeddedResource` when its folder does not match the active `$(TargetPlatformIdentifier)`.

The existing unconditional removal of Windows-folder XAML remains unchanged because it is WinUI markup rather than MAUI XAML.

Added regression coverage in `src/Controls/tests/Xaml.UnitTests/MSBuild/MSBuildTests.cs` for:

- retaining shared XAML and only the active Android, iOS, or MacCatalyst XAML;
- removing non-active platform XAML that reuses the same `x:Class`; and
- preserving the existing unconditional Windows XAML removal behavior.

### Issues Fixed

Fixes #36951

### Platforms Tested

- [x] Android
- [x] Windows
- [x] iOS
- [x] Mac

| Before | After |
|---|---|
| <img src="https://github.com/user-attachments/assets/a0fd36d9-2094-4948-a645-c3c0d1bf0e4e" width="600" height="300" /> | <img width="600" height="300" alt="image" src="https://github.com/user-attachments/assets/510d9024-dacc-4447-821d-29e7129ed844" /> |

🏁 Report — Final Recommendation

⚠️ Final Recommendation: REQUEST CHANGES

Winner: pr-plus-reviewer. The submitted PR is directionally correct, but the expert review found that its hard-coded platform globs can remove active XAML when iOS and MacCatalyst share a folder, miss unknown folders under Platforms, and make the new tests depend on platform workload packs. The consolidated candidate fixes those issues and passed the complete required regression filter: 5 passed, 0 failed, 0 skipped.

Comparative ranking

Rank Candidate Implementation Required validation Assessment
1 pr-plus-reviewer Replaces the four hard-coded globs with one Platforms/** sweep that excludes the active folder resolved from @(MauiPlatformSpecificFolder). It preserves unconditional Windows XAML removal and adds portable coverage for normal active folders, an iOS/MacCatalyst shared-folder redirect, an unknown Platforms/Shared folder, and Windows. Passed: 5/5 Best coverage and least duplicated production logic. It addresses all actionable expert findings and is the only fully validated candidate.
2 try-fix-1 Uses the same data-driven active-folder approach and additionally honors ExcludeFromCurrentConfiguration metadata outside Platforms. Blocked: Android and Windows passed; iOS and MacCatalyst stopped with NETSDK1178 because the unchanged PR tests resolved unavailable Apple packs. Better production shape than the raw PR, but its required command did not complete and its broader metadata behavior is not covered by the submitted tests.
3 pr Adds one conditional removal glob for each of Android, iOS, MacCatalyst, and Tizen. Gate inconclusive: Android supplied positive evidence; Apple cases were blocked by missing packs. Fixes the common built-in-folder case, but retains the expert-confirmed shared-folder over-removal, unknown-folder under-removal, platform-dependent tests, and shared theory directory.
4 try-fix-2 No implementation. Blocked before tests: baseline setup rejected the dirty raw worktree. No candidate diff or behavioral evidence to compare.
No candidate was demoted for a demonstrated product regression: the non-passing results for pr, try-fix-1, and try-fix-2 were recorded as environment/workflow blockers rather than regression failures. They remain below pr-plus-reviewer, which completed every required case successfully.

Why pr-plus-reviewer wins

The winner mirrors the existing Compile contract instead of maintaining a second per-platform enumeration. Resolving the active folder from the existing mapping also handles redirected folders without additive-removal conflicts, while the catch-all removes unknown folders consistently. Its synthetic tests set TargetPlatformIdentifier during target execution and invoke only _MauiRemovePlatformCompileItems, so they exercise the intended MSBuild behavior without importing unavailable platform SDKs.

The raw PR should therefore be updated with pr-plus-reviewer before approval.

📱 UI Tests — Button,Label,Layout

Detected UI test categories: Button,Label,Layout

✅ Deep UI tests — 366 passed, 0 failed, 7 skipped across 3 categories on platform-pool agent (replaces in-process counts above).

🧪 UI Test Execution Results (deep, platform pool)

Category Tests Snapshot diffs
Button 71/73 (2 skipped) ✓ —
Label 96/98 (2 skipped) ✓ —
Layout 199/202 (3 skipped) ✓ —
📎 Download drop-deep-uitests artifact (TRX + snapshot diffs)
🧭 Next Steps — reviewer patch required (pr-plus-reviewer)

addressed Ai summary concerns.

@kubaflo

This comment has been minimized.

@github-actions github-actions Bot added the s/agent-review-in-progress AI review is currently running for this PR label Aug 14, 2026

@MauiBot MauiBot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Expert Review — 4 findings

See inline comments for details.

</ContentView>";
}

// Deliberately shares the same x:Class across all Platforms/<Platform> variants, to

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔍 AI-Generated Review (multi-model)

[moderate] Regression Prevention — This comment is factually wrong for the code it is attached to. It sits at the end of the Xaml fixture class (after the CustomView/MainPage constants) and claims the fixture "deliberately shares the same x:Class across all Platforms/ variants", but neither new test uses these constants: BuildMauiXamlFilterProject writes "<x/>" placeholders (line 1159) that contain no x:Class at all. As written the comment tells the next reader that the duplicate-x:Class condition from #36951 is covered by this fixture when it is not. It also breaks the brace indentation of the enclosing class. Either delete it or move a corrected version next to the placeholder-writing code.

@MauiBot MauiBot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI Review Summary

@KarthikRajaKalaimani — new AI review results are available based on commit 3ffdbf6.

Gate Passed Confidence Low Platform iOS


🗂️ Review Sessions — click to expand
🚦 Gate — Test Before & After Fix

Gate Result: ✅ PASSED

Platform: IOS · Base: main · Merge base: 5d86a00a

Test Without Fix (expect FAIL) With Fix (expect PASS)
📄 MSBuildTests MSBuildTests ✅ FAIL — 112s ✅ PASS — 40s
🔴 Without fix — 📄 MSBuildTests: FAIL ✅ · 112s

Error-relevant lines (filtered from the build log):

     at Microsoft.Maui.Controls.MSBuild.UnitTests.MSBuildTests.SingleProject_RemovePlatformCompileItems_RetainsActivePlatformMauiXaml(String targetPlatformIdentifier, String activePlatformFolder) in /_/src/Controls/tests/Xaml.UnitTests/MSBuild/MSBuildTests.cs:line 1097
   at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
   at System.Reflection.MethodBaseInvoker.InvokeDirectByRefWithFewArgs(Object obj, Span`1 copyOfArgs, BindingFlags invokeAttr)
   at InvokeStub_MSBuildTests.SingleProject_RemovePlatformCompileItems_RetainsActivePlatformMauiXaml(Object, Span`1)
   at System.Reflection.MethodBaseInvoker.InvokeWithFewArgs(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
🟢 With fix — 📄 MSBuildTests: PASS ✅ · 40s

(no coded error found; showing last 1200 chars)

(useLinuxFolder: False) [643 ms]
  Passed SingleProject_SingularPlatformFolderMetadataRemainsBackwardCompatible(targetPlatformIdentifier: "maccatalyst", shouldIncludeLegacyFile: False) [640 ms]
  Passed SingleProject_SingularPlatformFolderMetadataRemainsBackwardCompatible(targetPlatformIdentifier: "android", shouldIncludeLegacyFile: False) [662 ms]
  Passed SingleProject_SingularPlatformFolderMetadataRemainsBackwardCompatible(targetPlatformIdentifier: "ios", shouldIncludeLegacyFile: True) [660 ms]
  Passed SingleProject_CodesignEntitlementsRespected [548 ms]
  Passed SingleProject_DefaultEntitlementsUsedWhenNoCustomSet [518 ms]
  Passed SingleProject_BuiltInPlatformFoldersCanBeExtended [689 ms]
  Passed DesignTimeBuild [1 s]
  Passed SingleProject_RemovePlatformCompileItems_AlwaysRemovesWindowsMauiXaml [520 ms]
  Passed RandomEmbeddedResource [678 ms]
[xUnit.net 00:00:32.06]     TouchXamlFile [SKIP]
[xUnit.net 00:00:32.06]       source gen changes
[xUnit.net 00:00:32.06]   Finished:    Microsoft.Maui.Controls.Xaml.UnitTests
  Passed TargetsShouldSkip [1 s]
  Skipped TouchXamlFile [1 ms]
Test Run Successful.
Total tests: 44
     Passed: 42
    Skipped: 2
 Total time: 32.3444 Seconds
📁 Fix files reverted (1 files)
  • src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.SingleProject.targets

📋 Pre-Flight — Context & Validation

PR #37176 Pre-Flight

Context

  • PR: Fix MauiXaml will generate source for every xaml file without respect to its condition by configuration/target
  • Issue: #36951
  • Base: main
  • Review branch: pr-review-37176 at squashed commit 6770c4192d
  • Platform requested for this phase: iOS
  • Gate: Passed before STEP 5a; do not rerun gate verification or create/overwrite gate/content.md.

Issue #36951 reports that XAML source generation consumes every MauiXaml item even when a file belongs to a non-active target/configuration. When identical x:Class values are used under multiple Platforms/<Platform> folders, leaked items generate duplicate attributes and InitializeComponent methods (CS0579/CS0111).

Existing PR Approach

The PR changes two files:

  1. src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.SingleProject.targets
    • Extends _MauiXamlToRemove, previously Windows-only, with four hard-coded globs.
    • Removes Android, iOS, MacCatalyst, and Tizen XAML whenever $(TargetPlatformIdentifier) does not equal the corresponding platform.
    • Keeps the existing unconditional Windows removal because Windows-folder XAML is WinUI markup.
  2. src/Controls/tests/Xaml.UnitTests/MSBuild/MSBuildTests.cs
    • Adds an MSBuild fixture that materializes platform XAML items and inspects the items surviving _MauiRemovePlatformCompileItems.
    • Adds a four-row active-platform theory and a Windows regression fact.

The alternative candidates must use a different root-cause strategy rather than relocating the same per-platform hard-coded checks. Relevant existing infrastructure on main includes MauiPlatformSpecificFolder, _MauiNormalizePlatformSpecificFolders, and _MauiCollectPlatformSpecificCompileItems; candidates should account for custom/shared platform folders as well as built-in folders.

Bounded Tests

Primary test:

dotnet test src/Controls/tests/Xaml.UnitTests/Controls.Xaml.UnitTests.csproj --filter "FullyQualifiedName~Microsoft.Maui.Controls.MSBuild.UnitTests.MSBuildTests.SingleProject_RemovePlatformCompileItems_RetainsActivePlatformMauiXaml"

Mandatory regression test:

dotnet test src/Controls/tests/Xaml.UnitTests/Controls.Xaml.UnitTests.csproj --filter "FullyQualifiedName~Microsoft.Maui.Controls.MSBuild.UnitTests.MSBuildTests.SingleProject_RemovePlatformCompileItems_AlwaysRemovesWindowsMauiXaml"

The two may be run in one invocation with:

dotnet test src/Controls/tests/Xaml.UnitTests/Controls.Xaml.UnitTests.csproj --filter "FullyQualifiedName~Microsoft.Maui.Controls.MSBuild.UnitTests.MSBuildTests.SingleProject_RemovePlatformCompileItems_RetainsActivePlatformMauiXaml|FullyQualifiedName~Microsoft.Maui.Controls.MSBuild.UnitTests.MSBuildTests.SingleProject_RemovePlatformCompileItems_AlwaysRemovesWindowsMauiXaml"

No full suite is permitted. Each candidate gets one implementation/test pass and at most one focused correction/retest.

Environment Constraints

The worktree contains unrelated pre-existing modifications under .github/ and eng/. Candidates must preserve them, modify only the issue-specific source/test files when necessary, use EstablishBrokenBaseline.ps1 for baseline/restore, and leave the PR branch restored after capturing artifacts.


🔬 Code Review — Deep Analysis

Expert Evaluation — Raw PR Fix

Verdict: NEEDS_CHANGES

Confidence: low

The PR correctly places XAML filtering in _MauiRemovePlatformCompileItems, before XAML files are consumed by source generation, and the trusted Gate confirms that the submitted fix reproduces and resolves the reported built-in-platform failure. However, the implementation builds a union of hard-coded removal globs without the active-platform allow-list used by the adjacent Compile filtering logic.

Findings

❌ Error — shared platform folders can lose active-platform XAML

Microsoft.Maui.Controls.SingleProject.targets:143-153 independently removes each non-active built-in folder. The platform-folder properties are user-configurable and may identify the same directory. For example, if both iOSProjectFolder and MacCatalystProjectFolder point to Platforms\Apple\, a Mac Catalyst build skips the Mac Catalyst rule but the iOS rule still removes the shared folder. The active XAML is then absent while its code-behind remains, causing a build failure. The adjacent Compile path avoids this by excluding the current platform's collected items from its removal set.

⚠️ Warning — custom platform-folder mappings remain unfiltered

The fix does not use the existing @(MauiPlatformSpecificFolder) registry. XAML in a custom folder such as Platforms\Apple with TargetPlatformIdentifiers="ios;maccatalyst" can still leak into unrelated inner builds even though its C# items are scoped correctly.

⚠️ Warning — tests do not cover conflicting/shared mappings

The new theory covers only mutually exclusive built-in folders, so it cannot detect the over-removal above. A shared multi-TPI folder test is needed to distinguish correct active-item preservation from the submitted union of deny-list rules.

💡 Suggestion — correct the fixture comment

The comment at MSBuildTests.cs:49 says the new fixture shares an x:Class, but BuildMauiXamlFilterProject writes <x/> placeholders and does not use those constants. It should be removed or corrected.

External Output Contract

Consumer token/pattern Producer location Producer emission condition Consumer assumption Ordinary negative case Downstream effect
MAUIXAML_ITEMS: _TestDumpMauiXamlItems generated by BuildMauiXamlFilterProject Emitted at high importance after _MauiRemovePlatformCompileItems runs The line contains the post-filter MauiXaml identities If the target is skipped, no line is emitted The helper returns an empty string and the required SharedPage.xaml assertion fails; the test fails closed

Blast Radius and Failure Modes

  • The target is shipped through buildTransitive and runs for every MAUI single-project build with default items enabled.
  • The effect is build-time item mutation rather than runtime startup or static-state behavior.
  • Built-in, distinct platform folders behave as intended.
  • An empty TargetPlatformIdentifier removes platform XAML consistently with the existing Compile behavior.
  • Shared or aliased platform folders can remove active XAML, and custom registered platform folders are not handled.

Evidence and Review Reconciliation

  • Trusted Gate: PASSED — tests fail without the fix and pass with the submitted fix; not rerun.
  • Required-check status: undetermined because GitHub CLI authentication was unavailable.
  • Prior review status: undetermined because the three GitHub review/comment surfaces could not be queried.

The shared build-infrastructure blast radius and unavailable CI/prior-review evidence cap confidence at low. The actionable findings are persisted separately in inline-findings.json.


🛠️ Try-Fix — Analysis & Comparison

STEP 5a Try-Fix Aggregate — PR #37176

Bounded to two sequential candidates. Gate verification was not rerun.

Candidate 1 — Metadata-Driven Allow-List

Model: claude-opus-5
Result: Pass — 5/5 tests
Correction/retest: Not used
Self-review: 1 moderate finding; 0 critical/major/minor
Detailed artifacts: CustomAgentLogsTmp/PRState/37176/PRAgent/try-fix/attempt-1/
Full narrative: CustomAgentLogsTmp/PRState/37176/PRAgent/try-fix-1/content.md

Approach

Candidate 1 reframed the root cause as MauiXaml never participating in the generic
MauiPlatformSpecificFolder registry already used by the Compile pipeline. It inverted the PR's
hard-coded deny-list into a metadata-driven allow-list:

  • Collect active XAML from every registered folder whose normalized
    TargetPlatformIdentifiers includes the current TargetPlatformIdentifier.
  • Treat XAML under $(PlatformsProjectFolder) and every registered platform folder as removal
    candidates.
  • Remove the candidates except the active set.
  • Preserve the pre-existing unconditional Windows removal.

Unlike the PR, the candidate adds no platform-name conditions and covers custom/shared registered
folders and relocated platform folders.

Diff

diff --git a/src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.SingleProject.targets b/src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.SingleProject.targets
index d0f3d1aaef..4cef168570 100644
--- a/src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.SingleProject.targets
+++ b/src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.SingleProject.targets
@@ -129,6 +129,42 @@
       <_MauiXamlToRemove
           Condition="'$(WindowsProjectFolder)' != ''"
           Include="$(WindowsProjectFolder)**/*.xaml" />
+
+      <!--
+        MauiXaml carries no ExcludeFromCurrentConfiguration metadata, so unlike Compile it was
+        never filtered per configuration: every platform folder's *.xaml stayed in MauiXaml (and
+        therefore in the XAML SourceGen's AdditionalFiles) for every inner build/TFM. Pages that
+        reuse the same x:Class per platform - the standard per-platform partial-page pattern -
+        then emitted duplicate InitializeComponent/attribute definitions (CS0579/CS0111).
+        See https://github.com/dotnet/maui/issues/36951.
+
+        This mirrors the Compile pipeline above (blanket removal + explicit keep-list) instead of
+        deny-listing individual platforms: everything under $(PlatformsProjectFolder) or under a
+        registered MauiPlatformSpecificFolder is a removal candidate, and only folders claiming
+        the active $(TargetPlatformIdentifier) are kept. That also covers custom/shared folders
+        (e.g. Platforms/Apple declared with TargetPlatformIdentifiers="ios;maccatalyst"), folders
+        relocated outside Platforms/ via $(<Platform>ProjectFolder), and folders for platforms
+        this targets file does not know about.
+
+        The TPI matching contract (EnsureTrailingSlash on the folder identity, whitespace- and
+        case-insensitive ';'-delimited list containment, empty list meaning "always keep") is
+        identical to _MauiCollectPlatformSpecificCompileItems - see the comment there. An empty
+        $(TargetPlatformIdentifier) (design-time/netstandard evaluation) keeps nothing, matching
+        how the Compile removal above behaves for those builds.
+
+        Windows is deliberately NOT special-cased here: the unconditional Windows include above
+        is a separate contribution to the same _MauiXamlToRemove list, so WinUI markup is still
+        removed even when 'windows' is the active platform and the keep-list retains it.
+      -->
+      <_MauiActivePlatformXaml
+          Include="$([MSBuild]::EnsureTrailingSlash('%(MauiPlatformSpecificFolder.Identity)'))**/*.xaml"
+          Condition=" '%(MauiPlatformSpecificFolder.TargetPlatformIdentifiers)' == '' or ('$(TargetPlatformIdentifier)' != '' and $([System.Text.RegularExpressions.Regex]::Replace(';%(MauiPlatformSpecificFolder.TargetPlatformIdentifiers);', '\s+', '').ToLowerInvariant().Contains(';$(TargetPlatformIdentifier.ToLowerInvariant());')) )" />
+      <_MauiPlatformXamlCandidate Include="$(PlatformsProjectFolder)**/*.xaml" />
+      <_MauiPlatformXamlCandidate Include="$([MSBuild]::EnsureTrailingSlash('%(MauiPlatformSpecificFolder.Identity)'))**/*.xaml" />
+      <_MauiXamlToRemove
+          Include="@(_MauiPlatformXamlCandidate)"
+          Exclude="@(_MauiActivePlatformXaml)" />
+
       <EmbeddedResource Remove="@(_MauiXamlToRemove)" />
       <MauiXaml Remove="@(_MauiXamlToRemove)" />
     </ItemGroup>

Tests

dotnet test src/Controls/tests/Xaml.UnitTests/Controls.Xaml.UnitTests.csproj --filter "FullyQualifiedName~Microsoft.Maui.Controls.MSBuild.UnitTests.MSBuildTests.SingleProject_RemovePlatformCompileItems_RetainsActivePlatformMauiXaml|FullyQualifiedName~Microsoft.Maui.Controls.MSBuild.UnitTests.MSBuildTests.SingleProject_RemovePlatformCompileItems_AlwaysRemovesWindowsMauiXaml"

Result: Failed: 0, Passed: 5, Skipped: 0, Total: 5.

Analysis

The alternative passed in its first implementation/test pass. Inline review found one moderate
backward-compatibility risk: blanket $(PlatformsProjectFolder)**/*.xaml removal also removes XAML
from unregistered shared folders such as Platforms/Shared/Colors.xaml. A project can register
that folder with an empty TargetPlatformIdentifiers list to keep it, but this is broader behavior
than the PR and may require migration guidance. The worktree was restored after artifact capture.

Candidate 2 — Item-Level Configuration Ownership

Model: gpt-5.6-sol
Result: Fail — 0/5 tests on both permitted runs
Correction/retest: Used once
Self-review: 1 critical finding; 0 major/moderate/minor
Detailed artifacts: CustomAgentLogsTmp/PRState/37176/PRAgent/try-fix/attempt-2/
Full narrative: CustomAgentLogsTmp/PRState/37176/PRAgent/try-fix-2/content.md

Approach

Candidate 2 treated absent item-level configuration ownership as the root cause. At
_MauiRemovePlatformCompileItems execution, it annotated built-in platform MauiXaml items with
an internal _MauiTargetPlatformIdentifier, then attempted one generic metadata predicate that
removed items whose owner differed from $(TargetPlatformIdentifier). Unregistered shared XAML
was intentionally left untouched, and the existing unconditional Windows removal remained.

This differed from both preceding designs: it did not use the PR's four conditional removal globs,
and it did not construct Candidate 1's active/candidate sets, use the platform-folder registry as
its mechanism, or blanket-remove unregistered Platforms/**/*.xaml.

Final Diff

diff --git a/src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.SingleProject.targets b/src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.SingleProject.targets
index d0f3d1aaef..3f594ec9ae 100644
--- a/src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.SingleProject.targets
+++ b/src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.SingleProject.targets
@@ -33,6 +33,7 @@
         Update="$(TizenProjectFolder)**/*$(DefaultLanguageSourceExtension)">
       <ExcludeFromCurrentConfiguration>false</ExcludeFromCurrentConfiguration>
     </Compile>
+
   </ItemGroup>
 
   <!--
@@ -104,6 +105,23 @@
 
   <!-- Removals -->
     <ItemGroup>
+      <!-- Record configuration ownership at execution time so items added by earlier targets are included. -->
+      <MauiXaml Condition=" '$(AndroidProjectFolder)' != '' " Update="$(AndroidProjectFolder)**/*.xaml">
+        <_MauiTargetPlatformIdentifier>android</_MauiTargetPlatformIdentifier>
+      </MauiXaml>
+      <MauiXaml Condition=" '$(iOSProjectFolder)' != '' " Update="$(iOSProjectFolder)**/*.xaml">
+        <_MauiTargetPlatformIdentifier>ios</_MauiTargetPlatformIdentifier>
+      </MauiXaml>
+      <MauiXaml Condition=" '$(MacCatalystProjectFolder)' != '' " Update="$(MacCatalystProjectFolder)**/*.xaml">
+        <_MauiTargetPlatformIdentifier>maccatalyst</_MauiTargetPlatformIdentifier>
+      </MauiXaml>
+      <MauiXaml Condition=" '$(WindowsProjectFolder)' != '' " Update="$(WindowsProjectFolder)**/*.xaml">
+        <_MauiTargetPlatformIdentifier>windows</_MauiTargetPlatformIdentifier>
+      </MauiXaml>
+      <MauiXaml Condition=" '$(TizenProjectFolder)' != '' " Update="$(TizenProjectFolder)**/*.xaml">
+        <_MauiTargetPlatformIdentifier>tizen</_MauiTargetPlatformIdentifier>
+      </MauiXaml>
+
       <!--
         Remove every Compile item under $(PlatformsProjectFolder) that is not
         part of the current build configuration AND has not been explicitly
@@ -129,6 +147,9 @@
       <_MauiXamlToRemove
           Condition="'$(WindowsProjectFolder)' != ''"
           Include="$(WindowsProjectFolder)**/*.xaml" />
+      <_MauiXamlToRemove
+          Condition=" '%(MauiXaml._MauiTargetPlatformIdentifier)' != '' and '%(MauiXaml._MauiTargetPlatformIdentifier)' != '$(TargetPlatformIdentifier)' "
+          Include="%(MauiXaml.Identity)" />
       <EmbeddedResource Remove="@(_MauiXamlToRemove)" />
       <MauiXaml Remove="@(_MauiXamlToRemove)" />
     </ItemGroup>

Tests

dotnet test src/Controls/tests/Xaml.UnitTests/Controls.Xaml.UnitTests.csproj --filter "FullyQualifiedName~Microsoft.Maui.Controls.MSBuild.UnitTests.MSBuildTests.SingleProject_RemovePlatformCompileItems_RetainsActivePlatformMauiXaml|FullyQualifiedName~Microsoft.Maui.Controls.MSBuild.UnitTests.MSBuildTests.SingleProject_RemovePlatformCompileItems_AlwaysRemovesWindowsMauiXaml"
  • Initial implementation: Failed: 5, Passed: 0, Skipped: 0, Total: 5.
  • Focused correction (Include="@(MauiXaml)" to Include="%(MauiXaml.Identity)"):
    Failed: 5, Passed: 0, Skipped: 0, Total: 5.

Failure Analysis

The initial metadata batch expanded the complete @(MauiXaml) list for a matching batch and
removed shared/active items. The single permitted correction switched to the batched identity,
but target-time MSBuild batching still did not isolate each removal: logs showed shared XAML
removed in several configurations and all platform XAML retained in another. Inline review
therefore recorded one critical logic/correctness finding. The correction allowance was exhausted,
the candidate was marked Fail, and the worktree was restored.

Aggregate Outcome

Two candidates were attempted, which exhausts the STEP 5a limit:

Candidate Mechanism Result Review signal
1 Registry-driven active allow-list Pass (5/5) One moderate compatibility risk
2 Item-level ownership metadata and predicate Fail (0/5 twice) One critical batching defect

Candidate 1 is the only empirically successful alternative, but its broader handling of
unregistered Platforms/ XAML must be weighed against the PR's narrower behavior in STEP 5b.


📝 PR Finalize — Recommended Title & Description

Assessment: ✏️ Recommend updating — the current title is grammatically unclear and lacks a platform/component prefix, while the description can more precisely connect the submitted target change and its MSBuild regression coverage.

Recommended title

[All] XAML build: Filter MauiXaml items by target platform

Recommended description

### Issue Details

MauiXaml source generation processes XAML files from non-active platform folders instead of respecting the current target platform.

### Root Cause

- `Microsoft.Maui.Controls.Globs.props` unconditionally globs `**/*.xaml` into the `MauiXaml` item group for every inner build/TFM.
- `Microsoft.Maui.Controls.SingleProject.targets` already gates `Compile` (`.cs`) items under `Platforms/<Platform>/` through `%(Compile.ExcludeFromCurrentConfiguration)`, but its XAML-removal logic only removed Windows `.xaml` (WinUI markup) from `MauiXaml`.
- XAML under `Platforms/Android`, `Platforms/iOS`, `Platforms/MacCatalyst`, and `Platforms/Tizen` therefore leaked into every inner build. When multiple platform folders reused the same `x:Class`—a supported per-platform pattern—XAML SourceGen produced duplicate attributes, fields, and `InitializeComponent` methods (`CS0579`/`CS0111`).

### Description of Change

Updated `src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.SingleProject.targets`, shipped through `buildTransitive` in `Microsoft.Maui.Controls.Build.Tasks`, to extend `_MauiRemovePlatformCompileItems`.

For each built-in Android, iOS, Mac Catalyst, and Tizen project folder, the submitted change removes its `.xaml` files from `MauiXaml` and `EmbeddedResource` when that platform does not match `$(TargetPlatformIdentifier)`. The pre-existing unconditional Windows-folder removal remains unchanged because Windows-folder XAML is WinUI markup rather than MAUI XAML.

Added MSBuild regression coverage in `MSBuildTests.cs` for:

- retaining the active Android, iOS, Mac Catalyst, or Tizen `MauiXaml` item while removing the other built-in platform items;
- preserving shared XAML outside platform folders;
- continuing to remove Windows XAML even for a Windows target.

### Issues Fixed

Fixes #36951

### Platforms Tested

- [x] Android
- [x] Windows
- [x] iOS
- [x] Mac

| Before | After |
|---|---|
| <img src="https://github.com/user-attachments/assets/a0fd36d9-2094-4948-a645-c3c0d1bf0e4e" width="600" height="300" /> | <img src="https://github.com/user-attachments/assets/510d9024-dacc-4447-821d-29e7129ed844" width="600" height="300" alt="Platform-specific MauiXaml items filtered after the fix" /> |

🏁 Report — Final Recommendation

⚠️ Final Recommendation: REQUEST CHANGES

Winner: pr-plus-reviewer

pr-plus-reviewer is the only candidate that combines a passing targeted regression run with coverage of the expert review's shared-folder failure mode and without try-fix-1's unregistered-XAML compatibility regression. The submitted PR should adopt this candidate's registry-driven filtering and tests before merge.

Comparative Ranking

Rank Candidate Validation Review result Assessment
1 pr-plus-reviewer PASS — 10/10 in the required candidate sandbox Resolves the expert error and both warnings Uses MauiPlatformSpecificFolder as the source of truth, excludes active mappings, supports custom/shared folders, and deliberately leaves unregistered shared XAML unchanged.
2 try-fix-1 PASS — 5/5 One moderate backward-compatibility finding Correctly uses a metadata-driven active allow-list, but blanket-removes every $(PlatformsProjectFolder)**/*.xaml, including unregistered shared resources that previously survived.
3 pr Trusted Gate PASSED; submitted focused cases pass NEEDS_CHANGES — one error, two warnings, one suggestion Fixes the reported distinct built-in-folder scenario, but independent hard-coded globs can remove active XAML when platform-folder properties overlap and do not handle custom MauiPlatformSpecificFolder mappings.
4 try-fix-2 FAIL — 0/5 on both permitted runs One critical batching defect Item metadata batching did not isolate removal identities; active/shared files were removed in some configurations while non-active files survived in another. Per the contract, this regression-test failure ranks below passing candidates.

Why pr-plus-reviewer Wins

The existing registry already normalizes built-in and extensibility mappings into TargetPlatformIdentifiers. Collecting active *.xaml from that registry and excluding it from registered-folder removal mirrors the proven Compile allow-list model without enumerating platform names. The added tests distinguish all material alternatives:

  • overlapping iOSProjectFolder and MacCatalystProjectFolder values retain active Mac Catalyst XAML;
  • a custom ios;maccatalyst folder is retained for its active targets and removed for Android;
  • unregistered Platforms/Shared XAML remains untouched;
  • the original Android/iOS/MacCatalyst/Tizen cases and unconditional Windows behavior remain covered.

Evidence and Remaining Uncertainty

  • Trusted Gate: PASSED; it was not rerun.
  • pr-plus-reviewer targeted validation: 10 passed, 0 failed, run once from /Users/cloudtest/vss/_work/_temp/pr-37176-pr-plus-reviewer.
  • diff --check against the immutable candidate baseline passed before validation.
  • Required GitHub check state and prior-review reconciliation remain undetermined because GitHub CLI authentication was unavailable during the expert pass. This uncertainty does not alter the request-changes recommendation because the raw PR has a concrete correctness defect.

The winning patch is persisted in pr-plus-reviewer/reviewer.patch; the full candidate against the PR base is in pr-plus-reviewer/candidate.patch.


📱 UI Tests — Button,Label,Layout

Detected UI test categories: Button,Label,Layout

❌ Deep UI tests — 354 passed, 1 failed, 8 skipped across 3 categories on platform-pool agent (replaces in-process counts above).

🧪 UI Test Execution Results (deep, platform pool)

Category Tests Snapshot diffs
Button 71/72 (1 skipped) ✓ —
Label 90/92 (2 skipped) ✓ —
Layout 193/199 (1 ❌, 5 skipped) —
🔍 AI analysis of failures — PR-related vs unrelated

🔍 AI-generated triage (GitHub Copilot CLI) — a heuristic judgement of whether each deep UI test failure is connected to this PR's changes. Verify before relying on it.

Likely unrelated: the failures appear pre-existing, flaky, or infrastructure.

  • ● Unrelated — Layout element lookup (~1 test): EditorsScrollingPageTest failed with a generic Appium NoSuchElementException in an editor/layout area untouched by the PR, while the build-target change retains active iOS XAML for this iOS run.
❌ Layout — 1 failed test
EditorsScrollingPageTest
OpenQA.Selenium.NoSuchElementException : An element could not be located on the page using the given search parameters.; For documentation on this error, please visit: https://www.selenium.dev/documentation/webdriver/troubleshooting/errors#no-such-element-exception
at OpenQA.Selenium.WebDriver.UnpackAndThrowOnError(Response errorResponse, String commandToExecute)
   at OpenQA.Selenium.WebDriver.ExecuteAsync(String driverCommandToExecute, Dictionary`2 parameters)
   at OpenQA.Selenium.Appium.AppiumDriver.Execute(String driverCommandToExecute, Dictionary`2 parameters)
   at OpenQA.Selenium.WebDriver.FindElement(String mechanism, String value)
   at OpenQA.Selenium.Appium.AppiumDriver.FindElement(String by, String value)
   at OpenQA.Selenium.Appium.MobileBy.FindElement(ISearchContext context)
   at OpenQA.Selenium.WebDriver.FindElement(By by)
   at OpenQA.Selenium.Appium.AppiumDriver.FindElement(By by)
   at Microsoft.Maui.TestCases.Tests.KeyboardScrolling.CloseiOSEditorKeyboard(AppiumDr
...

📎 Download drop-deep-uitests artifact (TRX + snapshot diffs)


🧭 Next Steps — reviewer patch required (pr-plus-reviewer)

The reviewer-enhanced candidate won, so the submitted PR still needs those changes.

Why: The reviewer-enhanced PR candidate passed all 10 targeted cases and fixes the submitted implementation's active-XAML over-removal for overlapping folders. It also supports registered custom/shared mappings without try-fix-1's compatibility regression for unregistered shared XAML.

Apply PRAgent/pr-plus-reviewer/reviewer.patch from the CopilotLogs
artifact (or follow the report's Required submitted-PR change), push the update, and run
the review again.

@MauiBot MauiBot added s/agent-gate-passed AI verified tests catch the bug (fail without fix, pass with fix) and removed s/agent-review-in-progress AI review is currently running for this PR labels Aug 15, 2026
@kubaflo
kubaflo changed the base branch from main to inflight/current August 15, 2026 15:30
@kubaflo
kubaflo merged commit ce1101e into dotnet:inflight/current Aug 15, 2026
154 of 167 checks passed
@github-actions github-actions Bot added this to the .NET 10 SR11 milestone Aug 15, 2026
kubaflo pushed a commit that referenced this pull request Aug 27, 2026
… to its condition by configuration/target (#37176)

<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!
 
### Issue Details

MauiXaml will generate source for every xaml file without respect to its
condition by configuration/target

### Root Cause 

• Microsoft.Maui.Controls.Globs.props globs **\*.xaml into the MauiXaml
item group unconditionally for every inner build/TFM.
• Microsoft.Maui.Controls.SingleProject.targets correctly gates Compile
( .cs ) items under Platforms/<Platform>/ via
%(Compile.ExcludeFromCurrentConfiguration) , but its XAML-removal logic
only ever stripped Windows .xaml (WinUI markup) out of MauiXaml . It
never removed non-active-platform .xaml under Platforms/Android ,
Platforms/iOS , Platforms/MacCatalyst , or Platforms/Tizen .
• Consequence: the XAML SourceGen consumes MauiXaml as AdditionalFiles
regardless of platform, so every platform's xaml leaked into every inner
build — producing duplicate InitializeComponent /attribute/field
declarations whenever multiple platforms reused the same class name (a
standard, supported pattern).

### Description of Change
 

src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.SingleProject.targets
(shipped via buildTransitive in Microsoft.Maui.Controls.Build.Tasks →
applies to every MAUI app)
 
Extended the _MauiRemovePlatformCompileItems target's _MauiXamlToRemove
computation (previously Windows-only) to also cover
Android/iOS/MacCatalyst/Tizen: for each built-in platform folder, its
.xaml files are queued for removal from MauiXaml / EmbeddedResource
unless it matches the currently active $(TargetPlatformIdentifier) . The
pre-existing unconditional Windows-folder removal (WinUI markup, not
MAUI XAML) is left unchanged.

 
### Issues Fixed
 
Fixes #36951 
 
**Tested the behavior in the following platforms.**
- [x] Android
- [x] Windows
- [x] iOS
- [x] Mac
 
| Before  | After  |
|---------|--------|
| <img
src="https://github.com/user-attachments/assets/a0fd36d9-2094-4948-a645-c3c0d1bf0e4e"
Width="600" Height="300" /> | <img width="600" height="300" alt="image"
src="https://github.com/user-attachments/assets/510d9024-dacc-4447-821d-29e7129ed844"
/> |
kubaflo pushed a commit that referenced this pull request Sep 2, 2026
… to its condition by configuration/target (#37176)

<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!
 
### Issue Details

MauiXaml will generate source for every xaml file without respect to its
condition by configuration/target

### Root Cause 

• Microsoft.Maui.Controls.Globs.props globs **\*.xaml into the MauiXaml
item group unconditionally for every inner build/TFM.
• Microsoft.Maui.Controls.SingleProject.targets correctly gates Compile
( .cs ) items under Platforms/<Platform>/ via
%(Compile.ExcludeFromCurrentConfiguration) , but its XAML-removal logic
only ever stripped Windows .xaml (WinUI markup) out of MauiXaml . It
never removed non-active-platform .xaml under Platforms/Android ,
Platforms/iOS , Platforms/MacCatalyst , or Platforms/Tizen .
• Consequence: the XAML SourceGen consumes MauiXaml as AdditionalFiles
regardless of platform, so every platform's xaml leaked into every inner
build — producing duplicate InitializeComponent /attribute/field
declarations whenever multiple platforms reused the same class name (a
standard, supported pattern).

### Description of Change
 

src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.SingleProject.targets
(shipped via buildTransitive in Microsoft.Maui.Controls.Build.Tasks →
applies to every MAUI app)
 
Extended the _MauiRemovePlatformCompileItems target's _MauiXamlToRemove
computation (previously Windows-only) to also cover
Android/iOS/MacCatalyst/Tizen: for each built-in platform folder, its
.xaml files are queued for removal from MauiXaml / EmbeddedResource
unless it matches the currently active $(TargetPlatformIdentifier) . The
pre-existing unconditional Windows-folder removal (WinUI markup, not
MAUI XAML) is left unchanged.

 
### Issues Fixed
 
Fixes #36951 
 
**Tested the behavior in the following platforms.**
- [x] Android
- [x] Windows
- [x] iOS
- [x] Mac
 
| Before  | After  |
|---------|--------|
| <img
src="https://github.com/user-attachments/assets/a0fd36d9-2094-4948-a645-c3c0d1bf0e4e"
Width="600" Height="300" /> | <img width="600" height="300" alt="image"
src="https://github.com/user-attachments/assets/510d9024-dacc-4447-821d-29e7129ed844"
/> |
kubaflo pushed a commit that referenced this pull request Sep 3, 2026
… to its condition by configuration/target (#37176)

<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!
 
### Issue Details

MauiXaml will generate source for every xaml file without respect to its
condition by configuration/target

### Root Cause 

• Microsoft.Maui.Controls.Globs.props globs **\*.xaml into the MauiXaml
item group unconditionally for every inner build/TFM.
• Microsoft.Maui.Controls.SingleProject.targets correctly gates Compile
( .cs ) items under Platforms/<Platform>/ via
%(Compile.ExcludeFromCurrentConfiguration) , but its XAML-removal logic
only ever stripped Windows .xaml (WinUI markup) out of MauiXaml . It
never removed non-active-platform .xaml under Platforms/Android ,
Platforms/iOS , Platforms/MacCatalyst , or Platforms/Tizen .
• Consequence: the XAML SourceGen consumes MauiXaml as AdditionalFiles
regardless of platform, so every platform's xaml leaked into every inner
build — producing duplicate InitializeComponent /attribute/field
declarations whenever multiple platforms reused the same class name (a
standard, supported pattern).

### Description of Change
 

src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.SingleProject.targets
(shipped via buildTransitive in Microsoft.Maui.Controls.Build.Tasks →
applies to every MAUI app)
 
Extended the _MauiRemovePlatformCompileItems target's _MauiXamlToRemove
computation (previously Windows-only) to also cover
Android/iOS/MacCatalyst/Tizen: for each built-in platform folder, its
.xaml files are queued for removal from MauiXaml / EmbeddedResource
unless it matches the currently active $(TargetPlatformIdentifier) . The
pre-existing unconditional Windows-folder removal (WinUI markup, not
MAUI XAML) is left unchanged.

 
### Issues Fixed
 
Fixes #36951 
 
**Tested the behavior in the following platforms.**
- [x] Android
- [x] Windows
- [x] iOS
- [x] Mac
 
| Before  | After  |
|---------|--------|
| <img
src="https://github.com/user-attachments/assets/a0fd36d9-2094-4948-a645-c3c0d1bf0e4e"
Width="600" Height="300" /> | <img width="600" height="300" alt="image"
src="https://github.com/user-attachments/assets/510d9024-dacc-4447-821d-29e7129ed844"
/> |
kubaflo pushed a commit that referenced this pull request Sep 6, 2026
… to its condition by configuration/target (#37176)

<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!
 
### Issue Details

MauiXaml will generate source for every xaml file without respect to its
condition by configuration/target

### Root Cause 

• Microsoft.Maui.Controls.Globs.props globs **\*.xaml into the MauiXaml
item group unconditionally for every inner build/TFM.
• Microsoft.Maui.Controls.SingleProject.targets correctly gates Compile
( .cs ) items under Platforms/<Platform>/ via
%(Compile.ExcludeFromCurrentConfiguration) , but its XAML-removal logic
only ever stripped Windows .xaml (WinUI markup) out of MauiXaml . It
never removed non-active-platform .xaml under Platforms/Android ,
Platforms/iOS , Platforms/MacCatalyst , or Platforms/Tizen .
• Consequence: the XAML SourceGen consumes MauiXaml as AdditionalFiles
regardless of platform, so every platform's xaml leaked into every inner
build — producing duplicate InitializeComponent /attribute/field
declarations whenever multiple platforms reused the same class name (a
standard, supported pattern).

### Description of Change
 

src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.SingleProject.targets
(shipped via buildTransitive in Microsoft.Maui.Controls.Build.Tasks →
applies to every MAUI app)
 
Extended the _MauiRemovePlatformCompileItems target's _MauiXamlToRemove
computation (previously Windows-only) to also cover
Android/iOS/MacCatalyst/Tizen: for each built-in platform folder, its
.xaml files are queued for removal from MauiXaml / EmbeddedResource
unless it matches the currently active $(TargetPlatformIdentifier) . The
pre-existing unconditional Windows-folder removal (WinUI markup, not
MAUI XAML) is left unchanged.

 
### Issues Fixed
 
Fixes #36951 
 
**Tested the behavior in the following platforms.**
- [x] Android
- [x] Windows
- [x] iOS
- [x] Mac
 
| Before  | After  |
|---------|--------|
| <img
src="https://github.com/user-attachments/assets/a0fd36d9-2094-4948-a645-c3c0d1bf0e4e"
Width="600" Height="300" /> | <img width="600" height="300" alt="image"
src="https://github.com/user-attachments/assets/510d9024-dacc-4447-821d-29e7129ed844"
/> |
kubaflo pushed a commit that referenced this pull request Sep 7, 2026
… to its condition by configuration/target (#37176)

<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!
 
### Issue Details

MauiXaml will generate source for every xaml file without respect to its
condition by configuration/target

### Root Cause 

• Microsoft.Maui.Controls.Globs.props globs **\*.xaml into the MauiXaml
item group unconditionally for every inner build/TFM.
• Microsoft.Maui.Controls.SingleProject.targets correctly gates Compile
( .cs ) items under Platforms/<Platform>/ via
%(Compile.ExcludeFromCurrentConfiguration) , but its XAML-removal logic
only ever stripped Windows .xaml (WinUI markup) out of MauiXaml . It
never removed non-active-platform .xaml under Platforms/Android ,
Platforms/iOS , Platforms/MacCatalyst , or Platforms/Tizen .
• Consequence: the XAML SourceGen consumes MauiXaml as AdditionalFiles
regardless of platform, so every platform's xaml leaked into every inner
build — producing duplicate InitializeComponent /attribute/field
declarations whenever multiple platforms reused the same class name (a
standard, supported pattern).

### Description of Change
 

src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.SingleProject.targets
(shipped via buildTransitive in Microsoft.Maui.Controls.Build.Tasks →
applies to every MAUI app)
 
Extended the _MauiRemovePlatformCompileItems target's _MauiXamlToRemove
computation (previously Windows-only) to also cover
Android/iOS/MacCatalyst/Tizen: for each built-in platform folder, its
.xaml files are queued for removal from MauiXaml / EmbeddedResource
unless it matches the currently active $(TargetPlatformIdentifier) . The
pre-existing unconditional Windows-folder removal (WinUI markup, not
MAUI XAML) is left unchanged.

 
### Issues Fixed
 
Fixes #36951 
 
**Tested the behavior in the following platforms.**
- [x] Android
- [x] Windows
- [x] iOS
- [x] Mac
 
| Before  | After  |
|---------|--------|
| <img
src="https://github.com/user-attachments/assets/a0fd36d9-2094-4948-a645-c3c0d1bf0e4e"
Width="600" Height="300" /> | <img width="600" height="300" alt="image"
src="https://github.com/user-attachments/assets/510d9024-dacc-4447-821d-29e7129ed844"
/> |
kubaflo pushed a commit that referenced this pull request Sep 8, 2026
… to its condition by configuration/target (#37176)

<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!
 
### Issue Details

MauiXaml will generate source for every xaml file without respect to its
condition by configuration/target

### Root Cause 

• Microsoft.Maui.Controls.Globs.props globs **\*.xaml into the MauiXaml
item group unconditionally for every inner build/TFM.
• Microsoft.Maui.Controls.SingleProject.targets correctly gates Compile
( .cs ) items under Platforms/<Platform>/ via
%(Compile.ExcludeFromCurrentConfiguration) , but its XAML-removal logic
only ever stripped Windows .xaml (WinUI markup) out of MauiXaml . It
never removed non-active-platform .xaml under Platforms/Android ,
Platforms/iOS , Platforms/MacCatalyst , or Platforms/Tizen .
• Consequence: the XAML SourceGen consumes MauiXaml as AdditionalFiles
regardless of platform, so every platform's xaml leaked into every inner
build — producing duplicate InitializeComponent /attribute/field
declarations whenever multiple platforms reused the same class name (a
standard, supported pattern).

### Description of Change
 

src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.SingleProject.targets
(shipped via buildTransitive in Microsoft.Maui.Controls.Build.Tasks →
applies to every MAUI app)
 
Extended the _MauiRemovePlatformCompileItems target's _MauiXamlToRemove
computation (previously Windows-only) to also cover
Android/iOS/MacCatalyst/Tizen: for each built-in platform folder, its
.xaml files are queued for removal from MauiXaml / EmbeddedResource
unless it matches the currently active $(TargetPlatformIdentifier) . The
pre-existing unconditional Windows-folder removal (WinUI markup, not
MAUI XAML) is left unchanged.

 
### Issues Fixed
 
Fixes #36951 
 
**Tested the behavior in the following platforms.**
- [x] Android
- [x] Windows
- [x] iOS
- [x] Mac
 
| Before  | After  |
|---------|--------|
| <img
src="https://github.com/user-attachments/assets/a0fd36d9-2094-4948-a645-c3c0d1bf0e4e"
Width="600" Height="300" /> | <img width="600" height="300" alt="image"
src="https://github.com/user-attachments/assets/510d9024-dacc-4447-821d-29e7129ed844"
/> |
kubaflo pushed a commit that referenced this pull request Sep 9, 2026
… to its condition by configuration/target (#37176)

<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!
 
### Issue Details

MauiXaml will generate source for every xaml file without respect to its
condition by configuration/target

### Root Cause 

• Microsoft.Maui.Controls.Globs.props globs **\*.xaml into the MauiXaml
item group unconditionally for every inner build/TFM.
• Microsoft.Maui.Controls.SingleProject.targets correctly gates Compile
( .cs ) items under Platforms/<Platform>/ via
%(Compile.ExcludeFromCurrentConfiguration) , but its XAML-removal logic
only ever stripped Windows .xaml (WinUI markup) out of MauiXaml . It
never removed non-active-platform .xaml under Platforms/Android ,
Platforms/iOS , Platforms/MacCatalyst , or Platforms/Tizen .
• Consequence: the XAML SourceGen consumes MauiXaml as AdditionalFiles
regardless of platform, so every platform's xaml leaked into every inner
build — producing duplicate InitializeComponent /attribute/field
declarations whenever multiple platforms reused the same class name (a
standard, supported pattern).

### Description of Change
 

src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.SingleProject.targets
(shipped via buildTransitive in Microsoft.Maui.Controls.Build.Tasks →
applies to every MAUI app)
 
Extended the _MauiRemovePlatformCompileItems target's _MauiXamlToRemove
computation (previously Windows-only) to also cover
Android/iOS/MacCatalyst/Tizen: for each built-in platform folder, its
.xaml files are queued for removal from MauiXaml / EmbeddedResource
unless it matches the currently active $(TargetPlatformIdentifier) . The
pre-existing unconditional Windows-folder removal (WinUI markup, not
MAUI XAML) is left unchanged.

 
### Issues Fixed
 
Fixes #36951 
 
**Tested the behavior in the following platforms.**
- [x] Android
- [x] Windows
- [x] iOS
- [x] Mac
 
| Before  | After  |
|---------|--------|
| <img
src="https://github.com/user-attachments/assets/a0fd36d9-2094-4948-a645-c3c0d1bf0e4e"
Width="600" Height="300" /> | <img width="600" height="300" alt="image"
src="https://github.com/user-attachments/assets/510d9024-dacc-4447-821d-29e7129ed844"
/> |
kubaflo pushed a commit that referenced this pull request Sep 11, 2026
… to its condition by configuration/target (#37176)

<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!
 
### Issue Details

MauiXaml will generate source for every xaml file without respect to its
condition by configuration/target

### Root Cause 

• Microsoft.Maui.Controls.Globs.props globs **\*.xaml into the MauiXaml
item group unconditionally for every inner build/TFM.
• Microsoft.Maui.Controls.SingleProject.targets correctly gates Compile
( .cs ) items under Platforms/<Platform>/ via
%(Compile.ExcludeFromCurrentConfiguration) , but its XAML-removal logic
only ever stripped Windows .xaml (WinUI markup) out of MauiXaml . It
never removed non-active-platform .xaml under Platforms/Android ,
Platforms/iOS , Platforms/MacCatalyst , or Platforms/Tizen .
• Consequence: the XAML SourceGen consumes MauiXaml as AdditionalFiles
regardless of platform, so every platform's xaml leaked into every inner
build — producing duplicate InitializeComponent /attribute/field
declarations whenever multiple platforms reused the same class name (a
standard, supported pattern).

### Description of Change
 

src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.SingleProject.targets
(shipped via buildTransitive in Microsoft.Maui.Controls.Build.Tasks →
applies to every MAUI app)
 
Extended the _MauiRemovePlatformCompileItems target's _MauiXamlToRemove
computation (previously Windows-only) to also cover
Android/iOS/MacCatalyst/Tizen: for each built-in platform folder, its
.xaml files are queued for removal from MauiXaml / EmbeddedResource
unless it matches the currently active $(TargetPlatformIdentifier) . The
pre-existing unconditional Windows-folder removal (WinUI markup, not
MAUI XAML) is left unchanged.

 
### Issues Fixed
 
Fixes #36951 
 
**Tested the behavior in the following platforms.**
- [x] Android
- [x] Windows
- [x] iOS
- [x] Mac
 
| Before  | After  |
|---------|--------|
| <img
src="https://github.com/user-attachments/assets/a0fd36d9-2094-4948-a645-c3c0d1bf0e4e"
Width="600" Height="300" /> | <img width="600" height="300" alt="image"
src="https://github.com/user-attachments/assets/510d9024-dacc-4447-821d-29e7129ed844"
/> |
@github-actions github-actions Bot locked and limited conversation to collaborators Sep 15, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

community ✨ Community Contribution partner/syncfusion Issues / PR's with Syncfusion collaboration s/agent-changes-requested AI agent recommends changes - found a better alternative or issues s/agent-fix-win AI found a better alternative fix than the PR s/agent-gate-passed AI verified tests catch the bug (fail without fix, pass with fix) s/agent-reviewed PR was reviewed by AI agent workflow (full 4-phase review)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

MauiXaml will generate source for every xaml file without respect it's condition by configuration/target

5 participants