Skip to content

TableView: first-class Reactor control + a 36-page gallery mirroring TableViewSamples (POC)#621

Draft
DDancingDeath wants to merge 21 commits into
microsoft:mainfrom
DDancingDeath:user/hik/tableview-reactor-demo
Draft

TableView: first-class Reactor control + a 36-page gallery mirroring TableViewSamples (POC)#621
DDancingDeath wants to merge 21 commits into
microsoft:mainfrom
DDancingDeath:user/hik/tableview-reactor-demo

Conversation

@DDancingDeath

@DDancingDeath DDancingDeath commented Jun 21, 2026

Copy link
Copy Markdown

Status: draft / proof-of-concept. Self-contained under samples/, gated OFF in shared CI, x64-only. No change to any existing Reactor project's every-PR build.

What this adds

A first-class Reactor (MVU) control for the native split-binary WinUI Microsoft.UI.Xaml.Controls.TableView (shipped in Microsoft.UI.Xaml.Controls.Advanced.dll), plus a 36-page gallery in Reactor.TestApp that mirrors the native TableViewSamples gallery — every page rendering for real (cells + headers + colored pills/chips/stoplight tints).

1. The consumable control — Reactor.Controls.TableView

Any Reactor consumer can drop in TableView(items, columns) in pure C#. It is reconciled by a real TableViewHandler (mount/update/unmount on a pooled control), not a XAML island:

  • Text + template columns (CellStyle.Text/Pill/Chip/Tint) via a cell-template bridge + value converter.
  • Sort + filter honoring the control's consumer-owned re-shape contract: header clicks raise Sorted/Filtered; the handler re-orders/-filters the bound ObservableCollection from a master snapshot (columns get a SortMemberPath automatically).
  • Selection (mode + unit + gutter, OnSelectionChanged), frozen leading/trailing, grid lines, headers visibility, column resize/reorder, hierarchy (HierarchicalItems + HierarchicalChildrenPath + ExpandFirstLevel), row banding, RTL, and an OnControlReady hook to drive imperative APIs (SortByColumn, SelectAll, AutoSizeColumn, ExpandAllGroups, …).
  • Stretch-to-fill layout; live updates work in place (an observable row model raises PropertyChanged so bound tint cells re-run their converter without a re-bind).

2. The gallery — first-class, mirrors the reference

Reactor.TestApp gets a TableView section: a NavigationView shell with the reference's grouped sections (Quick start / Columns / Rows & cells / Styling / Power user / Performance / About) and all 36 pages. Each page has the reference SamplePresenter chrome: heading + description + a "Try it" InfoBar + an interactive Options panel (combos/toggles/radios/sliders/buttons + live Status readouts) + the live table + a collapsible "Source code (C#)" section showing the page's key Reactor usage.

How it renders in a code-only host

The dev-framework-built satellite renders blank in a framework-dependent host. Fixes:

  • WindowsAppSDKSelfContained=true when the TableView path is on (the activation ABI must match) — the key fix that makes the body realize.
  • Register the satellite's XAML metadata provider once, merge its embedded Style/theme closure into Application.Resources exactly once (two copies access-violate the next Frame.Navigate), assign the default Style explicitly, and install a DispatcherQueueSynchronizationContext so the control's realization continuations resume on the UI thread.

Native binaries (both flavors, x64-only)

The satellite is checked in as both flavors and selected by sample $(Configuration):

  • native\fre\fre (free/optimized) → Release builds, for performance.
  • native\chk\chk (checked/asserts) → Debug builds, for debugging.

Built from the separate-binary control PR (advanced-binary-poc-v2), which folds in the canonical Advanced control branch.

CI safety

The TableView projects are not in Reactor.slnx; IncludeTableView defaults OFF in shared CI (GITHUB_ACTIONS) and on non-x64, so every existing Reactor PR build stays byte-identical. An on-demand workflow (tableview-control.yml) builds + best-effort UIA-validates the integration.

Review feedback addressed

  • Metadata provider now registered exactly once (cached instance + guard) regardless of caller.
  • Layout sizing respects framework modifiers: element Height is nullable (written only when explicitly set, else .Height()/Stretch win); the vestigial element-level MinWidth was removed.
  • TableView path is x64-only: IncludeTableView auto-off on non-x64 + a build-time guard; the control package restricted to x64 (the native asset is win-x64 only).

hiteshkrmsft and others added 6 commits June 22, 2026 00:57
…ppSDK 2.0.1)

Adds samples/apps/tableview-demo: a self-contained Reactor app that hosts the
native C++/WinRT TableView -- built as a separate satellite binary
(Microsoft.UI.Xaml.Controls.Advanced.dll) and projected to C# via CsWinRT
against public WinAppSDK 2.0.1 -- live inside the Reactor mount path.

Contents:
- App.cs / Program.cs: Reactor Component rendering TableView(Data)
- TableViewFacade.cs: the TableView(...) DSL facade via XamlHostElement
- TableView.Projection/: CsWinRT projection of the native component winmd
- Microsoft.UI.Xaml.Controls.Advanced.dll: the native satellite control (Content; POC artifact)
- app.manifest: embedded WinRT activation mapping to the satellite DLL
- selftest.ps1 + .github/workflows/tableview-demo.yml: headless self-test that
  asserts native activation inside the Reactor mount. On-demand CI, path-scoped
  to this folder so it never burdens the main Reactor build.

Isolated from Reactor.slnx, so the main solution and its every-PR CI are
unaffected. Consumes the split-binary control from microsoft-ui-xaml-lift
PR #15930004. Verified: dotnet build green + selftest PASS (native TableView
activated + 3 auto-columns + ItemsSource set).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replaces the raw XamlHostElement facade with a proper first-class Reactor
control, following the opt-in third-party-control pattern documented on
Microsoft.UI.Reactor.Advanced.Factories:

