mirror of
https://github.com/microsoft/microsoft-ui-xaml.git
synced 2026-10-28 08:25:50 +08:00
* Tabular: widen the dllmain activation carve-out for TableView MuxcActivationHandler fast-pathed every Microsoft.UI.Xaml.* activation to the MUX framework DLL, excluding only the Microsoft.UI.Xaml.Controls.Tabular.* subtree. Tabular also owns Microsoft.UI.Xaml.XamlTypeInfo.XamlControlsTabularXamlMetaDataProvider, which was therefore routed to MUX instead of resolving locally. Add an explicit kTabularOwnedNamespacesOutsideSubtree prefix set, matched on a trailing '.' so a prefix can only ever match a whole namespace component, and drop the resolved TODO. Base-framework routing is unchanged. Validated: Microsoft.UI.Xaml.Controls.vcxproj and Microsoft.UI.Xaml.Controls.Tabular.vcxproj both build with 0 errors / 0 warnings (amd64chk). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: f7510cb3-5321-46fb-919b-6234e3262d94 * Tabular: trim the dllmain activation carve-out comments Amends the comment block on the previous commit down to what the code needs; no behaviour change. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Tabular: publish TableView through the package and fix theme-resource resolution Removes the workarounds that consuming apps needed for TableView. An app outside the repo can now reference the package and render a TableView with no app-side shims: no projection regeneration, no ActivatableClass injection, no WinMDReference, no metadata-provider chaining. Public metadata Drop the IncludeTabularControlsInPublicMetadata gate so Tabular types reach the public merged winmd and the CsWinRT projection, and emit their activation registrations. Corrects nuspec comments that claimed Tabular was gated out. IDL de-duplication Tabular's IDL redeclared 8 Microsoft.UI.Xaml.CustomAttributes types; reference MUXC's unmerged winmd instead so the merge is clean. idl/dll split Tabular ran MIDL, mdmerge, XamlCompile and link in one project, so XamlCompile only ever saw pre-merge metadata. Split the metadata half into controls/idl-tabular, mirroring how MUXC separates controls/idl from controls/dev/dll. MergedWinMD consumes the unmerged winmd; the dll project runs XamlCompile against the merged public winmd. Theme resources Default styles resolved through the component's resource-map alias, ms-appx://TabularControlsAlias/. That authority does not exist in a consuming app: the app's build expands every reference PRI into its own resources.pri, which erases component root map names, so the lookup threw and took class activation down with it. Use an authority-less ms-appx:/// URI whose path matches AppxPriInitialPath, exactly as MUXC does in XamlControlsResources.cpp. Verified end to end against an external packaged app: UIA reports ControlType.DataGrid with a populated header and rows where it previously reported an empty rectangle and no descendants. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Tabular: import MUXC's property sheet instead of duplicating it controls\dev\dll-tabular\Microsoft.UI.Xaml.Common.props had drifted into a verbatim copy of controls\dev\dll\Microsoft.UI.Xaml.Common.props plus ten lines, so every MUXC build-setting change had to be mirrored by hand or the two binaries silently diverged. Import the MUXC sheet and keep only the Tabular delta: the MUXCONTROLS_TABULAR define and the conditional TABULAR_BINARY_EMITS_THEME_RESOURCES define. Imported by file-relative path rather than $(MUXCProjectRoot), because the Tabular vcxproj imports this sheet as its first import, before environment.props has defined that property. The MUXC sheet is safe to import from the sibling directory: its only non-property paths are GetPathOfFileAbove(environment.props), which resolves from the MUXC sheet's own location, and ScriptPath="..\..\tools\", which is project-relative and identical for both projects. Verified by rebuilding the Tabular DLL: same 4,209,664-byte output, zero errors. Also refreshes a TableView_themeresources.xaml comment that described theme-XBF emission as still disabled. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Tabular: add the metadata project to MUXControlsTabular.sln The solution listed only Microsoft.UI.Xaml.Controls.Tabular.vcxproj, so the metadata project split out alongside it, idl-tabular, was in no solution at all. Build order was unaffected -- MergedWinMD carries a build-order-only ProjectReference to the idl project, and the Tabular DLL carries one to MergedWinMD -- but the project was invisible to Visual Studio and to anything that enumerates the solution. Verified by building the solution: 0 errors. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Tabular: build from MUXControls.sln and retire the second solution Tabular built from its own MUXControlsTabular.sln with a second pipeline step, because the MUXC -> Tabular dependency was sequenced by step order rather than by the project graph: EnsureMuxcComponentWinMDBuilt only *asserts* that MUXC's component winmd is already on disk, and Tabular's references reached MUXC's idl project through MergedWinMD but never the controls DLL that emits that winmd. Declare the missing edge instead. The Tabular DLL now carries a build-order-only ProjectReference to controls\dev\dll\Microsoft.UI.Xaml.Controls.vcxproj, mirroring the one it already has to MergedWinMD. MUXC never references Tabular, so there is no cycle. With the graph complete, both Tabular projects join MUXControls.sln and the separate solution and its pipeline step are deleted as redundant. Verified by building the Tabular target through MUXControls.sln from the solution graph alone: 0 errors. A parallel build on a memory-constrained machine can hit C1076/C3859 while MUXC and Tabular compile together; -m:1 completes cleanly. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * TableViewSampleApp: correct the docs about package availability README.md and AGENTS.md both told readers TableView "is not yet available through the WindowsAppSDK NuGet package" and that the sample's workarounds "all disappear once the control ships in-box". Both statements are now false: the API reaches the public winmd, activation registrations are emitted, and the control's theme resources ship and resolve, so a packaged app can reference the package and use TableView with no workarounds. The sample's workarounds are not evidence of a product gap. The sample builds unpackaged and self-contained against raw build outputs so the control can be iterated on without a package round-trip, and that configuration is what requires them. Deleting them while the sample still links build outputs breaks it; they retire when the sample is re-pointed at the package. Docs only -- no build or behaviour change. The sample itself is unchanged, and was not rebuilt: this enlistment has no pack.cmd and no nuget.exe, so the mock aggregator package the sample restores against cannot be produced here. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Tabular: correct the idl project's note about MSB8028 The header comment said this project "intentionally shares controls\idl\" with the MUXC idl project and that the resulting MSB8028 was benign. That is not what the project does: it sets its own IntDir, and both IntDir and IntermediateOutputPath evaluate to BuildOutput\obj\<flavor>\controls\idl-tabular\. The MSB8028 that prompted the comment came from stale output -- .tlog and FileListAbsolute.txt files left in controls\idl\ by builds predating this project. Deleting the Tabular-named entries there clears the warning with no code change; both idl projects then build with 0 warnings. Comment only; no build or behaviour change. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * TableViewSampleApp: consume the package and delete the workaround machinery The sample hand-wired around the product: it linked raw build output, regenerated its own CsWinRT projection, injected a XAML metadata provider into the app provider's OtherProviders, seeded an internal template part through a never-loaded DataTemplate, compiled the control's theme resources from the control source tree, merged activatable-class registrations into its own app manifest, and staged the Tabular DLL next to the EXE. All of it existed because Tabular's type information was withheld from the public winmd and its theme resources did not resolve. Both of those are fixed, so the sample can be an ordinary consumer. Restructured on the ChartApp samples, which are the existing pattern for a separately-built control set: reference Microsoft.WindowsAppSDK.WinUI, and nothing else. Deleted: TabularMetadataProviderLoader.cs provider injection shim _SplitTypeSeed.xaml XamlTypeInfo seed for TableViewRow Build/MergeIxpAppManifest.ps1 activatable-class manifest merge Removed from the project file: the mock aggregator version override, the CsWinRT projection regeneration and its two targets, the theme-resource Page/Content items sourced from controls\dev, the Tabular DLL staging, and the IXP manifest augmentation block with its three targets. 232 lines to 60. App.xaml.cs drops the provider registration, the deferred resource merges and the diagnostic logging, leaving the standard OnLaunched. App.xaml merges the control's own TabularControlsResources instead of two dictionaries copied from the control source. Verified: builds clean (0 errors) and runs. Every page renders, and the Playground shows text, template, date-picker and image columns bound to live data. The app's own PRI is 3.5 MB, so MUXC's and Tabular's resources both fold into the app resource map as designed. No projection regeneration, no manifest injection, no theme resources compiled from the repo, and no reference into the control tree. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * TableViewSampleApp: rewrite the docs for a sample with no workarounds README.md and AGENTS.md documented a build that no longer exists: staging the control DLL, regenerating the projection, compiling theme resources from the control source, self-contained unpackaged layout, and the IXP manifest merge. Rewritten for what the sample now is -- an ordinary consumer of Microsoft.WindowsAppSDK.WinUI, modelled on the ChartApp samples. Documents the two things a reader actually needs: merge TabularControlsResources alongside XamlControlsResources, and expect CS8305/WMC1501 because TableView is MUX_PREVIEW. AGENTS.md keeps a short record of what the removed machinery was and lists the three product invariants to check if anyone ever needs it back, so the history is not lost with the code. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Tabular: scrub an internal reference and drop the now-dead alias macro Three review findings against this branch. OSS-safety: Microsoft.UI.Xaml.Controls.Tabular.vcxproj carried "See OSClient PR 16542065" in a comment. This repo mirrors publicly and comments mirror verbatim, so an internal PR number must not ship. Rewritten to keep the technical substance with no internal marker. Correctness: the same comment, and one in BuildMacros.h, asserted that resources resolve through the component's resource-map alias rather than ms-appx:///, because ms-appx:/// "would bind to the hosting process's package". The control now does exactly the opposite, deliberately: a consuming app's build expands every referenced PRI into its own resources.pri and drops component root-map names, so binding to the hosting process's package is what works. Both comments now describe shipped behaviour and point at TabularControlsResources.cpp. Dead code: MUXTABULARALIAS_STR had zero references once the URIs stopped using it -- one occurrence in the tree, its own definition. Removed. The XamlResourceMapName and ProjectPriIndexName properties keep the alias string, since those still name the root map of the standalone .pri. Build verified: 0 warnings, 0 errors. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Tabular: drop the vestigial PRI alias properties and scrub an internal bug ID XamlResourceMapName and ProjectPriIndexName named the standalone PRI's root map "TabularControlsAlias". Nothing consumes that name: the control resolves its default style through an authority-less ms-appx:/// URI, and a consuming app's build re-indexes the component PRI into its own resources.pri, discarding component root map names entirely. Verified rather than assumed. With both properties removed the emitted theme XBFs are byte-identical (all five SHA-256 hashes match) and the only PRI difference is the root map name, which falls back to the target name; the resource paths the runtime URI depends on are unchanged. MUXC sets neither property and its root map is "Microsoft.UI.Xaml", so defaulting is also the WinUI-consistent shape. AppxPriInitialPath and AppxPrependPriInitialPath stay -- those are load-bearing, since they place the XBFs at the path the default-style URI resolves. Comment added saying so, because this is the pair that actually matters. Also drops an internal bug ID from a pch.h comment. This repo mirrors publicly and comments mirror verbatim; the technical note is kept, the identifier is not. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * TableViewSampleApp: remove the last mock-era leftovers Four source files aliased every Tabular type, each with a comment saying the alias existed to "disambiguate the real split-binary type from the stale mock projection". That mock projection is gone, so the claim was tested rather than trusted: replacing an alias with a plain namespace import compiles with no CS0104. Microsoft.UI.Xaml.Controls and Microsoft.UI.Xaml.Controls.Tabular now coexist in the same file with no ambiguity, so there is no collision to disambiguate. Aliases replaced with a namespace import and the comments deleted. App.xaml no longer merges TabularControlsResources. Verified by removing it: all eight column headers and the rows still render, because the control resolves its own theme resources. The earlier belief that consumers must merge it came from changing two things at once -- adding the dictionary and declaring columns in the same step. It was the columns that mattered. Both docs corrected; they had been instructing readers to merge a dictionary they do not need. Also drops "Real" from a Playground label that distinguished the control from a mock that no longer exists. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Samples: add a TableView consumer matrix for C#/C++ x packaged/unpackaged Four minimal apps that consume TableView the way a customer would, modelled on the ChartApp samples, which are the existing pattern in this repo for a separately-built control set. Each references Microsoft.WindowsAppSDK.WinUI and nothing else, and App.xaml merges only XamlControlsResources: no projection regeneration, no manifest injection, no theme resources compiled from the control source, no staged DLL, no type seed, and no project reference into the control. Each app instantiates TableView twice on purpose. One comes from markup, exercising XamlTypeInfo and XAML-driven activation; the other is built in code-behind, exercising direct WinRT activation. Those paths fail independently, and the defect this matrix guards against was an activation and default-style failure, so both are covered. The C# apps bind with a classic {Binding} against a plain class. The C++ apps use TableViewTemplateColumn with x:Bind against a Person runtimeclass. That asymmetry is a C++/WinRT rule, not a control limitation: classic {Binding} resolves properties by reflection in .NET, but C++/WinRT needs an IXamlType, which the XAML compiler emits only for types it sees in markup, or an explicit ICustomPropertyProvider. A data type built purely from code has neither, so {Binding} silently resolves nothing and cells render empty while headers, rows, grid lines and theming all look correct. The README records this so the next person does not read it as a control bug. Preview-API warnings are left visible here, unlike TableViewSampleApp which suppresses CS8305 because it fires 324 times across the full API surface. The README states that split so it reads as a choice. All four build clean and run; the C# pair and the C++ packaged app were confirmed rendering bound data in both their tables. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Tabular: trim the build comments to what a reader needs The comments added with the idl/dll split and the theme fix had grown into prose -- rationale, history and reasoning that belonged in the PR, not the tree. Cut to the facts a maintainer needs at the point of change, with the reasoning left to the commits that introduced it. No behaviour change; build verified 0 warnings, 0 errors. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Samples: shorten the x:Bind note in the C++ apps The inline explanation duplicated the README. Left the fact and the pointer. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Tabular: ship the Tabular DLL in the XamlProduct payload CI failed every packaged app with APPX0703: "Manifest references file Microsoft.UI.Xaml.Controls.Tabular.dll which is not part of the payload." Publishing Tabular's winmd made eng\winrtclassregistration.targets emit its activatable-class registrations into consuming app manifests, but nothing added the DLL those registrations name to the payload. eng\consumebinaries.targets lists Microsoft.UI.Xaml.Controls.dll in @(XamlProduct) and had no Tabular counterpart, so every packaged app advertised a binary it did not carry. Charts, the closest precedent, keeps both halves together and gates each on the same Exists() condition -- a metadata entry with ImplementationDll in productmetadata.props and a binary entry in WinUIDetailsBinaries -- so its registrations and payload cannot desync. Tabular had only the metadata half. Verified by building a packaged sample that CI failed on: 0 errors, and both Microsoft.UI.Xaml.Controls.dll and Microsoft.UI.Xaml.Controls.Tabular.dll are now in the app payload. The existing Error condition on @(XamlProduct) also means a missing Tabular binary now fails with a clear message instead of an APPX0703 at packaging. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Tabular: declare the idl project's dependency on MUXC's unmerged winmd Tabular.ProjectImports.targets feeds MIDL a path to MUXC's unmerged winmd from dev\dll for the Microsoft.UI.Xaml.CustomAttributes types this IDL stopped redeclaring, but the idl project had no ordering edge to the project that produces it. Step order in the pipeline used to guarantee it; retiring the second solution removed that guarantee, leaving a clean-build race. An x86 build surfaced it as 52 x MIDL2009 "undefined symbol Microsoft.UI.Xaml.CustomAttributes.MUXPropertyDefaultValue". Build-order-only reference, mirroring the one the Tabular DLL project already has. MUXC's DLL project references only Lightup, so this is not a cycle. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Samples: bind the markup TableView's ItemsSource from XAML The markup-instantiated table had its ItemsSource assigned from code-behind, which left the markup path only partly exercised: the control came from XAML but its data did not. All four apps now bind it with x:Bind, so the markup table is driven entirely from markup and the code-behind table stays the pure code path. C# exposes a People property; C++ exposes it through MainWindow.idl backed by an IObservableVector. In both, People is populated before InitializeComponent, since x:Bind evaluates there -- populate it after and the markup table silently binds to nothing while the code-built table still works. Verified on all four: each window reports 2 TableView elements and 6 TableViewRow elements, 3 from the markup table and 3 from the code table. A failed markup binding would show 3. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Tabular: correct the XamlProduct comment The comment claimed this entry keeps packaging from failing with APPX0703. It does not. @(XamlProduct) drives an existence check; the payload copy is done by _UpdateMUXFilesToCopyForApp above, via a wildcard over Product\*.dll that already covered Tabular. The entry is still worth keeping as a validation, but it is not a payload fix and the comment should not say otherwise. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Tabular: make the packaging project depend on the Tabular DLL The WinUI component package could ship Tabular's activatable-class registrations without shipping Tabular's DLL. Every consuming .wapproj then failed packaging with APPX0703: "Manifest references file Microsoft.UI.Xaml.Controls.Tabular.dll which is not part of the payload." The packaging project had exactly one ordering edge, to MergedWinMD. MergedWinMD depends on Tabular's *idl* project, which is enough to produce the merged winmd and therefore the registrations -- those are architecture-independent and always name Tabular.dll -- but nothing pulled in the DLL project that produces the binary. The payload is per-architecture and came up empty for Tabular. Reproduced by clearing the staging directory and building only the packaging project, as the pack step does: Microsoft.UI.Xaml.Controls.dll and both .pri files were restored, Microsoft.UI.Xaml.Controls.Tabular.dll was not. With this build-order-only reference the same experiment stages the Tabular DLL. Not a cycle: the Tabular DLL project depends on MergedWinMD and MUXC's controls DLL, neither of which depends on packaging. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Tabular: address PR review nits Three comment nits from review. The two nuspec comments noting that an existing wildcard also picks up Tabular's winmd and dll/.pri restated what the pattern plainly does, and would need touching for every future component. Removed, including the second identical one in the WinUI nuspec that was not flagged but is the same noise. The file entries are unchanged. BuildMacros.h cited a bare "PRI277 collision", which explains nothing on its own. Reworded to state the collision in words; the error code stays in the Tabular vcxproj where the surrounding detail lives. Comment-only; build verified 0 warnings, 0 errors. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Samples: label which TableView comes from markup and which from code Both tables rendered identically, so the sample did not actually show what it was demonstrating. Each now sits in its own captioned grid: "Table 1 - instantiated from MARKUP (XAML)" and "Table 2 - created in CODE-BEHIND". A nested Grid with Auto/* rows rather than a StackPanel, so the caption takes its natural height and the table still stretches; a StackPanel would give the table unbounded height. The status line said "markup TableView: True; code TableView: 1; items: 3" -- a null check and a child count rendered as text, which the captions now convey far better. Replaced with the one thing the captions do not say: that both tables are bound to the same items. All four build clean and run. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Tabular: fix the Pass2 winmd snapshot and merge TabularControlsResources Two defects kept TableView from being consumable, one at build time and one at runtime. Build: Microsoft.UI.Xaml-Product.sln failed in the Tabular project with error WMC1006: Cannot resolve Assembly or Windows Metadata file 'Type universe cannot resolve assembly: winrtbase, Version=255.255.255.255' followed by two MSB3030 errors for the generic.xaml and themeresources.xaml the failed compile never produced. CompilePageRequiringCustomCompilation already drops the pre-merge winmds from @(ReferencePath), which is what Pass1 consumes. Pass2 does not read that item: for native projects the SDK's MarkupCompilePass2 has already snapshotted its references into @(XamlReferencesToCompile), by way of @(WinMDReferenceToCompile), before this target runs. That snapshot still carried MUXC's unmerged winmd, and unmerged winmds reference the midlrt 'winrtbase' placeholder that only mdmerge resolves, so Pass2 failed while Pass1 succeeded. Apply the same three filters to the snapshot. Runtime: every sample crashed roughly eight seconds after launch with a 0xC000027B stowed exception, from a XamlParseException (0x802B000A) raised during the first layout pass: Cannot find a Resource with the Name/Key SortIndicatorForeground TableView's column-header style resolves SortIndicatorForeground through SortIndicator's default style, and SortIndicator ships in the Tabular DLL rather than in MUXC - controls/Tabular.ProjectImports.targets is the only importer of SortIndicator.vcxitems. The key is therefore defined in Tabular's themeresources.xaml and absent from MUXC's, so merging XamlControlsResources alone leaves it unresolvable. Merge TabularControlsResources alongside it. That dictionary is Tabular's own theme resources and the exact analogue of XamlControlsResources for MUXC, so this is ordinary consumption of the control set rather than an app-side workaround. Verified against a locally built package: all five apps launch and render, with TableView reporting ControlType.DataGrid and non-empty bounds from UIA in the C# and C++, packaged and unpackaged shapes. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Tabular: guarantee MergedWinMD is built before XamlCompile WMC1006 ('cannot resolve assembly: winrtbase') and the two MSB3030 errors for the generic.xaml and themeresources.xaml that never got produced are a build ordering failure, not a reference-filtering one. The previous attempt filtered @(XamlReferencesToCompile) and had no effect; revert it. In build 156031576, mdmerge wrote MergedWinMD's public output at 21:22:36 while Tabular's XamlCompile Pass2 ran at 21:16:38, six minutes earlier. Pass2 resolves against $(MUXCXamlConsumeWinmd), which is that output, so it was absent. Pass1 survives because only Pass2 is given LocalAssembly - this project's own unmerged winmd - and only Pass2 therefore has to resolve that assembly's midlrt 'winrtbase' placeholder. The ordering-only ProjectReference to MergedWinMD does not prevent this. packaging\Microsoft.WinUI.csproj lists MergedWinMD and this project as sibling ProjectReferences with DisableTransitiveProjectReferences set, so MSBuild schedules them concurrently and Tabular never blocks on it. MUXC does not hit this because its Pass2 references $(IntermediateOutputPath)Merged\Microsoft.winmd - an artefact its own project produces, which cannot race. Tabular's equivalent reference crosses a project boundary. Build MergedWinMD on demand when its output is missing, then fail with a clear message rather than letting the compiler fall through to WMC1006. Where another node is already building it with these properties, MSBuild blocks here instead of racing. Validated locally: a clean build.cmd /c build succeeds, and deleting the merged winmd and rebuilding this project alone with BuildProjectReferences=false - so nothing else can produce it - restores it through this target and completes Pass2 with no WMC1006 or MSB3030. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Samples: move the TableView consumer matrix to a follow-up change This change is large enough already. The four-app consumer matrix under Samples\TableViewApp (C# and C++, packaged and unpackaged) is additive and reviews better on its own, so it moves to a follow-up pull request that lands after this one. TableViewSampleApp stays. Its docs no longer point at the matrix, and both the README and AGENTS.md are corrected on one point they got wrong: consuming TableView does require merging TabularControlsResources alongside XamlControlsResources. SortIndicator ships in the Tabular DLL rather than in MUXC, so SortIndicatorForeground - which TableView's column-header style resolves - is absent from MUXC's dictionary, and omitting the merge throws XamlParseException 0x802B000A on the first layout pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Tabular: keep midlrt winmds out of XamlCompile and supply the merged one Pass2 failed with WMC1006 'cannot resolve assembly: winrtbase'. Reading the assembly-reference tables shows why: Tabular's metadata carries an AssemblyRef to microsoft.ui.xaml.controls.g, MUXC's unmerged winmd, which itself references the midlrt winrtbase placeholder that only mdmerge strips. Pass2 loads LocalAssembly, follows that reference and cannot resolve it. Pass1 is given no LocalAssembly, so it never walks the reference and succeeds. MUXC never hits this because its metadata has no cross-reference to another unmerged winmd. The cross-reference comes from the IDL de-duplication in Tabular.ProjectImports.targets, which points MIDL at MUXC's unmerged winmd so the shared CustomAttributes resolve there instead of being redeclared. Filter midlrt outputs by extension rather than by directory. The previous attempt matched on 'Unmerged' appearing in the path and missed controls\idl-tabular\Microsoft.UI.Xaml.Controls.g.winmd, a copy with no such segment. Apply the filters to @(XamlReferencesToCompile) as well, since that is the snapshot Pass2 reads rather than @(ReferencePath). Filtering also removes Tabular's own types, so pass this project's mdmerge output alongside, mirroring controls/dev/dll/Microsoft.UI.Xaml.Common.targets:489 where MUXC's Pass2 references its own Merged\Microsoft.winmd. It is guarded by Exists() and is produced before this target runs. Also drops the previous attempt's guard, which never executed: it hooked MarkupCompilePass2, a target skipped for this project. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Tabular: keep the control out of MUXFinalRelease packaging WMC1006 fails only in BuildMUX Debug_x64, the one job that builds Microsoft.UI.Xaml-Product.sln, and only with MUXFinalRelease=true. The other five jobs build MUXControls.sln and never reach this path, so their passing said nothing. Product.sln has no Tabular project of its own: the control arrives solely through packaging\Microsoft.WinUI.csproj's ProjectReference, added so the package could not ship Tabular registrations without the Tabular binary. Every Tabular type is [MUX_PREVIEW] or [MUX_INTERNAL], both of which expand to feature(Feature_Experimental). eng\muxfinalrelease.props leaves MUX_PRERELEASE undefined for a final release, which makes that feature AlwaysDisabled, so mdmerge -createPublicMetadata cuts the public winmd from 93 types to 6 - only TabularControlsResources and the metadata provider survive. The project then still compiles generic.xaml, whose TargetTypes no longer exist, and XamlCompile fails; the two MSB3030 errors are the themes that compile never produced. Condition the ProjectReference on MUXFinalRelease != true. The reason it was added does not apply there: registrations derive from the same stripped metadata, so a final-release package emits no Tabular registrations and there is nothing for APPX0703 to report. Also reverts the previous attempt, which supplied $(StrippedMetadataWinmdPath) to XamlCompile. That file is the 6-type winmd above, so it was actively wrong in the flavour that fails. Measured in a clean local build with MUXFinalRelease=true - the configuration CI uses and the one no earlier attempt was ever tested against. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Tabular: drop the metadata and registrations in MUXFinalRelease too Excluding Tabular from the MUXFinalRelease package left the flavour inconsistent: the binary was no longer built, but 16 activatable-class registrations naming Microsoft.UI.Xaml.Controls.Tabular.dll were still emitted. That is the APPX0703 mismatch the packaging ProjectReference was added to prevent, just inverted. The registrations derive from MuxControlsWinMD, which points at the unmerged winmd from the idl project - 93 types, unaffected by feature gating - not at the 6-type stripped winmd that mdmerge -createPublicMetadata produces once Feature_Experimental is AlwaysDisabled. So they survived the packaging change. Condition the MuxControlsWinMD entry on MUXFinalRelease != true so metadata, registrations and binary are dropped together and the flavour stays self-consistent. Verified by clean builds in both flavours: MUXFinalRelease=true - builds clean, Tabular registrations 0, no Tabular.dll, public winmd 3083 types with 0 Tabular MUXFinalRelease=false - builds clean, Tabular.dll present, registrations 16, public winmd 3379 types with 70 Tabular Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Tabular: note when the MUXFinalRelease exclusion must be revisited Both conditions hold only while every Tabular type is preview. Once TableView leaves [MUX_PREVIEW] its types survive final-release stripping, and the conditions would silently keep the control out of the release package - no build error, no test failure, just a missing control. Say so at both sites so the next person changing that attribute sees it. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Restore the UTF-8 BOMs and trim the MUXFinalRelease comments Five files lost their BOM during editing - MergedWinMD\Directory.Build.props, controls\MUXControls.sln, TabularControlsResources.cpp, BuildMacros.h and packaging\Microsoft.WinUI.csproj. That is unintended diff noise, and .sln files in particular are BOM-sensitive for Visual Studio tooling. Also shortens the two MUXFinalRelease comments; the detail belongs in the commit message rather than the build files. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>