- Reactor.Controls.TableView/ (new library):
  - TableViewElement : Element -- typed record (Items, Columns, SelectionMode,
    SelectedIndex, OnSelectionChanged).
  - TableViewHandler : IElementHandler<TableViewElement, TableView> -- mounts /
    diffs / unmounts the native control; reconciles columns + ItemsSource +
    selection as minimal writes on a pooled instance.
  - Factories -- registers the handler via ControlRegistry.Register in a static
    ctor (per-library trim unit) + TableView(...) DSL factories.
- Kept OUT of core src/Reactor (core must not depend on the POC control binary);
  consumes the control purely through the public extensibility API.
- Demo App.cs now renders the typed TableView(Data); removed TableViewFacade.cs.

Also fixes a latent Central Package Management violation: the demo + projection
carried explicit Version= on PackageReference (NU1008 on a clean restore, which
would fail the on-demand CI). Switched to CPM form (central WinAppSDK version;
VersionOverride for CsWinRT).

Verified: dotnet build green (0 warn / 0 err) + selftest PASS (native TableView
activated + 3 columns + ItemsSource via the first-class TableViewHandler).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…I.Reactor.TableView)

Makes Reactor.Controls.TableView packable so consumers reference the native control
via a single PackageReference instead of a committed binary. The package bundles:
- lib/: the first-class control + the CsWinRT projection (bundled via
  TargetsForTfmSpecificBuildOutput; not a separate package)
- runtimes/win-x64/native/: the native Microsoft.UI.Xaml.Controls.Advanced.dll
  (NuGet auto-deploys it next to the consumer exe)
- build/: a .targets + app.manifest that supply the WinRT activation manifest when
  the consumer has not declared one
- deps: Microsoft.UI.Reactor + Microsoft.WindowsAppSDK

pack-and-verify.ps1 packs core Reactor + this package to a local feed, scaffolds an
external consumer that references ONLY the package, builds it, and runs it headlessly
-- asserting the native control activates through the package.

Verified: package structure correct; external consumer builds green; headless
selftest PASS (native TableView activated + 3 columns + ItemsSource via the
first-class handler, deployed entirely from the package).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The first-class control activated with data but rendered a blank body in a
code-only Reactor app (no XAML-compiled metadata). Fixed with three pieces, all
self-contained in the control library/package so it renders out of the box for
both ProjectReference and PackageReference consumers:

1. Register the satellite XAML metadata provider via
   ReactorApp.RegisterControlAssembly so the WinUI XAML loader resolves
   controls:TableView (+ the template's primitive types) when the style closure
   is parsed -- a code-only app has no compiler-generated provider to auto-chain.
2. Embed + apply the control's default Style/theme closure (Styles/*.xaml):
   parsed into Application.Resources and assigned explicitly (implicit lookup
   misses a loose satellite control), so the template inflates.
3. Merge the control's localized SR_TableView* strings into the app PRI
   (TableViewStrings/ + post-build makepri); public WinAppSDK 2.0.1's PRI lacks
   them and native row/header realization throws without them. The package's
   build/.targets does the same merge for package consumers.

Verified: 12-row grid renders headers + cells (RenderTargetBitmap, TVDEMO_SHOT);
pack-and-verify.ps1 now also asserts the packaged consumer RENDERS (not just
activates) -- RENDER cells=15 through a pure PackageReference. Demo render uses
the typed explicit-columns API. README documents the mechanism.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…tes)

The blank-body bug taught us activation != rendering, but the CI selftest only
checked activation. Adds a render gate: runs the demo with TVDEMO_SHOT=1, which
walks the control's visual tree (composition-independent, survives headless
agents) and asserts >=6 rendered cells -- guarding the regression where the
satellite control activates but its Style/template never inflates (blank body).

Verified: PASS -- activated AND rendered 42 cells.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…p standalone demo)

Per review feedback ("adding to the existing gallery should have been enough"),
host the native C++/WinRT TableView sample inside the existing Reactor.TestApp
gallery as a new "TableView" tab instead of a separate standalone app.

- Reactor.TestApp gains a TableView tab hosting the full 36-page TableViewSamples
  gallery (TableViewSamples.Embedded) via XamlHostElement, rendering the projected
  native split-binary Advanced TableView. Verified: Showcase = 16 rows + 9 column
  headers via UIA + screenshot.
- Gated behind -p:IncludeTableView: default ON locally + the on-demand
  tableview-gallery workflow; default OFF when GITHUB_ACTIONS=true so the shared
  every-PR 'dotnet build Reactor.slnx' is unaffected. App.cs guards the tab with
  #if INCLUDE_TABLEVIEW.
- Shared TableView.Projection relocated to samples/TableView.Projection/.
- Removed the standalone samples/apps/tableview-demo app + the first-class
  Reactor.Controls.TableView library/NuGet (superseded by the in-gallery sample).
- Fixed a latent CPM NU1008 (WindowsAppSDK Version=) in the embedded gallery csproj.
- Replaced tableview-demo.yml with tableview-gallery.yml + a gallery selftest
  (builds with the gallery ON, best-effort UIA render check).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@DDancingDeath DDancingDeath force-pushed the user/hik/tableview-reactor-demo branch from dc9c6e4 to 103240d Compare June 22, 2026 14:45
…p (drop embedded gallery)

Final shape per review intent: "show tableview control in the reactor sample" +
"expose tableview control reactor consumers use" + "no separate demo sample app".

- Consumable first-class control as a library: samples/Reactor.Controls.TableView
  (TableViewElement + TableViewHandler + ControlRegistry registration + embedded
  Style/theme closure + code-only-host rendering enablement). This is what a Reactor
  consumer references and uses:
      using static Reactor.Controls.Factories;
      TableView(items, columns)
- Reactor.TestApp's "TableView" tab consumes that control (Demos/TableViewControlDemo.cs)
  exactly as a consumer would -- a directory of 12 people x 4 typed columns.
- Dropped the embedded TableViewSamples gallery (XamlHostElement host): it cannot
  coexist with the control library in one process -- loading the control crashed the
  gallery's SampleShell -> Frame.Navigate (WinRT/WinAppSDK activation conflict via the
  shared projection, 0xC0000005). The first-class control is the cleaner Reactor-native demo.
- Fixed the library's Reactor P2P ref (removed GlobalPropertiesToRemove, which produced an
  inconsistent Reactor build that crashed the WinAppSDK runtime under a self-contained host).
- Still gated behind -p:IncludeTableView (default ON local + on-demand tableview-control.yml;
  OFF when GITHUB_ACTIONS=true) so the every-PR Reactor.slnx build is unaffected.

Verified: TestApp ON build 0 errors + UIA = 12 rows x 4 headers (Name/Age/City/Role), stable;
full 'dotnet build Reactor.slnx -c Release' with GITHUB_ACTIONS=true = 0 errors (CI-safe;
control + projection are not in the slnx).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@DDancingDeath DDancingDeath changed the title [Sample][POC] TableView-in-Reactor demo (native split-binary control, WinAppSDK 2.0.1) [Sample][POC] Native TableView as a first-class Reactor control (shown in Reactor.TestApp) Jun 22, 2026
@azchohfi azchohfi requested a review from Copilot June 22, 2026 17:31

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 adds a proof-of-concept “first-class” Reactor control wrapper for the native split-binary WinUI Microsoft.UI.Xaml.Controls.TableView (from Microsoft.UI.Xaml.Controls.Advanced.dll), plus a gated integration/demo in Reactor.TestApp and an on-demand GitHub Actions workflow to build/self-check it without impacting every-PR CI.

Changes:

  • Introduces Reactor.Controls.TableView (element + V1 handler + factories) and embeds the control’s style/theme closure so it can render in code-only Reactor hosts.
  • Adds a gated “TableView” tab to Reactor.TestApp, including WinRT activation manifest + PRI string merge to satisfy the native control’s localized string lookup.
  • Adds a CsWinRT projection project and an on-demand workflow/script to build and (best-effort) validate UIA rendering.

Reviewed changes

Copilot reviewed 26 out of 28 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
samples/TableView.Projection/TableView.Projection.csproj CsWinRT projection project for the satellite control winmd.
samples/Reactor.TestApp/TableViewStrings/Resources.resw Localized strings required by native TableView (merged into PRI).
samples/Reactor.TestApp/TableViewStrings/merge-tableview-strings.ps1 Post-build PRI merge script for TestApp.
samples/Reactor.TestApp/tableview-control-selftest.ps1 On-demand build + best-effort UIA render self-test script.
samples/Reactor.TestApp/Reactor.TestApp.csproj Gated IncludeTableView wiring, references, native DLL content, PRI merge target.
samples/Reactor.TestApp/GlobalUsings.TableView.cs Alias to avoid SortDirection ambiguity with the projection.
samples/Reactor.TestApp/Demos/TableViewControlDemo.cs New TestApp demo tab consuming the control as a library user would.
samples/Reactor.TestApp/app.manifest WinRT activation manifest mapping runtime classes to Advanced.dll.
samples/Reactor.TestApp/App.cs Adds conditional TableView tab + default tab selection when enabled.
samples/Reactor.Controls.TableView/TableViewStyles.cs Registers metadata provider + merges embedded style/theme closure + applies style.
samples/Reactor.Controls.TableView/TableViewHandler.cs V1 element handler (mount/update/unmount, columns, items, selection event).
samples/Reactor.Controls.TableView/TableViewElement.cs New Reactor element record + column definition for TableView.
samples/Reactor.Controls.TableView/Styles/07_TableView.xaml Embedded default style/template for TableView/TableViewRow.
samples/Reactor.Controls.TableView/Styles/06_EditableContentPresenter.xaml Embedded template for a TableView primitive.
samples/Reactor.Controls.TableView/Styles/05_SortIndicator.xaml Embedded template for sort indicator primitive.
samples/Reactor.Controls.TableView/Styles/04_MarqueeSelector_themeresources.xaml Theme resources for marquee selection.
samples/Reactor.Controls.TableView/Styles/03_SortIndicator_themeresources.xaml Theme resources for sort indicator + badge.
samples/Reactor.Controls.TableView/Styles/02_TableView_themeresources.xaml Theme resources for TableView surface/metrics + keyed styles.
samples/Reactor.Controls.TableView/Styles/01_TabularSurfaces_themeresources.xaml Shared tabular-surface theme tokens embedded with the control.
samples/Reactor.Controls.TableView/Reactor.Controls.TableView.csproj Packable control library project + embeds styles + packs native/targets artifacts.
samples/Reactor.Controls.TableView/Factories.cs Factories + handler registration via ControlRegistry.
samples/Reactor.Controls.TableView/build/Resources.resw Packaged strings for consumers (merged during build via targets).
samples/Reactor.Controls.TableView/build/Microsoft.UI.Reactor.TableView.targets Consumer build targets (manifest + PRI string merge).
samples/Reactor.Controls.TableView/build/merge-tableview-strings.ps1 Packaged PRI merge script for consumers.
samples/Reactor.Controls.TableView/build/app.manifest Packaged WinRT activation manifest for consumers.
.github/workflows/tableview-control.yml On-demand workflow to build/self-test the gated TableView integration.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +35 to +47
private static bool s_init;
private static Style? s_tvStyle;
private static readonly object s_gate = new object();

/// <summary>Diagnostic status of the last init attempt (surfaced by the demo selftest).</summary>
internal static string Status { get; private set; } = "(not initialized)";

/// <summary>Registers the satellite XAML metadata provider. Idempotent; safe to call early.</summary>
internal static void RegisterMetadata()
{
try { ReactorApp.RegisterControlAssembly(new AdvancedXamlMetadataProvider()); }
catch (Exception ex) { System.Diagnostics.Debug.WriteLine("[TableViewStyles] register failed: " + ex); }
}
Comment on lines +40 to +45
/// <summary>Layout height of the hosted control.</summary>
public double Height { get; init; } = 360;

/// <summary>Minimum layout width of the hosted control.</summary>
public double MinWidth { get; init; } = 520;

Comment on lines +30 to +34
Reconciler.SetElementTag(tv, el);

tv.Height = el.Height;
tv.MinWidth = el.MinWidth;
if (el.SelectionMode is { } mode)
Comment on lines +64 to +67
if (oldEl.Height != newEl.Height)
tv.Height = newEl.Height;
if (oldEl.MinWidth != newEl.MinWidth)
tv.MinWidth = newEl.MinWidth;
Comment on lines +24 to +28
<PropertyGroup>
<IncludeTableView Condition="'$(IncludeTableView)' == '' and '$(GITHUB_ACTIONS)' == 'true'">false</IncludeTableView>
<IncludeTableView Condition="'$(IncludeTableView)' == ''">true</IncludeTableView>
<DefineConstants Condition="'$(IncludeTableView)' == 'true'">$(DefineConstants);INCLUDE_TABLEVIEW</DefineConstants>
</PropertyGroup>
Comment on lines +3 to +6
<PropertyGroup>
<TargetFramework>net10.0-windows10.0.22621.0</TargetFramework>
<Platforms>x64;ARM64</Platforms>
<RootNamespace>Reactor.Controls</RootNamespace>
…rendering for real

Integrate the complete 37-page native TableViewSamples gallery into the existing
Reactor.TestApp (a "TableView Gallery" tab hosting the compiled gallery via
XamlHostElement) ALONGSIDE the consumable first-class Reactor.Controls.TableView
control ("TableView" tab) - both rendering the native split-binary Advanced TableView
for real (cells + headers + colored pills/chips/stoplight tints), gated behind
IncludeTableView so shared CI stays byte-identical.

Three problems solved:

1. COEXISTENCE AV (0xC0000005 in Frame.Navigate): the separately XAML-compiled gallery
   and the registered advanced projection provider each described the same native WinRT
   type with a distinct native CCustomClassInfo. Fix: register the gallery's compiled
   XAML metadata provider as the single winning authority at startup (App.cs).

2. BLANK BODY (headers + cells never materialized - empty grid): ROOT CAUSE is
   WindowsAppSDKSelfContained. Framework-dependent activation resolves a WinAppSDK
   runtime build whose ABI / ms-appx resource resolution the dev-framework-built
   Advanced.dll's internal realization cannot use, so its inner-type templates
   (TableViewColumnHeader / TableViewCell / row presenter) silently fail to load and no
   headers/cells generate. Fix: the TestApp is now WindowsAppSDKSelfContained=true when
   IncludeTableView=true (the local self-contained runtime restores full rendering).
   Found by orchestrated investigation: the working standalone reference
   (TableViewGallery.WinUI, which is self-contained) rendered 16 rows x 9 headers; the
   only material diff was self-contained. Verified: control 12 rows x 4 headers with
   cell text; gallery Showcase 16 rows x 9 headers with colored Department pills, Status
   chips, stoplight Salary tints, hierarchy chevrons - identical to standalone.

3. ROW realization ordering: re-assert ItemsSource on Loaded (declarative XAML hosts get
   template-first ordering for free; a code-only host data-binds before the template
   applies). Enablement unified so the advanced theme closure merges into
   Application.Resources exactly once (the gallery defers to Reactor.Controls.TableViewStyles).

CI-safe: the TableView projects are not in Reactor.slnx; the self-contained switch only
engages when IncludeTableView=true; dotnet build Reactor.slnx -c Release with
GITHUB_ACTIONS=true = 0 warnings / 0 errors (TableView tabs OFF, byte-identical to pristine).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@DDancingDeath DDancingDeath changed the title [Sample][POC] Native TableView as a first-class Reactor control (shown in Reactor.TestApp) Port full TableView gallery + consumable control into Reactor.TestApp (renders for real) Jun 23, 2026
hiteshkrmsft and others added 9 commits June 23, 2026 19:51
…ew gallery

Adds a pure-C# Reactor (MVU) TableView gallery that consumes the consumable
Reactor.Controls.TableView control directly -- the idiomatic first-class approach --
instead of hosting the compiled WinUI gallery via XamlHostElement interop. The
"TableView" tab now shows this first-class gallery; the "TableView Gallery" tab keeps
the XamlHostElement interop (full 37 native pages) for comparison.

Control surface expanded (Reactor.Controls.TableView):
- TableViewElement: SelectionMode/SelectionUnit, GridLinesVisibility, HeadersVisibility,
  CanSort/Filter/Reorder/ResizeColumns, IsSelectionGutterVisible, FrozenColumnCount.
- TableColumn: a CellStyle {Text, Pill, Chip, Tint} + per-column Width.
- TableViewHandler maps these to the native props (CanUser*Columns) and sets per-column
  FrozenEdge=Leading for FrozenColumnCount.

Template columns (TableViewCellVisuals.cs) render the gallery's signature visuals in a
code-only host: CellStyle.Pill/Chip/Tint build a native TableViewTemplateColumn.CellTemplate
via XamlReader.Load of a DataTemplate bound through a TableViewCellVisualConverter
(Department -> pill hue, IsActive -> Active/Inactive chip, Salary -> stoplight tint, using
the exact Showcase colors). The converter is registered through a code-created merged
dictionary (Application.Resources is a Source-set XamlControlsResources, so the indexer
throws "Local values are not allowed").

First-class gallery (Demos/TableViewFirstClassGallery.cs): a Reactor component with a page
selector -- Showcase, Selection, Sort + filter, Grid lines, Frozen columns, Headers -- each
TableView(People, columns) with { feature props }. Showcase renders 12 rows x 7 headers with
colored Department pills, Active/Inactive chips, stoplight Salary tints, and a frozen first
column, all in pure C#. Replaces the basic TableViewControlDemo (deleted).

CI-safe: self-contained + the TableView tabs still gate on IncludeTableView; dotnet build
Reactor.slnx -c Release with GITHUB_ACTIONS=true = 0 errors.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…chk+fre native binaries

Make the first-class Reactor TableView gallery look like the real TableViewSamples
gallery, and ship both build flavors of the native Advanced.dll so the sample can be
run optimized (Release/fre) for performance or checked (Debug/chk) for debugging.

Gallery (Demos/TableViewFirstClassGallery.cs, pure-C# Reactor MVU):
- NavigationView shell (PaneTitle "TableView") with grouped sections (Quick start /
  Columns / Rows & cells / About), routed by SelectedTag.
- Each page is a Component with SamplePresenter-style chrome: Heading + description +
  a "Try it" InfoBar + an interactive Options card (RadioButtons / ToggleSwitch /
  Slider) that reconfigures the live TableView, plus the table itself.
- Pages: Home, Showcase, Selection, Sort + filter, Frozen columns, Headers, Grid lines,
  About. Showcase renders 12 rows x 7 cols with colored Department pills, Active/Inactive
  Status chips and stoplight Salary tints (template columns) + a frozen first column.
- Demos/TableViewSampleData.cs: shared Person data + Vibrant/Text column sets.

Native binary, per-configuration (both checked in, built from PR #15930004 tip
c75da7b3ef, which already merges advanced-poc-v2 @149f6f270f):
- native\fre\  = fre (free/optimized) Advanced.dll  -> Release builds (performance).
- native\chk\  = chk (checked/asserts) Advanced.dll  -> Debug builds (debugging).
- Reactor.TestApp.csproj selects native\$(fre|chk)\ by $(Configuration), falling back to
  chk if fre is absent. Named chk/fre to dodge the [Rr]elease/[Dd]ebug .gitignore rules.

Verified: Release consumes amd64fre and renders for real (NavigationView + colored
cells); CI-OFF `dotnet build Reactor.slnx -c Release` (GITHUB_ACTIONS=true) = 0/0.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…mples, and FIX sorting

Two changes driven by user feedback ("same as reference sample" + "sorting is not working").

FIX sorting (+ filtering) in the consumable control (Reactor.Controls.TableView):
- The native TableView uses a consumer-owned re-shape model: a header click only raises Sorted/
  Filtered and updates the column SortMemberPath/SortDirection/Filter state -- the CONSUMER must
  re-order/-filter the data itself. The handler did neither, so nothing sorted.
- TableViewHandler now sets SortMemberPath on every column and binds an ObservableCollection "view"
  rebuilt from a master snapshot on Sorted/Filtered: intersect active column filters, then apply the
  SortedColumns chain (by SortIndex, reflection on SortMemberPath, null-safe IComparable). Mirrors the
  reference SortPage's Sorted/Filtered handler. Verified: clicking Salary sorts the rows descending.

Full reference parity for the first-class gallery:
- NavigationView shell now reproduces the real SampleShell exactly: 36 items across Home / Quick start
  / Columns / Rows & cells / Styling / Power user (+ Performance, About), with the reference labels and
  Segoe Fluent glyph icons (Reactor's IconResolver renders raw glyph strings as FontIcons).
- Each page uses SamplePresenter-style chrome (reference Header + Description verbatim via TvMeta + a
  "Try it" InfoBar + an Options panel + the live table). Interactive pages: Showcase, Selection, Cell
  selection, Headers, Grid lines, Frozen leading/trailing (trailing via FrozenEdge setter), Column
  resize, Dynamic columns, Conditional/Per-cell styling, Row colors (AlternatingRowBackground), RTL
  (FlowDirection), Virtualization, Pagination, Data export, Performance. Built-in-gesture + native-only
  pages render the configured table + an explanatory note.
- TableViewSampleData.ManyPeople(n) synthesizes large datasets for pagination/perf/virtualization.

Verified: all 36 pages navigate with no crash; sorting reorders rows (screenshot); CI-OFF
`dotnet build Reactor.slnx -c Release` (GITHUB_ACTIONS=true) = 0/0.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…leViewSamples

User: "pages don't have the same options" + "work on every page to match, except home and
about. DO where what is right." Every page (except Home/About) now reproduces its reference
SamplePresenter.Options: the same section headers, the same controls, and a live Status / readout
block — driven through the consumable Reactor.Controls.TableView control.

Control: add OnControlReady (Action<TableView>, fired once on Loaded) so a page can capture the live
native control to drive imperative APIs (SortByColumn / SetSortColumn / ClearSort / ToggleSortDirection,
SelectAll / Select / DeselectAll, AutoSizeColumn, ScrollIntoView) and subscribe to Sorted / Filtered
for live readouts.

Gallery: uniform routing tag -> Component<Tv{Tag}Page>(); TvSample gains Section(header, caption, …)
and Readout(label, value); TvFx (brush + FreezeTrailing) and Home/About fold into the shell.

Pages (4 section files, ~34 components):
- Quick start — Showcase (mode/row-count/banding/gutter), Selection (mode combo + Select first/last/all/
  clear + live count/index/changes), Cell selection (unit combo), Multi-column sort (programmatic presets
  + Sorted-fires + priority readout), Per-column filtering (Filtered-fires + visible count), Inline edit
  (IsReadOnly toggle), Keyboard nav (shortcut table).
- Columns — Column resize (column combo + Min/Width/Max sliders with value + Status), reorder + autosize,
  drag-reorder gesture, dynamic columns (per-column visibility), sticky headers, headers visibility,
  frozen leading / trailing.
- Rows & cells — row reorder, grouped rows, hierarchy, row colors (banding), grid lines, row templates,
  row details, mixed controls, marquee.
- Power user / Styling — conditional + per-cell styling, advanced filter, clipboard, persisted layout,
  RTL, virtualization (source/size combos), pagination (real paged window), data export (CSV/TSV/JSON
  preview), performance (timed sort/filter).

Where a behaviour is native-only (grouping, hierarchy, whole-row templates, row details, in-cell controls,
real clipboard/layout serialization), the page still renders the configured table + the matching option
controls + a TvSample.NativeNote, and computes the readouts it genuinely can.

Verified: 36/36 pages navigate with no crash; imperative options work (Select all -> 12 selected; Sort by
Salary -> rows reshape; Column resize sliders drive Width/Min/Max with live Status); CI-OFF
`dotnet build Reactor.slnx -c Release` (GITHUB_ACTIONS=true) = 0/0.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…oc-v2 + mirror rounded corners

Forward-ported the latest control branch user/hik/tableview/advanced-poc-v2 (commit f0ca535ec4,
"rounded corners — outer container + row selection/keyboard focus") into the separate-binary PR
#15930004 branch user/hik/tableview/advanced-binary-poc-v2 (merge 5aa1358b01, pushed), then rebuilt
BOTH satellite flavors and refreshed the checked-in binaries:
- native\chk\  amd64chk (9.64 MB)
- native\fre\  amd64fre (1.73 MB)

The consumable control applies its own Reactor-side default Style (Styles/07_TableView.xaml), which
fully replaces the native ControlTemplate — so it is kept in sync with the native TableView.xaml:
CornerRadius 8 on the outer container Border + CornerRadius 4 on the row Border (TemplateBinding),
matching f0ca535ec4 so the rounded corners actually render in the Reactor host.

Verified: Release sample consumes amd64fre and renders (NavigationView + 36 pages + options); build 0/0.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ive updates (Showcase)

Three reference-parity gaps the user called out:
- Table height: the tables were a fixed 460px, leaving empty space. Added a Stretch flag to the
  control (VerticalAlignment/HorizontalAlignment=Stretch + MinHeight 320, no fixed Height) and made
  TvSample.Page fill the available height (table grows, options rail scrolls). Every page now stretches.
- Hierarchy: exposed HierarchicalItems + HierarchicalChildrenPath on the control (binds the native
  HierarchicalItemsSource + HierarchicalChildrenPropertyName). Showcase now DEFAULTS to Hierarchical
  (matching the reference) with real expand chevrons; verified 4 roots expand to 8 rows.
- Live updates: added an observable LivePerson model (Salary/IsActive raise PropertyChanged so bound
  cells + tint converters re-run IN PLACE, no re-bind), plus LivePeople(n) + HierarchyRoots(). Showcase
  gains a Live-updates rail (Off/1000/500/200 ms) driven by UseEffect + DispatcherTimer; verified the
  Salary tints recolor live (205 px changed across 1.5s).

Showcase options now mirror the reference: Mode (Flat/Grouped/Hierarchical), Row count, Live updates,
Appearance (vibrant + banding), Selection gutter, Status readouts.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ge, Groups expand/collapse, more live updates

Orchestrated pass (3 sub-agents, one per section file) filling the gaps the user flagged:
- Stretch everywhere: removed all fixed `height:` args across Quick start / Columns / Rows / Power so
  every table fills the available height via TvSample.Page (content-height + MinHeight 320, matching the
  reference SamplePresenter example container).
- Hierarchy page is now a REAL tree-grid (HierarchicalItems = HierarchyRoots(), children "Children"),
  with Expand all / Collapse all / Toggle selected actions + IsHierarchical / ChildrenPropertyName /
  Selected node readouts. Verified 4 roots expand to 8 rows with chevrons + indentation.
- Groups page captures the control and calls the native ExpandAllGroups() / CollapseAllGroups(), with
  real group-count / total / per-group-count readouts.
- Live updates added to the per-cell styling (CellStyling) + row-colors pages (observable LivePerson +
  UseEffect DispatcherTimer mutating Salary in place), matching the reference. Verified tints recolor.
- Columns pages use native MoveColumn / ResetColumnOrder / AutoSizeAllColumns / column Visibility.

Verified: 36/36 pages navigate no-crash; Hierarchy 4→8 on expand; CellStyling live updates recolor;
CI-OFF `dotnet build Reactor.slnx -c Release` (GITHUB_ACTIONS=true) = 0/0.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… by default

Two follow-ups from user feedback:
- "No scrolling option to go down": the NavigationView content host measures the page unconstrained, so
  the inner options ScrollView never activated and the rail was cut off. Reverted to a page-level
  ScrollView (like the reference SamplePresenter's ScrollViewer) so the whole page scrolls and every
  option (down to the Status readouts) is reachable. The table is content-height by default (grows with
  its rows, no dead space); the data-heavy Virtualization + Performance pages pass an explicit tableHeight
  so their tables stay fixed, virtualizing viewports (don't realize 50k/100k rows).
- "Table should be expanded by default, first level": added ExpandFirstLevel to the control; after binding
  HierarchicalItemsSource it enqueues tv.ExpandItem(root) for each root (once the tree is realized). Set on
  the Showcase (default Hierarchical) + Hierarchy + GridLines-hierarchical tables. Verified the Showcase
  default now shows 23 rows (4 roots expanded to their children) instead of 4 collapsed.

Verified: 36/36 pages no-crash (Virtualization stays bounded); page scrolls to all options; CI-OFF
`dotnet build Reactor.slnx -c Release` (GITHUB_ACTIONS=true) = 0/0.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
User: "I don't see sample code in each page." Added a collapsible "Source code (C#)" expander
(monospace, horizontally scrollable) under each page's example — mirroring the reference
SamplePresenter's source viewer. TvSample.Page gains a `sourceCode` parameter rendered via
TvSample.SourceCode().

Every feature page (34 — all except Home/About) now carries a ~12–25 line verbatim C# snippet of
its KEY Reactor usage: the TableView(items, columns) with { … } config plus the relevant options /
OnControlReady imperative / UseEffect timer code, accurate to what the page does. Authored via 3
section sub-agents (Columns/Rows/Power) + the orchestrator (Quick start). Sub-agents also tightened
each page's Options / Status readouts against the reference page.

Verified: build ON 0/0; 36/36 pages navigate no-crash; Source code expander present + renders the
snippet (screenshot); CI-OFF `dotnet build Reactor.slnx -c Release` (GITHUB_ACTIONS=true) = 0/0.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@DDancingDeath DDancingDeath changed the title Port full TableView gallery + consumable control into Reactor.TestApp (renders for real) TableView: first-class Reactor control + a 36-page gallery mirroring TableViewSamples (POC) Jun 24, 2026
@microsoft-github-policy-service

Copy link
Copy Markdown

@DDancingDeath please read the following Contributor License Agreement(CLA). If you agree with the CLA, please reply with the following information.

@microsoft-github-policy-service agree [company="{your company}"]

Options:

  • (default - no company specified) I have sole ownership of intellectual property rights to my Submissions and I am not making Submissions in the course of work for my employer.
@microsoft-github-policy-service agree
  • (when company given) I am making Submissions in the course of work for my employer (or my employer has intellectual property rights in my Submissions by contract or applicable law). I have permission from my employer to make Submissions and enter into this Agreement on behalf of my employer. By signing below, the defined term “You” includes me and my employer.
@microsoft-github-policy-service agree company="Microsoft"
Contributor License Agreement

Contribution License Agreement

This Contribution License Agreement (“Agreement”) is agreed to by the party signing below (“You”),
and conveys certain license rights to Microsoft Corporation and its affiliates (“Microsoft”) for Your
contributions to Microsoft open source projects. This Agreement is effective as of the latest signature
date below.

  1. Definitions.
    “Code” means the computer software code, whether in human-readable or machine-executable form,
    that is delivered by You to Microsoft under this Agreement.
    “Project” means any of the projects owned or managed by Microsoft and offered under a license
    approved by the Open Source Initiative (www.opensource.org).
    “Submit” is the act of uploading, submitting, transmitting, or distributing code or other content to any
    Project, including but not limited to communication on electronic mailing lists, source code control
    systems, and issue tracking systems that are managed by, or on behalf of, the Project for the purpose of
    discussing and improving that Project, but excluding communication that is conspicuously marked or
    otherwise designated in writing by You as “Not a Submission.”
    “Submission” means the Code and any other copyrightable material Submitted by You, including any
    associated comments and documentation.
  2. Your Submission. You must agree to the terms of this Agreement before making a Submission to any
    Project. This Agreement covers any and all Submissions that You, now or in the future (except as
    described in Section 4 below), Submit to any Project.
  3. Originality of Work. You represent that each of Your Submissions is entirely Your original work.
    Should You wish to Submit materials that are not Your original work, You may Submit them separately
    to the Project if You (a) retain all copyright and license information that was in the materials as You
    received them, (b) in the description accompanying Your Submission, include the phrase “Submission
    containing materials of a third party:” followed by the names of the third party and any licenses or other
    restrictions of which You are aware, and (c) follow any other instructions in the Project’s written
    guidelines concerning Submissions.
  4. Your Employer. References to “employer” in this Agreement include Your employer or anyone else
    for whom You are acting in making Your Submission, e.g. as a contractor, vendor, or agent. If Your
    Submission is made in the course of Your work for an employer or Your employer has intellectual
    property rights in Your Submission by contract or applicable law, You must secure permission from Your
    employer to make the Submission before signing this Agreement. In that case, the term “You” in this
    Agreement will refer to You and the employer collectively. If You change employers in the future and
    desire to Submit additional Submissions for the new employer, then You agree to sign a new Agreement
    and secure permission from the new employer before Submitting those Submissions.
  5. Licenses.
  • Copyright License. You grant Microsoft, and those who receive the Submission directly or
    indirectly from Microsoft, a perpetual, worldwide, non-exclusive, royalty-free, irrevocable license in the
    Submission to reproduce, prepare derivative works of, publicly display, publicly perform, and distribute
    the Submission and such derivative works, and to sublicense any or all of the foregoing rights to third
    parties.
  • Patent License. You grant Microsoft, and those who receive the Submission directly or
    indirectly from Microsoft, a perpetual, worldwide, non-exclusive, royalty-free, irrevocable license under
    Your patent claims that are necessarily infringed by the Submission or the combination of the
    Submission with the Project to which it was Submitted to make, have made, use, offer to sell, sell and
    import or otherwise dispose of the Submission alone or with the Project.
  • Other Rights Reserved. Each party reserves all rights not expressly granted in this Agreement.
    No additional licenses or rights whatsoever (including, without limitation, any implied licenses) are
    granted by implication, exhaustion, estoppel or otherwise.
  1. Representations and Warranties. You represent that You are legally entitled to grant the above
    licenses. You represent that each of Your Submissions is entirely Your original work (except as You may
    have disclosed under Section 3). You represent that You have secured permission from Your employer to
    make the Submission in cases where Your Submission is made in the course of Your work for Your
    employer or Your employer has intellectual property rights in Your Submission by contract or applicable
    law. If You are signing this Agreement on behalf of Your employer, You represent and warrant that You
    have the necessary authority to bind the listed employer to the obligations contained in this Agreement.
    You are not expected to provide support for Your Submission, unless You choose to do so. UNLESS
    REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING, AND EXCEPT FOR THE WARRANTIES
    EXPRESSLY STATED IN SECTIONS 3, 4, AND 6, THE SUBMISSION PROVIDED UNDER THIS AGREEMENT IS
    PROVIDED WITHOUT WARRANTY OF ANY KIND, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY OF
    NONINFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
  2. Notice to Microsoft. You agree to notify Microsoft in writing of any facts or circumstances of which
    You later become aware that would make Your representations in this Agreement inaccurate in any
    respect.
  3. Information about Submissions. You agree that contributions to Projects and information about
    contributions may be maintained indefinitely and disclosed publicly, including Your name and other
    information that You submit with Your Submission.
  4. Governing Law/Jurisdiction. This Agreement is governed by the laws of the State of Washington, and
    the parties consent to exclusive jurisdiction and venue in the federal courts sitting in King County,
    Washington, unless no federal subject matter jurisdiction exists, in which case the parties consent to
    exclusive jurisdiction and venue in the Superior Court of King County, Washington. The parties waive all
    defenses of lack of personal jurisdiction and forum non-conveniens.
  5. Entire Agreement/Assignment. This Agreement is the entire agreement between the parties, and
    supersedes any and all prior agreements, understandings or communications, written or oral, between
    the parties relating to the subject matter hereof. This Agreement may be assigned by Microsoft.

… + sizing)

From the PR reviewer + a thorough self-review:

Control correctness:
- ItemsSource contract: the handler snapshotted the consumer's collection, so in-place add/remove/move
  on a bound ObservableCollection was invisible (e.g. RowReorder's "Move 0→3 (API)" did nothing). Now
  subscribe to the source's INotifyCollectionChanged and re-sync the master snapshot (re-applying the
  active sort/filter); unsubscribe on rebind + unmount. Verified Move 0→3 now reorders the rows.
- Metadata provider registered EXACTLY once (cached + double-checked-lock guard) instead of a fresh
  provider on every Factories/EnsureInit call.

Layout sizing honors framework modifiers:
- Element Height is now nullable — written only when explicitly set (else .Height()/.MinHeight() modifiers
  or Stretch win). Removed the vestigial element-level MinWidth (use the .MinWidth() modifier).

x64-only native path (the satellite DLL is win-x64 only):
- IncludeTableView auto-off on non-x64 + a build-time _TableViewArchGuard error if forced on another arch.
- Restricted the control package to <Platforms>x64</Platforms>.

Perf:
- Virtualization page caches its dataset by size (was re-materializing 10k–50k rows + rebinding every
  render, snapping scroll back). Showcase passes an explicit tableHeight so Flat+1000 stays virtualized.

Verified: build ON 0/0; 36/36 pages no-crash; Move 0→3 reorders; CI-OFF slnx Release (GITHUB_ACTIONS=true) = 0/0.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@DDancingDeath

Copy link
Copy Markdown
Author

Thanks for the review. Addressed all of it in 07944e1f (verified: build 0/0, 36/36 pages no-crash, CI-OFF Reactor.slnx 0/0):

Inline comments

  1. Metadata provider registered per-call → now registered exactly once (cached instance + double-checked-lock guard); both EnsureInit() and Factories funnel through the guarded path.
    2–4. Height/MinWidth element props fighting Element.Modifiers → element Height is now nullable and the handler writes tv.Height only when it's explicitly set (otherwise .Height()/.MinHeight() modifiers or Stretch win). Removed the vestigial element-level MinWidth (consumers use the .MinWidth() modifier).
  2. ARM64 would deploy the x64 DLLIncludeTableView now auto-defaults off on non-x64, plus a build-time _TableViewArchGuard that fails early if it's forced on another arch.
  3. Package Platforms x64;ARM64 but only win-x64 native asset → restricted the control package to <Platforms>x64</Platforms> for this POC.

From a deeper self-review (also fixed in 07944e1f)

  • ItemsSource contract: the handler snapshotted the consumer's collection, so in-place add/remove/move on a bound ObservableCollection was invisible (e.g. the RowReorder page's "Move 0→3 (API)" was a no-op). The handler now subscribes to the source's INotifyCollectionChanged and re-syncs the master snapshot (re-applying the active sort/filter), unsubscribing on rebind + unmount. Verified "Move 0→3" now reorders the rows.
  • Virtualization page re-materialized 10k–50k rows + re-bound every render (snapping scroll back) → now caches the dataset by size. Showcase passes an explicit tableHeight so Flat + 1000 rows stays virtualized.

This remains a draft / self-contained POC (gated OFF in shared CI, x64-only), so it doesn't touch any existing Reactor project's every-PR build.

hiteshkrmsft and others added 3 commits June 24, 2026 22:27
The package's runtimes/win-x64/native asset pointed at
..\Reactor.TestApp\Microsoft.UI.Xaml.Controls.Advanced.dll, which moved to
native\fre\ (and native\chk\) when chk/fre flavors were split. dotnet pack
therefore referenced a non-existent file. Repoint to the optimized fre
(release) satellite so the package builds and ships the native control at
runtimes/win-x64/native/. Verified: pack produces the nupkg with the 1.69 MB
fre Advanced.dll at the correct path.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The vendored native TableView (Advanced.dll) is an unshipped WinRT satellite,
so framework-dependent activation against the installed public WinAppSDK
runtime renders a blank table. The consuming app must set
WindowsAppSDKSelfContained=true until the native control ships in public
WinAppSDK. The consumer targets injected the manifest and merged PRI strings
but were silent about this, so a consumer hit a mystifying empty grid.

Add a non-fatal RTV0001 build warning (unpackaged win-x64 only) guiding the
consumer to set self-contained. Affects PackageReference consumers only; the
in-repo sample uses ProjectReference and already sets the flag.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The native split-binary TableView satellite was renamed upstream
(microsoft-ui-xaml-lift PR #15930004, branch tabular-binary-rename):
Microsoft.UI.Xaml.Controls.Advanced.{dll,g.winmd} ->
Microsoft.UI.Xaml.Controls.Tabular.{dll,g.winmd}. The WinRT namespace is
unchanged (Microsoft.UI.Xaml.Controls), so runtimeclass names stay the same;
only the binary/winmd file name plus two resource classes renamed
(AdvancedControlsResources -> TabularControlsResources,
XamlControlsAdvancedXamlMetaDataProvider -> XamlControlsTabularXamlMetaDataProvider).

Rebuilt both flavors of the renamed satellite from dll-tabular (chk 9.4 MB,
fre 1.69 MB - fre identical size to the old fre Advanced, confirming a
content-neutral rename) plus the Tabular.g.winmd, and updated every consumer:
- native\{chk,fre}\...Tabular.dll (was Advanced.dll)
- TableView.Projection: CsWinRTInputs winmd + CsWinRTIncludes resource/provider
  class names -> Tabular
- app.manifest (both copies): <file name> + AdvancedControlsResources +
  XamlControlsAdvancedXamlMetaDataProvider activatableClass -> Tabular
- TableViewStyles.cs: metadata-provider alias target + TabularControlsResources
- Reactor.TestApp.csproj / Reactor.Controls.TableView.csproj: DLL paths, pack
  asset, Content link, x64 guard text -> Tabular
- doc comments + merge-string-script comment -> Tabular (string-merge root is the
  binary-name-independent Microsoft.UI.Xaml/Resources subtree, so unaffected)

Verified: Debug-ON build 0 errors; Release-ON build 0 errors (fre 1.69 MB copied);
CI-OFF (Reactor.slnx, IncludeTableView off) 0/0; both flavors launch and render
(UIA: DataGrid=1, 7 column headers, 23 rows on Showcase).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants