3145 Commits
Author SHA1 Message Date
Hemant Kumar b9fa30e549 WinUI Profiler: record the kernel's GPU memory events (#12424)
## Description

The WinUI Profiler (`tools/WinUIProfiler`) now also records the kernel's
GPU memory events for the target process, live and from `.etl` files.
Windows writes them in any WinUI build.

### Current Behavior

The profiler reads the target's `Microsoft-Windows-XAML` and
`Microsoft-Windows-XAML-Profiler` events. Its only GPU memory data was
the profiler provider's `GpuMemorySnapshot` event, stored like any other
event, and only from WinUI builds with `XamlProfilerEnabled`. #12416
removed that event. The native GPU sampler reads GPU engine utilization,
not memory.

### New Behavior

- **Events:** `Microsoft-Windows-DxgKrnl` keyword `0x4`:
`VidMmProcessUsageChange` (367) and `VidMmProcessBudgetChange` (366),
the process's usage and budget per adapter and memory segment group.
They carry the values `IDXGIAdapter3::QueryVideoMemoryInfo` returns. The
kernel writes them when the usage or budget changes, and writes the
current values when the process opens a GPU adapter and when a session
requests capture state.
- **Matched by the event's `ProcessId` field**, not the event header:
the System process writes some of a process's rows, such as those at
exit that bring its usage down to 0. That field becomes the event's
process ID; the thread ID stays the writing thread.
- **Live:** each connection's session also enables DxgKrnl keyword
`0x4`, with no process filter, and requests capture state when reading
starts, so an attach gets the current usage and budget at once. Both are
best effort: a failure is traced as a warning, and XAML events are read
as before.
- **`.etl` files:** the target's rows are read along with its XAML
events.
- **Session files** store them with provider `DxgKrnl`. The schema
version is unchanged.
- **App:** the connection panel's status line adds a "GPU memory" count,
and its tooltip a line for it.
- **CLI:** `processes` has a DxgKrnl column. For traces it still lists
only processes with XAML or XAML-Profiler events, since every process
that uses the GPU has GPU memory events; a session file always lists its
process. The usage text and messages say "events" instead of "XAML
events".
- **README:** the provider and its events, how rows are matched, the
live behavior, and a `logman` line for the provider.

## Impact and risk

Developer tooling only, under `tools/WinUIProfiler`; no product code
changes. Low risk. Session files that contain GPU memory rows can't be
read by earlier builds of the tool, which don't know the `DxgKrnl`
provider; other session files are unchanged.

## How Has This Been Tested?

`tools/WinUIProfiler` has no test project yet. I validated with traces
of a 1,000-item ListView test app, from a VM without a GPU (WARP) and
from a Snapdragon X Elite laptop (integrated GPU), and live on the VM.

| Test | Result |
| --- | --- |
| `dotnet build .\WinUIProfiler.Cli\WinUIProfiler.Cli.csproj -c Release`
| Passed, 0 warnings |
| `.\scripts\Build-App.ps1 -Configuration Release -Platform x64` |
Passed |
| CLI, VM trace | The app's 2 rows: usage 0 and budget 50,680,655,872
bytes, the values of the `GpuMemorySnapshot` events in the same trace |
| CLI, laptop trace with the app running | 130 usage rows and 1 budget
row; usage from 0 to about 22 MB |
| CLI, laptop trace through app exit | 255 usage rows and 1 budget row;
the last rows bring usage to 0 |
| Which process wrote the laptop rows | The System process wrote 2 of
the running app's rows and 127 of its exit rows; the app's own threads
wrote the rest. Matching by `ProcessId` keeps all of them |
| Live attach to a running app (Core live source, elevated) | The
capture-state usage and budget rows arrive; 0 lost |
| Live launch (same) | 6,230 XAML events and 2 GPU memory rows; 0 lost |
| `logman` with the README's provider lines | Records the app's GPU
memory rows |
| `record`, then `summary` and `dump` of the `.sqlite` | DxgKrnl rows
round-trip; a file with only GPU memory rows lists its process |
| Status line strings | `EtwFormat` and `EtwDetailsFormat` format with
the new arguments. The App UI itself wasn't driven |

Not tested: discrete GPUs (non-local memory), machines with two GPUs,
Windows 10.
2026-10-28 01:51:24 +05:30
Akanksha PatelandCopilot 03aabf5360 Capture an initial WinUI Profiler snapshot automatically after connecting (#12425)
## Fixes

<!-- Link either the public GitHub issue or the internal issue this PR
addresses. Remove the unused line. -->
<!-- PRs without a linked issue may be closed unless they are minor
documentation/typo fixes. -->

No linked issue was supplied. Implements the requested automatic initial
tree snapshot for WinUI Profiler.

## PR Type

<!-- Check the type of change. Limit each PR to one type when possible.
-->

- [ ] Bugfix
- [x] Feature
- [ ] Code style update (formatting, renaming)
- [ ] Refactoring (no functional changes, no API changes)
- [ ] Build related changes
- [ ] Documentation content changes
- [ ] Other (please describe):

## Description

<!-- Describe your changes in detail. -->

### Current Behavior
<!-- How does this work today? -->

Connecting to a target does not capture a baseline. Users must take the
first tree snapshot manually, potentially missing the state immediately
after connection.

### New Behavior
<!-- How will it work after this PR? -->

- Automatically capture and persist an **Initial snapshot** when
launch/attach completes successfully, after the authenticated TAP hello
and the existing connection prerequisites.
- Reuse the manual capture path and prevent manual snapshots or another
connection from overtaking the initial capture.
- Keep the initial snapshot in the existing newest-first history
alongside later manual snapshots. Each reconnect captures its own
baseline without clearing earlier history; periodic hello heartbeats do
not trigger additional snapshots.
- Preserve cancellation and reject results from a cancelled, closed, or
replaced connection before publishing them to history. Report capture
errors through the existing error UI.
- Add the initial-snapshot title resource and document the behavior. No
native capture, snapshot schema, or tree-display changes.

## Customer Impact

<!-- How does this change affect end users? Is it user-facing or infra
changes? -->

Profiler users get a saved connection baseline without an extra click.
Manual capture becomes available after the initial attempt finishes.
History remains available for the current profiler session, and saved
JSON files retain their existing on-disk lifetime.

## Regression Potential

<!-- Could this change cause regressions? What areas might be affected?
-->

- [x] Low risk — isolated change, limited scope
- [ ] Medium risk — touches shared components or public APIs
- [ ] High risk — architectural or breaking API change

Limited to the standalone profiler's connection/capture UI and
resources. The additional capture runs once per successful connection
and uses the existing capture timeout, persistence, error reporting, and
cancellation path.

## How Has This Been Tested?

<!-- Describe how you validated your changes. -->

- [x] I have performed a self-review of my own code
- [ ] I have added tests to cover my changes
- [ ] Existing tests pass locally

**Release x64 build: passed.** Ran from the repository root with the
.NET SDK resolver set to `C:\Program Files\dotnet` and an isolated
`BaseOutputPath`, preserving the already-running profiler:

```powershell
.\initrun.ps1 -Flavor amd64fre .\tools\WinUIProfiler\scripts\Build-App.ps1 -Configuration Release -Platform x64
```

**External UI/runtime validation: passed, 25 checks and zero failures.**
Ran this temporary Windows UI Automation harness against the built app:

```powershell
& "$env:SystemRoot\System32\WindowsPowerShell\v1.0\powershell.exe" -NoLogo -NoProfile -STA -File 'C:\Users\akanpatel\.copilot\session-state\18d84a18-e328-402b-b9ec-6a2269e43683\files\initial-snapshot-validation\Validate.ps1' -Profiler 'C:\Users\akanpatel\.copilot\session-state\18d84a18-e328-402b-b9ec-6a2269e43683\files\initial-snapshot-validation\app-build\x64\Release\net10.0-windows10.0.26100.0\win-x64\WinUIProfiler.App.exe'
```

Verified automatic capture after packaged launch and attach; persisted
snapshots with real XAML/Composition nodes and correlations; the initial
label and authenticated process identity; later manual capture retaining
the baseline; no duplicate capture on heartbeat; history retention on
disconnect; one new baseline on reconnect; no capture for
cancelled/failed connections; recovery after cancellation/failure; and
no XAML binding or unhandled runtime errors.

The temporary harness was removed after validation. No test cases or
test project are included in this PR; no repository automated test suite
was run.

**Whitespace validation: passed.**

```powershell
git --no-pager diff --check
```

## Screenshots (if appropriate)

<!-- If you are making visual changes, include before/after screenshots.
-->

Not applicable; no layout or styling changes.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 18d84a18-e328-402b-b9ec-6a2269e43683
2026-10-28 00:58:04 +05:30
Surendran RajamohanandCopilot d16403c09a WinUI Profiler: say GpuMemorySnapshot is from earlier builds
XAML no longer writes GpuMemorySnapshot, so the README describes it as
something earlier builds reported.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: e91a0e91-385c-48fd-9b9c-daea01d24e65
2026-10-28 00:13:37 +05:30
Surendran RajamohanandCopilot 496e182522 WinUI Profiler: record the kernel's GPU memory events
The Microsoft-Windows-XAML-Profiler GpuMemorySnapshot event measures the
process's GPU memory with IDXGIAdapter3::QueryVideoMemoryInfo on the UI
thread, under the D3D device lock, each time a composition surface is
created, freed or resized. The kernel already writes the same counters:
Microsoft-Windows-DxgKrnl VidMmProcessUsageChange (367) and
VidMmProcessBudgetChange (366), keyword 0x4, on every change, plus the
current values when a process opens a GPU adapter and on capture state.

Record those events with the target's XAML events, so the profiler has
the process's GPU memory usage and budget from the kernel, in any build,
without depending on the snapshot event:

- Live sessions enable DxgKrnl keyword 0x4 for every process, because the
  System process writes some of the target's events (such as those
  written when it exits), and request capture state when reading starts,
  so an attached process gets its current values. Best effort: if this
  fails, the session still reads the XAML events.
- Live and .etl reading keep the 366/367 events whose ProcessId field is
  the target, as XamlProvider.DxgKrnl events. Session files store them
  like the XAML events; the schema is unchanged.
- The connection panel counts GPU memory events. The CLI adds a DxgKrnl
  column, and for a trace lists only processes with XAML events.
- README: the provider, what its events carry, the live behavior and the
  logman line.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: e91a0e91-385c-48fd-9b9c-daea01d24e65
2026-10-27 23:49:30 +05:30
suren003 1433a837e7 Remove GpuMemorySnapshot from the XAML profiler (#12416)
## Fixes

<!-- TODO: link the tracking issue -->

## PR Type

- [ ] Bugfix
- [ ] Feature
- [ ] Code style update (formatting, renaming)
- [ ] Refactoring (no functional changes, no API changes)
- [ ] Build related changes
- [ ] Documentation content changes
- [x] Other (please describe): removes a diagnostics event, and the GPU
memory query that fed it, from the XAML profiler instrumentation.

## Description

### Current Behavior

In builds with the XAML profiler compiled in (`XAMLPROFILER_ENABLED`,
which `main` turns on for Debug builds only), while a trace session
enables `Microsoft-Windows-XAML-Profiler`,
`DCompSurface::TraceProfilerMemoryChange` writes `GpuMemorySnapshot` on
every DComp surface allocation, free and resize. To fill the event, the
UI thread:

1. takes the shared D3D device lock;
2. walks from the device to its DXGI adapter and `IDXGIAdapter3`;
3. calls `QueryVideoMemoryInfo` twice, for the local and non-local
segment groups.

The event is 34 bytes, but on a VM without a GPU the query takes about
21 µs, most of it in the kernel. A launch of a 1,000-item ListView test
app has 52–76 surface changes, so there the query costs about 1.1–1.6 ms
of UI-thread time per profiled launch. On a laptop GPU it cost 0.7 ms
per launch (4 µs median per query, 132 µs at most).

### New Behavior

XAML no longer queries GPU memory or writes `GpuMemorySnapshot`.

The DirectX kernel already traces the same numbers.
`Microsoft-Windows-DxgKrnl` writes `VidMmProcessUsageChange` (event 367)
and `VidMmProcessBudgetChange` (event 366) for each process, adapter and
memory segment group:
- whenever the process's usage or budget changes;
- as a rundown when the process first opens an adapter;
- on capture state (keyword `0x4`).

They carry the values `QueryVideoMemoryInfo` returns, so profiling tools
read them instead. A trace needs DxgKrnl keyword `0x4` with capture
state, in a session that accepts kernel-mode providers (in a WPR
profile, `NonPagedMemory="true"`).

The two events written at the same point are unchanged:
`DCompSurfaceMemoryChanged` (the surface's id and size) and
`XamlHeapSnapshot` (XAML's heap counters).

## Customer Impact

None for apps: the removed code only ran in builds with the profiler
compiled in, while a trace session enabled the provider.

Profiling sessions lose a UI-thread stall on every surface change. Tools
that read `GpuMemorySnapshot` need to read the DxgKrnl events instead.

## Regression Potential

- [x] Low risk — isolated change, limited scope
- [ ] Medium risk — touches shared components or public APIs
- [ ] High risk — architectural or breaking API change

Two files, and the change only deletes code (plus a comment saying where
the numbers come from now). Everything removed is inside `#ifdef
XAMLPROFILER_ENABLED` and only ran while a session enabled the provider.
Nothing in this repo reads `GpuMemorySnapshot`.

## How Has This Been Tested?

- **Build.** amd64chk, the configuration in which `main` compiles the
profiler, builds clean.
- **Same values.** On a VM without a GPU (WARP), XAML's own usage query
returns 0. There, in traces of the ListView1000 test app that have both
`GpuMemorySnapshot` and the DxgKrnl events, every snapshot equals the
kernel's latest usage and budget for that process and adapter: 52 of 52
when the app is still running at the end of the trace, and 102 of 102
when the trace continues through app exit. A D3D12 test program that
allocates and frees video memory checked non-zero usage the same way:
usage matched in 19 of 19 samples and budget in 18 of 19 (the miss was a
sample taken before the program's device existed).
- **Real GPU.** On a Snapdragon X Elite laptop (integrated GPU, one
adapter, Windows 11), with the x64 test app running emulated, every
snapshot equals the kernel's usage and budget: 76 of 76 with the app
still running at the end of the trace, and 130 of 130 through app exit,
with usage between 2.5 and 21.3 MB. There the snapshots took 0.70 ms of
UI-thread time per launch. Enabling DxgKrnl keyword `0x4` instead makes
the app write 511 kernel events per launch, about 0.1 ms at about 0.2 µs
each (estimated from back-to-back event timestamps).
- **Cost.** Measured on a VM without a GPU (WARP), in an amd64fre build
with the profiler compiled in, ListView1000, profiler session on, 12
interleaved rounds of before and after:

  | | Before | After |
  |---|---:|---:|
| CPU per launch in `DCompSurface::TraceProfilerMemoryChange` | 1.23 ms
| 0.11 ms |
| Difference per round, mean (95% CI) | | −1.12 ms (−1.33 to −0.92);
lower in 12 of 12 rounds |
  | `GpuMemorySnapshot` events per launch | 52.5 | 0 |
  | `DCompSurfaceMemoryChanged` events per launch | 52.5 | 52.8 |

Where the query's time went (121 CPU samples): ntoskrnl 32%, dxgkrnl
17%, d3d11 17%, dxgmms2 13%, dxgi 5%, Microsoft.UI.Xaml 4%.

**Still to do:** discrete GPUs (non-local memory) and machines with two
GPUs still need a capture on real hardware.

- [x] I have performed a self-review of my own code
- [ ] I have added tests to cover my changes
- [ ] Existing tests pass locally

## Screenshots (if appropriate)

Not applicable.
2026-10-27 11:06:04 -07:00
Hemant Kumar b4573c044e WinUI Profiler: save live XAML events to a SQLite session file (#12423)
## Description

Third step of the WinUI Profiler's event pipeline
(`tools/WinUIProfiler`): while connected, the app saves every XAML event
it receives to a SQLite session file. Builds on #12419 (live events) and
#12415 (reading `.etl` files). The object-lifetime and frame processors
will read from these files.

### Current Behavior

The app reads the target's XAML events live and only counts them.
Nothing is kept after disconnect.

### New Behavior

- **One file per connection** in
`%LOCALAPPDATA%\WinUIProfiler\Sessions`, named
`<date>-<time>-<process>-<pid>.sqlite`. The connection panel shows the
file name, event count and size; the full path is in the tooltip.
- **Tables:**
- `SessionInfo`: one row with the process, coverage (from process start
or from connection), time zero, QPC frequency, size limit, how the
session ended, and events lost or dropped.
- `EventTypes`: one row per event layout, with the field names and their
.NET types (for example `Int64,Int32,String,Boolean`).
- `Events`: `Seq` (arrival order 1, 2, 3...), `Qpc`, thread, `TypeId`
(references `EventTypes`), and the field values as a JSON array.
- **Writer:** a separate thread commits batches of up to 2,000 events or
every 250 ms, so disk writes don't hold up event processing. It waits
rather than drops, so the pipeline queue stays the only place events are
dropped.
- **Size limit:** 500 MB per file. Near the limit, the oldest 5% of
events are removed and the file records from which event it is complete.
- **Infinity and NaN** (which occur in real XAML events) are stored as
strings and read back as numbers.
- The file is readable while being written and after a crash. It is
closed as a single file on disconnect, target exit or app close.
- **CLI:** `processes`, `summary` and `dump` accept `.sqlite` files. The
new `record <etl> --pid <pid> --out <file> [--limit-mb]` writes a
session file from a trace.
- The connection panel's status lines are shorter: one line each, with
details in tooltips.
- Adds `Microsoft.Data.Sqlite` 10.0.13.

## Impact and risk

Developer tooling only, under `tools/WinUIProfiler`; no product code
changes. Low risk. Session files are not deleted by the profiler (a
retention policy is a follow-up).

## How Has This Been Tested?

`tools/WinUIProfiler` has no test project yet. I validated against
`.etl` traces and against `logman` recording the same providers in
parallel, on a local Release build of `Microsoft.UI.Xaml.dll` with
`XamlProfilerEnabled` (not part of this PR).

| Test | Result |
| --- | --- |
| `dotnet build .\WinUIProfiler.Cli\WinUIProfiler.Cli.csproj -c Release`
| Passed, 0 warnings |
| `.\scripts\Build-App.ps1` | Passed |
| `record` of a 73,860-event trace, then `dump` of the `.sqlite` vs
`dump` of the `.etl` | All 73,860 events identical (incl. 1,582
Infinity/NaN values); only the time column differs, by a constant offset
(time zero is the recording's first event) |
| `record` with `--limit-mb` 1 to 5 | Files stay under the limit; the
newest events are intact |
| Live launch of a WinUI 3 app in the app, with interaction, `logman` in
parallel | Per thread, the session file holds exactly logman's events in
order; 69,696 events, 0 lost, 0 dropped; closed as "Disconnected" |
| `Seq` and timestamps in the live files | `Seq` gapless; no timestamp
went backwards |
| CLI reading a file while the app is recording | Passed |
| Profiler killed mid-recording | File readable; all committed batches
present |
| SQLite foreign-key check (`Events.TypeId` → `EventTypes`) | No
violations |
2026-10-27 23:07:05 +05:30
Hemant KumarandCopilot App 29200d1531 WinUI Profiler: save live XAML events to a SQLite session file
While connected, every event the pipeline receives is saved to a SQLite file,
one per connection, in %LOCALAPPDATA%\WinUIProfiler\Sessions. A writer thread
commits batches; field values are a JSON array per event, with field names and
.NET types stored once per event type. Files stay within 500 MB by removing the
oldest events. The CLI reads session files and records one from an .etl.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
2026-10-27 22:59:52 +05:30
Akanksha PatelandCopilot ba09cff5b6 Compact WinUI Profiler snapshot tree display (#12421)
## Fixes

<!-- Link either the public GitHub issue or the internal issue this PR
addresses. Remove the unused line. -->
<!-- PRs without a linked issue may be closed unless they are minor
documentation/typo fixes. -->

Follow-up to #12414; no linked issue.

## PR Type

<!-- Check the type of change. Limit each PR to one type when possible.
-->

- [x] Bugfix
- [ ] Feature
- [ ] Code style update (formatting, renaming)
- [ ] Refactoring (no functional changes, no API changes)
- [ ] Build related changes
- [ ] Documentation content changes
- [ ] Other (please describe):

## Description

<!-- Describe your changes in detail. -->

### Current Behavior
<!-- How does this work today? -->

The XAML and Composition snapshot trees add vertical padding inside the
native TreeView rows, making the hierarchy unnecessarily spread out.
Labels also lead with snapshot-local `#Id` counters, which can be
mistaken for object identities.

### New Behavior
<!-- How will it work after this PR? -->

- Remove redundant vertical padding while retaining the native TreeView
indentation, chevrons, selection, and correlation outline.
- Show the short runtime type, optional element name, and actual
captured address in parentheses, without a leading counter.
- Show the captured XamlRoot address in each root heading.
- Preserve internal IDs for topology and correlation, and expose the
selected node's ID in Details.

This changes only four snapshot-viewer display files. Native capture,
saved snapshot schemas, and correlation behavior are unchanged.

## Customer Impact

<!-- How does this change affect end users? Is it user-facing or infra
changes? -->

More snapshot nodes fit on screen, and labels distinguish actual
object/visual addresses from snapshot bookkeeping IDs. Both trees use
the same compact layout.

## Regression Potential

<!-- Could this change cause regressions? What areas might be affected?
-->

- [x] Low risk — isolated change, limited scope
- [ ] Medium risk — touches shared components or public APIs
- [ ] High risk — architectural or breaking API change

Scope is limited to row spacing, labels, root headings, and the
selected-node Details display. Expansion, selection, highlighting,
scrolling, and bidirectional mappings were exercised against a real
snapshot.

## How Has This Been Tested?

<!-- Describe how you validated your changes. -->

- [x] I have performed a self-review of my own code
- [ ] I have added tests to cover my changes
- [ ] Existing tests pass locally

Release x64 profiler build: **Passed** using:

```powershell
$env:DOTNET_MSBUILD_SDK_RESOLVER_CLI_DIR = 'C:\Program Files\dotnet'
.\initrun.ps1 -Flavor amd64fre .\tools\WinUIProfiler\scripts\Build-App.ps1 -Configuration Release -Platform x64
```

Temporary, out-of-repository UI/runtime probe: **29 checks passed, 0
failures**. Captured a real FolderTreeAppCpp snapshot through TAP with
90 XAML nodes and 191 Composition nodes, then exercised the actual
viewer:

- Compact rows and native indentation in both trees; actual addresses,
names, and XamlRoot headings.
- Restoring the original padding reproduced oversized rows; removing it
restored compact spacing.
- Expand/collapse, mapping in both directions, correlation highlighting,
scrolling to a match, and retained IDs in Details.
- Light/dark themes and larger text without fixed-height clipping.

`git diff --check`: **Passed**.

No repository test files were added. The full repository test suite,
High Contrast, and multiple monitor DPI settings were not tested.

## Screenshots (if appropriate)

<!-- If you are making visual changes, include before/after screenshots.
-->

The actual viewer was visually verified locally. The screenshot includes
local session paths and is not attached.

| Display | Before | After |
|---|---|---|
| Row height on the validation machine | 47 DIP | 32 DIP |
| Example node label | `#12 Grid (RootGrid) [0x...]` | `Grid (RootGrid)
(0x...)` |
| Root heading | `XamlRoot #1` | `XamlRoot (0x...)` |

Addresses above are illustrative placeholders, not captured pointer
values.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 18d84a18-e328-402b-b9ec-6a2269e43683
2026-10-27 09:46:55 -07:00
Hemant Kumar d87f0d9ce0 WinUI Profiler: live XAML ETW events, from process start for launches (#12419)
## Description

Second step of the WinUI Profiler's event pipeline
(`tools/WinUIProfiler`): the app now reads the target's XAML
TraceLogging events live while connected. Builds on #12415, which reads
them from `.etl` files.

### Current Behavior

The app connects to a WinUI 3 app and shows CPU, GPU, memory and tree
snapshots. XAML events can only be read from a recorded `.etl` file with
the CLI.

### New Behavior

- **Launch (unpackaged or packaged):** the ETW session starts before the
process is created. The process has no ID yet, so ETW filters on the
executable name: the selected `.exe`, or for a packaged app the
`Executable` of the matching `<Application>` in the installed package's
`AppxManifest.xml`. As soon as the launch returns the process ID, the
same session switches to a process ID filter. ETW keeps the events in
the session's buffers until then, so the launch's first event is
included. The target is launched normally, not suspended, so its launch
timing is not affected.
- **Attach:** the session filters on the process ID and counts from
connection.
- Events go through a queue of 65,536 events to one processing thread
that runs event processors (`IEventProcessor`). The first processor
counts events. When the queue is full, new events are dropped and
counted; the session keeps running.
- The connection panel shows whether the counts start at process start
or at connection, the events per provider, events lost by ETW and events
dropped by the profiler. The last counts stay visible after disconnect.
If ETW cannot start (permissions), the panel says why and the metrics
keep working. A launch is shown as "from connection" when activation
returns a packaged app that was already running.
- An ETW session outlives a crashed profiler and keeps the providers
enabled in the target. Sessions are named `WinUIProfiler-<profiler
PID>-<id>`; starting a session stops those whose profiler process no
longer exists.
- Microsoft-Windows-XAML is enabled with keyword `0x100000`, which no
manifest event uses, so only TraceLogging events are written. The
README's `logman` recipe now uses the same keyword.

## Impact and risk

Developer tooling only, under `tools/WinUIProfiler`; no product code
changes. Low risk. Reading ETW needs an elevated profiler or membership
in the local Performance Log Users group, as for `logman`.

## How Has This Been Tested?

`tools/WinUIProfiler` has no test project yet, so this was validated
against `logman` recording the same providers in parallel, on a local
Release build of `Microsoft.UI.Xaml.dll` with `XamlProfilerEnabled` (not
part of this PR).

| Test | Result |
| --- | --- |
| `dotnet build .\WinUIProfiler.Cli\WinUIProfiler.Cli.csproj -c Release`
| Passed, 0 warnings |
| `.\scripts\Build-App.ps1 -Configuration Release -Platform x64` |
Passed |
| Unpackaged launch in the app | "from process start"; 42,483 + 13,983
events = logman's first 56,466 for that process, from its first event; 0
lost, 0 dropped |
| Packaged launch in the app (Microsoft Store, which carries its own
`Microsoft.UI.Xaml.dll`) | "from process start"; 82,689 events =
logman's 82,689 |
| Attach in the app | "from connection"; counts follow activity; session
stopped on disconnect |
| Exe filter, then switch to the process ID 1 ms, 0.5 s and 1 s after
launch, with a second copy of the exe running | Target counts identical
to logman; the other copy's events excluded after the switch |
| Reading started 6 s after launch | Identical to logman (ETW buffered
the events) |
| AUMID-to-executable lookup for every app installed on the test machine
| 300 of 300 match their manifests |
| Session left by a dead profiler process | Stopped; a session of a
running process is kept |
| 24 short launch and attach runs | No failures, no sessions left |
2026-10-27 20:07:34 +05:30
Hemant KumarandCopilot App 7f2f671327 WinUI Profiler: read XAML events live, from process start for launches
The app now reads the target's XAML TraceLogging events with a real-time ETW
session while connected. For a launch the session starts before the process is
created, filtered by executable name (for packaged apps, the Executable in the
installed package's manifest), and switches to the process ID once the launch
returns it, so the first events are included without suspending the target.
Attach filters by process ID and counts from connection.

Events go through a 65,536-event queue to one processing thread; the first
processor counts them. The connection panel shows whether counts start at
process start or at connection, events per provider, events lost by ETW and
events dropped by the profiler. Sessions left by a crashed profiler are stopped.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
2026-10-27 18:56:45 +05:30
Surendran RajamohanandCopilot 552b0dacb1 Remove GpuMemorySnapshot from the XAML profiler
While a profiler session was on, DCompSurface::TraceProfilerMemoryChange wrote
GpuMemorySnapshot on every DComp surface allocation, free and resize. Each one
took the shared D3D device lock, walked device -> DXGI adapter ->
IDXGIAdapter3 and made two QueryVideoMemoryInfo kernel calls on the UI thread:
about 21 us per surface change, most of it in the kernel, to write a 34-byte
event. A launch of a 1,000-item ListView test app has 52-76 surface changes,
so about 1.1-1.6 ms of UI-thread time.

The DirectX kernel already traces the same numbers. Microsoft-Windows-DxgKrnl
writes VidMmProcessUsageChange and VidMmProcessBudgetChange for a process on
every change of its usage or budget, plus a rundown when the process first
opens an adapter and on capture state. They carry the values
QueryVideoMemoryInfo returns (all 52 snapshots in a ListView capture matched
the kernel's values). Profiling tools can read those instead, so XAML needs no
query and no event.

DCompSurfaceMemoryChanged and XamlHeapSnapshot are unchanged.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: e91a0e91-385c-48fd-9b9c-daea01d24e65
2026-10-27 17:11:55 +05:30
Akanksha PatelandCopilot 347deb0843 Add XAML and Composition tree snapshots and viewer to WinUIProfiler (#12414)
## Fixes

<!-- Link either the public GitHub issue or the internal issue this PR
addresses. Remove the unused line. -->
<!-- PRs without a linked issue may be closed unless they are minor
documentation/typo fixes. -->

Standalone profiler feature; no linked issue. Uses the tool-side
snapshot approach from #12393, without its MUX instrumentation or other
profiler features.

## PR Type

<!-- Check the type of change. Limit each PR to one type when possible.
-->

- [ ] Bugfix
- [x] Feature
- [ ] Code style update (formatting, renaming)
- [ ] Refactoring (no functional changes, no API changes)
- [ ] Build related changes
- [ ] Documentation content changes
- [ ] Other (please describe):

## Description

<!-- Describe your changes in detail. -->

### Current Behavior
<!-- How does this work today? -->

WinUIProfiler can connect to a target process and display live process
metrics, but cannot capture, save, or inspect its XAML and Composition
trees.

### New Behavior
<!-- How will it work after this PR? -->

This PR adds on-demand tree snapshots and an interactive viewer,
entirely under `tools/WinUIProfiler`.

- **Capture exactly two trees:** the realized XAML visual tree and
publicly exposed Composition visual tree. The injected TAP discovers
XamlRoots through public diagnostics callbacks and traverses each root
on its owning UI thread using public XAML and Composition APIs. Open
popup children are captured as separate visual subtrees.
- **Record useful node data and direct correlations:** types, XAML
names, hierarchy/order, selected SDK properties, COM object addresses,
Composition `IVisual` addresses, optional diagnostics handles,
root/thread metadata, and capture intervals. XAML-to-Composition links
come from `ElementCompositionPreview.GetElementVisual` and canonical COM
identity; they do not depend on internal comp-node pointers.
- **Transport and save snapshots:** add snapshot request/chunk/result
messages to the authenticated TAP connection. Validate
request/capture/process identity, chunk ordering and sizes, schema,
graph relationships, and correlation references before atomically saving
JSON under `%LOCALAPPDATA%\WinUIProfiler\Snapshots`. Capture has
explicit timeout, cancellation, size, and record limits, with visible
failures rather than partial-success files.
- **Select captures from snapshot history:** show successful snapshots
newest first, with counts and saved paths. History survives
disconnect/reconnect within the current profiler session. Selecting an
entry opens its viewer; selecting it again reuses that window, while
different captures can be opened in separate windows.
- **Inspect both trees:** asynchronously load and validate saved
snapshots, lazily populate tree branches, show selected-node properties,
highlight direct counterparts in either direction, and provide a match
picker when there are multiple direct matches. Unmapped nodes do not
acquire guessed ancestor mappings. Missing or invalid files surface
errors.
- **Navigate larger snapshots:** display the XAML object's COM identity
address or Composition visual's `IVisual` address beside each node, with
a full-label tooltip. Each tree has independent **Expand all** and
**Collapse all** controls; expansion includes lazy descendants, and
collapse resets descendant expansion state.
- **Reduce property noise:** hide known default-valued Composition
properties in the viewer only. Non-default values, unknown properties,
and getter errors remain visible. XAML properties and the complete saved
JSON are unchanged.
- **Integrate the standalone build and UI:** generate the TAP's required
public C++/WinRT projections from the app's restored SDK metadata,
retain x64/ARM64 payload staging, add localized/accessibility strings,
and document capture, viewing, and limitations.

**Scope and limitations:** no MUX/product changes, ETW listener, heap
capture, recording database, internal `HWCompNode` tree, or private
compositor-tree traversal. Composition names/comments are not added. The
capture represents realized/publicly accessible objects, not a logical
tree or globally atomic cross-thread snapshot. `GetElementVisual` may
materialize handout visuals. Capture is bounded to 20 seconds, 64 MiB,
and 131,072 records. JSON files persist after exit, but the history list
is session-only and is not reloaded on startup.

## Customer Impact

<!-- How does this change affect end users? Is it user-facing or infra
changes? -->

Profiler users can capture and inspect a connected application's XAML
and public Composition trees, follow direct cross-tree mappings, and
compare saved captures without rebuilding or modifying MUX. This is a
standalone tooling feature; it does not change shipping WinUI control
behavior or SDK APIs.

## Regression Potential

<!-- Could this change cause regressions? What areas might be affected?
-->

- [x] Low risk — isolated change, limited scope
- [ ] Medium risk — touches shared components or public APIs
- [ ] High risk — architectural or breaking API change

Changes are confined to the standalone profiler. The affected areas are
TAP request/lifetime handling, SDK projection generation and payload
staging, snapshot file validation, and viewer interactions. Capture is
opt-in and runs work on target UI threads, so it can temporarily affect
the profiled application's responsiveness; public visual acquisition can
also materialize handout visuals. Existing authentication, heartbeat,
metrics, and disconnect behavior remain in place.

## How Has This Been Tested?

<!-- Describe how you validated your changes. -->

- [x] I have performed a self-review of my own code
- [ ] I have added tests to cover my changes
- [ ] Existing tests pass locally

Validation on Windows x64 with .NET SDK 10.0.403:

- `.\scripts\Build-App.ps1 -Configuration Release -Platform x64` from
`tools\WinUIProfiler` — **passed**, including native x64/ARM64 TAP and
injector builds, managed app compilation, and payload staging.
- `MSBuild.exe
tools\WinUIProfiler\WinUIProfiler.App\WinUIProfiler.App.csproj /t:Build
/p:Configuration=Release /p:Platform=x64 /nologo /v:quiet` — **passed**
for the final viewer changes.
- `dotnet format whitespace
tools\WinUIProfiler\WinUIProfiler.App\WinUIProfiler.App.csproj
--no-restore --verify-no-changes --include
tools\WinUIProfiler\WinUIProfiler.App\ViewModels\SnapshotViewerViewModel.cs
tools\WinUIProfiler\WinUIProfiler.App\Views\SnapshotViewerWindow.xaml.cs
--verbosity quiet` — **passed**.
- `git diff --check` — **passed**.
- Session-only managed/native smoke harnesses — **passed**
capture/transport validation, repeated captures, document/model
validation, direct one-to-many and many-to-one mappings,
cancellation/error cases, default-property filtering, raw-property
preservation, and address labels.
- Session-only Windows UI automation — **passed** capture/history across
reconnect, lazy expansion, selected-node details, bidirectional mapping
and match selection, viewer reuse/separate windows, disconnected history
access, missing-file errors, and parent-window cleanup. A live capture
contained 90 XAML nodes, 310 Composition nodes, and 90 correlations.
- Final `verify-snapshot-tree-controls-ui.ps1 -ProcessId 22824 -Reuse`
session-only UI check — **passed** every row's displayed address, full
lazy-descendant expansion, independent collapse/reset/re-expansion of
both trees, and mapping/details after bulk operations.

The local smoke/UI harnesses are not included in this PR. No repository
regression-test files were added. The full WinUI product test suite and
native ARM64 execution were not run.

## Screenshots (if appropriate)

<!-- If you are making visual changes, include before/after screenshots.
-->

Before this change there was no snapshot capture/history UI or tree
viewer. The images below show the new snapshot history and the two-tree
viewer with addresses, independent expansion controls, and selected-node
details.

![Snapshot capture controls and session
history](https://github.com/user-attachments/assets/afe02043-5178-4bc9-a01e-4c8d6ea66a17)

![XAML and Composition snapshot viewer with addresses, mappings, and
expansion
controls](https://github.com/user-attachments/assets/3a5b4588-7dce-425a-93af-2caa941fa126)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-10-27 17:10:47 +05:30
Hemant Kumar c2f0d35060 WinUI Profiler: read XAML TraceLogging events from .etl files (#12415)
## Description

First step of the WinUI Profiler's event pipeline
(`tools/WinUIProfiler`): read XAML ETW events from a recorded `.etl`
file, and a small CLI to look at them.

### Current Behavior

The profiler app connects to a WinUI 3 app and shows CPU, GPU and
memory. It does not read any XAML ETW events.

### New Behavior

`WinUIProfiler.Core` can read the XAML events of one process from a
`.etl` file:

- `OfflineEtlSource.Read(path, processId, sink)` opens the file with
TraceEvent and calls `sink` once per event.
- `XamlEventSubscription` keeps only TraceLogging events (ETW channel
11) from Microsoft-Windows-XAML and Microsoft-Windows-XAML-Profiler, for
the requested process. Manifest events are not read. Each event is
copied into a `ProfilerEvent`, because TraceEvent reuses its event
objects.
- The same subscription will be reused for live sessions in the next PR.

`WinUIProfiler.Cli` shows what a trace contains, without the UI:

| Command | Shows |
| --- | --- |
| `processes <trace.etl>` | Event count per process, to find the
target's PID |
| `summary <trace.etl> --pid <pid>` | Event counts for that process, by
event name |
| `dump <trace.etl> --pid <pid> [--name <text>] [--max <n>]` | The
events in order, with their fields |

The README explains how to record a trace with `logman` and inspect it.
Adds `Microsoft.Diagnostics.Tracing.TraceEvent` 3.2.8; the
`packages.lock.json` changes come from restore.

The app's behavior does not change in this PR.

## Impact and risk

Developer tooling only, under `tools/WinUIProfiler`; no product code
changes. Low risk.

## How Has This Been Tested?

`tools/WinUIProfiler` has no test project yet, so this was validated
with the CLI on a 60 s trace of a WinUI 3 sample app. Run from
`tools/WinUIProfiler`:

| Command | Result |
| --- | --- |
| `dotnet build .\WinUIProfiler.Cli\WinUIProfiler.Cli.csproj -c Release`
| Passed, 0 warnings |
| `.\scripts\Build-App.ps1 -Configuration Release -Platform x64` |
Passed |
| `WinUIProfiler.Cli processes <trace>` | Target: 73,860 events (57,695
Microsoft-Windows-XAML + 16,165 Microsoft-Windows-XAML-Profiler), 0 lost
|
| `WinUIProfiler.Cli summary <trace> --pid <target>` | No manifest
events; `CoreServices_Frame`, `DependencyObject_Enter`,
`ElementEnteredTree`, `ChildAdded`, `CompPeerLinked` present |
| `WinUIProfiler.Cli dump <trace> --pid <target> --name
CoreServices_Frame --max 2` | Prints `IsStart` and `FrameNumber` per
frame |
| README `logman` steps from a non-elevated prompt | Trace recorded and
read by the CLI |

The Microsoft-Windows-XAML-Profiler events need a
`Microsoft.UI.Xaml.dll` built with `XamlProfilerEnabled=true`; the trace
used a local Release build with that setting, which is not part of this
PR.
2026-10-27 16:57:41 +05:30
Hemant KumarandCopilot App e73a0ae103 WinUI Profiler: read XAML TraceLogging events from .etl files
Add an event reader to WinUIProfiler.Core and a small developer CLI.

- OfflineEtlSource reads a recorded .etl with TraceEvent.
- XamlEventSubscription keeps TraceLogging events (ETW channel 11) from
  Microsoft-Windows-XAML and Microsoft-Windows-XAML-Profiler for one process
  and copies each into a ProfilerEvent. Manifest events are not read.
- WinUIProfiler.Cli: processes, summary and dump commands.
- README: how to record a trace with logman and inspect it.
- Adds Microsoft.Diagnostics.Tracing.TraceEvent 3.2.8.

The app's behavior is unchanged; it will use the reader for live ETW next.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
2026-10-27 16:50:25 +05:30
Akanksha PatelandCopilot bd03b2c662 Fix WinUI Profiler process identity and reconnect controls (#12413)
Fixes #
Internal Issue: https://task.ms/

<!-- Link either the public GitHub issue or the internal issue this PR
addresses. Remove the unused line. -->
<!-- PRs without a linked issue may be closed unless they are minor
documentation/typo fixes. -->

Addresses two review findings from #12406:
- [Preserve the selected process
identity](https://github.com/microsoft/microsoft-ui-xaml/pull/12406#discussion_r4385701293).
- [Restore reconnect controls when a connection
ends](https://github.com/microsoft/microsoft-ui-xaml/pull/12406#discussion_r4385930293).

## PR Type

<!-- Check the type of change. Limit each PR to one type when possible.
-->

- [x] Bugfix
- [ ] Feature
- [ ] Code style update (formatting, renaming)
- [ ] Refactoring (no functional changes, no API changes)
- [ ] Build related changes
- [ ] Documentation content changes
- [ ] Other (please describe):

## Description

<!-- Describe your changes in detail. -->

### Current Behavior
<!-- How does this work today? -->

- Selecting a process updates the PID textbox, but its queued
text-change event clears the saved process creation time and bypasses
the existing PID-reuse check.
- When a target exits or its connection fails, the view model retains
the finished connection. Connect and target options remain disabled
until the user clicks Disconnect.

### New Behavior
<!-- How will it work after this PR? -->

- Keep the selected process and creation time together. Set the
selection before updating the textbox, and invalidate it only when the
target text differs.
- Observe connection completion, dispose and unsubscribe the finished
connection, then release ownership and refresh the UI. Retain its metric
history, terminal status, and error details. Ignore an older completion
if it no longer owns the current connection.

## Customer Impact

<!-- How does this change affect end users? Is it user-facing or infra
changes? -->

Profiler users retain PID-reuse protection when selecting a running app
and can connect again after exit or failure without a redundant
Disconnect. Completed graphs and failure details remain available.

## Regression Potential

<!-- Could this change cause regressions? What areas might be affected?
-->

- [x] Low risk — isolated change, limited scope
- [ ] Medium risk — touches shared components or public APIs
- [ ] High risk — architectural or breaking API change

Only the profiler window and live-session view model change. No product
runtime, TAP protocol, public API, or layout changes.

## How Has This Been Tested?

<!-- Describe how you validated your changes. -->

- [x] I have performed a self-review of my own code
- [ ] I have added tests to cover my changes
- [ ] Existing tests pass locally

**Release x64 build: passed**

```powershell
$env:DOTNET_MSBUILD_SDK_RESOLVER_CLI_DIR = 'C:\Program Files\dotnet'
.\initrun.ps1 -Flavor amd64fre .\tools\WinUIProfiler\scripts\Build-App.ps1 -Configuration Release -Platform x64
```

**Real-app regression checks: 22 passed, 0 failed**

Ran a temporary external harness with `Run-Regression.ps1 -Label
fixed-sampling` against the built profiler and FolderTreeAppCpp. Checks
cover queued textbox events, edited-target invalidation, PID-reuse
rejection before injection, live metrics, target exit, unexpected
sampling completion, reconnect, event unsubscription, restored UI
controls, retained history/errors, and manual disconnect without
terminating the target. Both reported bugs were reproduced on the
unchanged app first.

The temporary harness was not added to the repository; no extra test
files are included in this PR. No existing automated test suite was run.

**Whitespace validation: passed**

```powershell
git diff --check
```

## Screenshots (if appropriate)

<!-- If you are making visual changes, include before/after screenshots.
-->

Not applicable; no layout or visual changes.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 18d84a18-e328-402b-b9ec-6a2269e43683
2026-10-27 16:12:02 +05:30
Saharsh Ananta Jaiswal e172a68fee Update standalone WinUIDetails fallback to 2.6.4-dev.experimental1D (#12405)
## Fixes

Internal Issue: https://task.ms/63217679

Related dependency fix: https://task.ms/64592557

## PR Type

- [x] Build related changes

## Description

### Current Behavior

Internal standalone builds default to `Microsoft.Internal.WinUIDetails`
`2.6.0-dev.experimental6` when no monobuild version is supplied.

### New Behavior

Update only that fallback to `2.6.4-dev.experimental1D`. Preserve
`WindowsAppSDKVersionPinned`, the later imported version-props mapping,
the OSS pin and all six companion fallbacks.

The selected package comes from a successful main-line producer on 24
October 2026; its normal-feed archive was verified against that
producer's package.

This is a dependency update, not a Charts or TableView source change.

## Customer Impact

Internal standalone builds consume the newer component package. OSS and
explicitly overridden monobuild selection are unchanged.

## Regression Potential

- [x] Medium risk — the selected native dependency changes; package
compatibility and runtime validation are still required.

## How Has This Been Tested?

- [x] I have performed a self-review of my own code.
- [ ] I have added tests to cover my changes.
- [ ] Existing tests pass locally.

- The ten-case MSBuild selection matrix passes before and after the
edit, covering standalone, OSS, explicit pin, imported props,
global-property precedence and malformed imports.
- The proposed package's signature is verified, and its normal-feed
archive matches the main-line producer package byte-for-byte.
- An isolated, uncached restore of the actual internal component project
selects the new package from the normal feed, with matching archive and
NuGet content hashes.
- Both unchanged real samples publish against the produced candidate
component. Their native control peers and package-bound modules were
observed at startup.
- Full baseline and candidate x64 Release builds, component packaging
and test-project compilation passed. Compilation coverage is separate
from the selected executions below.
- Selected headless tests passed in both lanes: 13 methods and 108
executions per lane, including 20 iterations each of three MockDComp
keyframe and two transform tests. The loaded MockDComp modules match the
restored packages.
- Final component dependencies are unchanged; component, test-input and
consumer-output hashes reconcile.
- The public PR Build workflow disables its compile matrix. Its green
checks are not architecture-build evidence; internal integration CI is
still required.
- Functional/regression, clean-shutdown, human accessibility and
required CI acceptance remain pending; startup observations are not a
substitute for those checks.
- Local results cover the recorded source snapshot, not subsequent main
changes or a new merge commit.

## Screenshots

Not applicable to this dependency-only diff.
2026-10-27 15:42:25 +05:30
Hemant Kumar 8f7d838788 Placeholder WinUIProfiler app with tap connection (#12406)
## Fixes

Fixes #
Internal Issue: https://task.ms/<ado-bug-id>

## PR Type

<!-- Check the type of change. Limit each PR to one type when possible.
-->

- [ ] Bugfix
- [x] Feature
- [ ] Code style update (formatting, renaming)
- [ ] Refactoring (no functional changes, no API changes)
- [ ] Build related changes
- [ ] Documentation content changes
- [ ] Other (please describe):

## Description

WinUIProfiler tool placeholder

### Current Behavior
N/A

### New Behavior
Standalone tool, which launches and connects to packaged/unpackaged or
already running app

## Customer Impact

<!-- How does this change affect end users? Is it user-facing or infra
changes? -->

## Regression Potential

<!-- Could this change cause regressions? What areas might be affected?
-->

- [x] Low risk — isolated change, limited scope
- [ ] Medium risk — touches shared components or public APIs
- [ ] High risk — architectural or breaking API change

## How Has This Been Tested?

<!-- Describe how you validated your changes. -->

- [x] I have performed a self-review of my own code
- [ ] I have added tests to cover my changes
- [ ] Existing tests pass locally

## Screenshots (if appropriate)

<!-- If you are making visual changes, include before/after screenshots.
-->
2026-10-27 12:43:09 +05:30
Abhijeet Jha 9449655062 ScrollViewer::OnPointerReleasedHandledEventsToo: clear stale press state (#12290)
Description:
Keep ToggleSwitch focused after selecting a NavigationView item without
suppressing application pointer handlers. Addresses #9331. Earlier
review discussion:
https://github.com/microsoft/microsoft-ui-xaml/pull/12255.

Root cause:
ScrollViewer sees the item's press but its normal release handler is
skipped when the child handles the release. The stale pressed flag then
lets a later toggle release move focus to ScrollViewer.

Fix:
Use handledEventsToo press/release listeners and a ScrollViewer-local
counter to clear the flag when the observed presses have completed.
Reset bookkeeping on unload. Remove the earlier core input and per-press
event-state changes.

Behavior:
Keep the existing normal focus decisions and application event delivery.
This change does not introduce a new focus policy for nested input.

Testing:
Native compilation/linking and targeted C#/XAML test
2026-10-27 12:01:26 +05:30
Saharsh Ananta Jaiswal d8ab570820 Localization Update 20261019 (#12403)
## Fixes

Internal Issue: https://task.ms/64340236

## PR Type

- [x] Bugfix
- [ ] Feature
- [ ] Code style update (formatting, renaming)
- [ ] Refactoring (no functional changes, no API changes)
- [ ] Build related changes
- [ ] Documentation content changes
- [ ] Other (please describe):

## Description

Brings the TableView translations from the 19 October localization
update to main. The six TableView strings added in #11820 now have
translations in all 85 supported languages.

### Current Behavior

12 of the 19 TableView strings are translated. The cell control type
("cell"), the cell and group-header name formats, the cell text
separator and the Boolean values fall back to English in every language.
Coverage is 1,020 of 1,615 string-language pairs (63.2%).

### New Behavior

18 of the 19 strings are translated: 1,528 of 1,615 pairs (94.6%). Two
gaps remain:
- `TableViewCellBlankName` (added in #12285) has no translations yet.
- The pt-PT and ug-CN translations of
`TableViewCellLocalizedControlType` are left out because both mean
"mobile phone". Those two languages keep the English "cell" until the
translations are corrected.

The returned `TableViewBooleanTrue` and `TableViewBooleanFalse` values
are identical to English in 13 and 14 languages, including zh-CN, zh-TW
and ko-KR.

Not included from the update:
- The `Microsoft.Internal.WinUILocalizationResources` bump to
3.0.0-experimental.261019.1, which is not on the OSS dependency feed.
- MapControl placeholder files, which have no translations yet.

## Customer Impact

User-facing. Screen readers announce TableView cells, cell and
group-header names and Boolean values from each language's resources
instead of falling back to English, apart from the gaps above.

## Regression Potential

- [x] Low risk — isolated change, limited scope
- [ ] Medium risk — touches shared components or public APIs
- [ ] High risk — architectural or breaking API change

Resource-only: 85 non-English `Resources.resw` files gain entries. No
code, English strings or existing translations change.

## How Has This Been Tested?

- [x] I have performed a self-review of my own code
- [ ] I have added tests to cover my changes
- [ ] Existing tests pass locally

- 83 files are byte-identical to the generated update; pt-PT and ug-CN
differ only by the one removed entry.
- Against main: 2,032 lines added, none removed. No existing value, file
header, encoding or line ending changes, and `en-us` is unchanged.
- All 85 files parse as XML, and the format placeholders (`%1!s!`,
`{0}`) match English in all 1,528 translated values.

## Screenshots (if appropriate)

Not applicable.
2026-10-27 10:59:13 +05:30
Neeraj VermaandCopilot 163f3a56ae Apply multiline coding style to native profiler metrics
Expand braced control flow, separate declarations and statements, and replace local lambdas with named file-scope helpers without changing metric behavior.

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

Copilot-Session: 0da43f78-cdc6-4dd3-b731-29dd185daded
2026-10-27 10:12:31 +05:30
Neeraj VermaandCopilot ff50256c5d Refine profiler charts, XAML UI and typed metric interop
Use quarter-second sampling with left-to-right two-minute charts and utilization scaling. Move dialogs and chart visuals into XAML, adopt the App SDK file picker, and replace byte-offset decoding with typed native contracts.

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

Copilot-Session: 0da43f78-cdc6-4dd3-b731-29dd185daded
2026-10-27 09:18:51 +05:30
Abhijeet Jha c8bfb0c3ef ResourceResolver::GetParentForResourceLookup: preserve flyout scope (#12344)
Description:
NavigationView child selection indicators ignore Grid-scoped
NavigationViewSelectionIndicatorForeground overrides when shown in a
flyout. Ordinary flyouts also miss owner-scoped resources in default
templates and code-set theme bindings. Fixes #8283.

Root cause:
ReparentRepeater moves the children under an internal Popup with no
parent. The resource walk stops there instead of continuing through the
associated flyout's declaring scope.

Fix:
Share GetParentForResourceLookup between live ThemeResource refresh and
SetThemeResourceBinding. Use the existing GetAssociatedFlyoutNoRef and
GetMentor APIs for template and ordinary flyouts, retaining the
visited-popup cycle guard. Fix test-host initialization using
App.TestContentRoot and wait for flyout closure before resource-test
teardown.

Behavior:
Nearer overrides and application/default fallbacks remain unchanged;
owner-scoped flyout colors follow theme changes. Local validation passes
190 AppPopup assertions and 14 targeted TAEF tests, including
ordinary/shared/nested flyouts and cyclic ownership. Remote CI
validation is still required.
2026-10-27 08:22:36 +05:30
Godly T.AliasandCopilot 79fe886bc8 Fix Window.DispatcherQueue use-after-free after XAML shutdown (#12346)
## Fixes

Internal Issue: https://task.ms/55026189

## PR Type

- [x] Bugfix
- [ ] Feature
- [ ] Code style update (formatting, renaming)
- [ ] Refactoring (no functional changes, no API changes)
- [ ] Build related changes
- [ ] Documentation content changes
- [ ] Other (please describe):

## Description

### Current Behavior

`Window.DispatcherQueue` is meant to be read from any thread; its
generated getter has no thread check. But
`Window::get_DispatcherQueueImpl` walked
`DesktopWindowImpl::m_dxamlCoreNoRef`, a raw `DXamlCore*` cached in the
constructor and never cleared.

A desktop app shuts XAML down on a thread when its last window closes,
which deletes that thread's core. If the app still holds the `Window`,
and a background thread then reads `Window.DispatcherQueue` (for
example, to marshal work back to the UI thread during shutdown), the
getter walks freed memory, and the app can crash with an access
violation. Crash dumps show exactly this: a closed window kept alive by
a managed reference, read from a thread-pool worker during process exit.

### New Behavior

- `WindowImpl` gets `get_DispatcherQueueImpl`, and `Window` delegates to
it.
- `DesktopWindowImpl` captures a weak reference to its thread's
`DispatcherQueue` once, in its constructor, and resolves it in the
getter. The getter never touches the core.
- While the window's XAML is running, the core's dispatcher holds the
queue, so the getter returns the same object as before.
- After XAML shuts down, it returns the shut-down queue while anything
still holds it, and `TryEnqueue` returns false. Once the queue is
destroyed it returns null, which the getter's
`_Outptr_result_maybenull_` contract already allows.
- The reference is weak because `DispatcherQueue` keeps its
`ShutdownStarting`/`ShutdownCompleted` handlers until it's destroyed. A
strong reference would leak any window captured by such a handler.
- `UWPWindowImpl` keeps its existing lookup.

The new regression test
`XamlIslandTests::GetDispatcherQueueFromThreadpoolAfterCoreShutdown`:

1. closes a `Window` that it keeps alive;
2. shuts that thread's XAML down and verifies the core is gone;
3. reads `Window.DispatcherQueue` from an MTA thread-pool worker.

It checks that the same queue is returned before `Close`, after `Close`
and after shutdown, and that `TryEnqueue` then returns false.

## Customer Impact

Apps that read `Window.DispatcherQueue` from a background thread around
shutdown no longer crash in the getter. Once the window's queue has been
destroyed, the getter returns null, so callers on other threads should
null-check it. Behavior while a window's XAML is running is unchanged.

## Regression Potential

- [x] Low risk — isolated change, limited scope
- [ ] Medium risk — touches shared components or public APIs
- [ ] High risk — architectural or breaking API change

While XAML is running, the getter returns the same object as before.
Behavior changes only where the old code read freed memory, or during
core teardown, where the old lookup could return null. The weak
reference adds no lifetime extension or reference cycle. The member is
immutable after construction, so reading it from other threads is safe.

## How Has This Been Tested?

- [x] I have performed a self-review of my own code
- [x] I have added tests to cover my changes
- [ ] Existing tests pass locally

Validated on amd64chk on an internal branch that predates #12268 and
#11982, with and without the fix:

| | With fix | Without fix |
|---|---|---|
| New regression test | Passes | Access violation in the getter's core
walk |
| XamlIslandTests, Helix query, Win32Explicit (46 tests on that branch)
| 40 pass | 39 pass; the extra failure is the new test |
| WindowIntegrationTests, Helix query, WPF (42 tests on that branch) |
42 pass | 42 pass |

Six other XamlIslandTests fail on that machine both with and without the
fix; they are unrelated to this change.

Among the files this fix touches or depends on, that branch differs from
`main` only in these, none of which affect the fix:
- Its `DesktopWindowImpl.cpp`/`.h` lack #12268, which changes only the
Width/Height setters after `Close`.
- Its
`WindowsXamlManager_Partial.cpp`/`FrameworkApplication_Partial.cpp` lack
#11982's shutdown changes. On `main` the core is still deleted at
shutdown, and the test keeps the queue alive.
- Its `XamlIslandTests.cpp`/`.h` lack #11982's new tests, hence the
different test count.
- `Window_Partial.cpp`, `UWPWindowImpl.*`, `WindowImpl.h`,
`DXamlCore.cpp` and `xcpwindow.cpp` are byte-identical.

Not built on `main` locally; relying on PR CI.

## Screenshots (if appropriate)

Not applicable; no visual change.

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 84bf8dd5-9217-47bc-a3f9-88bffebaff37
2026-10-27 07:39:16 +05:30
Hitesh KumarandCopilot b22743a863 TableView: reorganize and order IDL files (#12382)
Reorganizes the IDL files added for the TableView effort so they match
the layout and ordering of established controls (ItemsView, ScrollView,
SelectorBar, InfoBar, TeachingTip, Repeater,
`controls/idl/Microsoft.UI.Xaml.Controls.idl`). It also moves the IDL
comment notes into the TableView dev spec and rewrites that spec to be
accurate and concise. No API is added, removed or renamed.

### Files
- `controls/dev/TableView/TableView.idl`
- `controls/dev/TableView/TableViewSource.idl`
- `controls/dev/dll-tabular/Microsoft.UI.Xaml.Controls.Tabular.idl`
- `controls/dev/ResizeGripper/ResizeGripper.idl`
- `controls/dev/ResizeGripper/ResizeGripperAutomationPeer.idl`
- `controls/dev/TabularShaping/SortDirection.idl`
- `docs/design-notes/TabularControls/TableView-dev-spec.md`

### IDL changes
- **Type order:** enums, interfaces, column classes, event args (in the
same order as the events), helper classes, the control, then automation
peers (in the same order as the helpers).
- **Member order:** constructor, properties, methods, events, then
statics. Dependency-property statics follow the order of their
properties.
- **Formatting:** matches the reference IDLs.
- **Comments:** documentation and rationale comments moved into the dev
spec. A coverage check confirms all 111 comment blocks are captured.
Only one-line "do not ..." guard comments stay in the IDLs
(SortDirection namespace, Tabular IDL ordering and namespace,
ResizeGripper private namespace, frozen overload metadata on
`TableViewSource`), and each points to the dev spec.

### Dev spec changes
- **Size and structure:** rewritten to be accurate, concise and
consistent with the other dev specs in the repo (TitleBar, SelectorBar).
It went from about 14,200 to about 4,900 words and follows the repo
template order: Description, Design considerations, Architectural
overview, Performance, Debugging, Implementation details, Appendix.
- **Content:** IDL notes are folded into the feature sections.
Duplicated and stale text is removed.
- **Accuracy:** every claim was cross-checked against the code, and
about 30 incorrect or outdated statements were fixed. Examples:
- the "Key public components" list now matches the IDLs (removed
`TableViewEditingUnit`, `TableViewEditAction.Discard` and the public
editing hooks)
  - no edit deferral in this release
  - row template parts and states
  - the body repeater's `ItemTemplate` is `TableViewRowTemplateSelector`
  - header scroller mode and row cache length
  - the cell wrapper is a `Grid`
- cell UIA control type, and `ITransformProvider` on the column-header
peer
  - keyboard map and density resource keys
  - why `TableView` is unsealed
- **Cited wording kept:** headings and phrases cited by code comments
("Keyboard", "Re-shape while focused", "Sticky headers", etc.) are
unchanged.

### ABI note
Member reordering changes the vtable order and IIDs of `ITableView`,
`ITableViewColumn`, `ITableViewColumnStatics`, `ITableViewSource` and
the private `IResizeGripper`.
- All TableView types are `[MUX_PREVIEW]` (Feature_Experimental), and
ResizeGripper is `[MUX_INTERNAL]` in the private namespace.
- Preview consumers, including C# `TableViewColumn` subclasses, need to
rebuild.
- `ITableViewColumnOverrides`, `ITableViewStatics` and
`ITableViewSourceStatics` are unchanged.

### Follow-ups (not in this PR)
- The API spec (`docs/api-specs/TableView/TableView-spec.md`) still
calls column resize "planned" and says duplicate row identity always
fails fast. Update it, and move the dev spec's "API notes not yet in the
API spec" appendix into it.
- About 100 code and test comments cite `TableView.idl:<line>` or
`dev-spec:NNN` line numbers. Rewrite them to section names.
- A few code comments in `TableView.h` and `TableView_Editing.cpp` still
mention a "deferral" that doesn't exist.

### Validation
- **IDL equivalence:** a script that strips comments and whitespace and
compares types, attributes and members confirms the six IDLs differ only
in order and comments.
- **Build:** the Tabular idl and dll projects build with 0 warnings and
0 errors, and checked-in generated files are unchanged.
- **WinMD comparison** (Tabular, Private.Controls, XamlTypeInfo) against
main: identical types, members, signatures and attributes. The only
differences are the 5 IIDs above.
- **Tests:** the TableView suite (882 tests) ran on a test VM. 876
passed and 3 are `[Ignore]`. The remaining 3 failed or hung in the full
run but passed when rerun alone on this branch and on the baseline. The
grouped automation-peer chunk hangs intermittently on both this branch
and baseline. Later commits change only type order, comments and docs.
- **Dev spec:** independent fact-check and readability reviews were run,
and all findings are addressed. A final review of the last fixes found
two issues, both corrected.

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 7e074e0a-bef2-4f87-ae83-4ebdf5da11b2
2026-10-27 01:55:58 +05:30
Neeraj VermaandCopilot 56d45d2665 Replace profiler UI polling with change notifications
Publish connection/heartbeat and committed-sample changes through the session view model. Coalesce notifications on the UI dispatcher, skip unchanged chart histories, and detach publishers during disconnect and window shutdown.

Validate Debug/x64 production build, session-only notification RED/GREEN checks, and actual target UI state, heartbeat, metrics, reconnect, exit and shutdown without restoring test files to the branch.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 0da43f78-cdc6-4dd3-b731-29dd185daded
2026-10-26 18:12:29 +05:30
Neeraj VermaandCopilot 357f33ea05 Remove tests from profiler executable placeholder
Remove managed/native test projects, UI/build test scripts and generated test artifacts. Drop test-only package versions, friend-assembly access and stale test documentation while preserving production components.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 0da43f78-cdc6-4dd3-b731-29dd185daded
2026-10-26 17:41:02 +05:30
Saharsh Ananta Jaiswal e43de2ad2c TableView: TiP attribution, per-operation TiP tests and TableView_Instance telemetry (#12301)
Builds on #12120. TableView's TiP blames the app only when its own code
decided the outcome, each key operation has its own TiP test and
measure, and telemetry records one event per table load.

## TiP tests
| Test | Measure | Fails with |
|---|---|---|
| Initialize | 64477764 | `template_setup_failed`,
`source_attach_failed` |
| Sort | 64745033 | `sort_failed` |
| Edit begin | 64745034 | `edit_begin_failed` |
| Edit commit | 64745035 | `edit_commit_failed` |
| Filter | 64745036 | `filter_failed` |
| Expand or collapse one group | 64745037 | `group_expansion_failed` |
| Expand or collapse one tree node | 64745038 |
`hierarchy_expansion_failed` |

- A test fails, with the HRESULT, only when TableView's own code throws.
App code's exceptions are tagged where TableView calls it, so the test
closes Ignored (`application_fault`) only when one of them decided the
outcome.
- Column code: the editing hooks are TableView's for every column,
except where they realize or focus a `CellEditingTemplate`'s content.
That content, and the overrides of a column class the app derived, are
the app's.
- Initialize runs from the template applied with a source attached until
the first row or group header is laid out. Unloaded before that with
rows and a body viewport, it closes Ignored as `unloaded_before_render`;
otherwise as `unloaded`.
- The metrics bucket is the flow direction and whether the source has at
least 1,000 rows before the filter. The metrics carry both row counts.
- No test runs for selection, a source swap after Initialize, a
cancelled edit, group configuration, a subtree expansion or an expansion
request that changes nothing. A failure in any of them still writes
`TableView_Error`.
- A process exit while a test runs is recorded by TiP as that test's
failure, and so is a crash or hang on Windows builds whose Error
Reporting recovers TiP results.
- 64477774, the old combined operation test, is retired after this
merges.

## Telemetry
- `TableView_Instance` (one per load) replaces
`TableView_SessionSummary`: enabled and used features, source-row,
data-row and realized-row buckets, column and source kinds, RTL, and an
incomplete template.
- An app filter predicate, sort or group key selector or custom comparer
that throws is still contained, and now writes one recoverable
`TableView_Error` per operation with the first HRESULT and a
`FaultCount`, also when the operation then fails. A verb an app delegate
starts inside another counts only its own.
- Scrolling is not measured in the field; scroll performance is left to
a lab benchmark.

## Validation
- 28 operation, 15 Initialize and 20 `TableView_Instance` cases, checked
from captured ETW events of the final build. The 7 operation and
Initialize cases whose behavior changes also ran on `f6c060a` and differ
there; the other 22 operation cases match it.
- 175 earlier cases rerun against `42b575b`: 174 identical; the other
now also reports a group key that threw inside a filter that then threw
an app data fault, as intended.
- A local fault-injection build forces 19 failure paths, including
built-in and app-derived column code, TableView's own code around a
`CellEditingTemplate` editor, failures after contained app delegates, an
unload before the first row's layout pass, and a swallowed app
exception. TableView's own failures fail their test with its reason and
the HRESULT; an app-tagged one closes Ignored.
- UI Automation walkthrough of the final build (sort, edit, filter,
group, tree node, selection): 13 successes, each under its own measure,
none for selection, and no `TableView_Error`.
- MSBuild: an internal pipeline build fails when the TiP package or its
config is missing; the real package, the opt-out, local builds and
external pipelines pass. A build with the public stub compiles.

## Notes
- Versions start at 1 (`SchemaVersion`, `InstanceVersion`, both TiP data
versions), since nothing has shipped.
- Internal pipeline builds (`IsInternalWinUIBuild` and `TF_BUILD`) fail
when Tabular falls back to the public TiP stub;
`UseTestInProductionStub=true` chooses it on purpose.
- The dev spec's "Telemetry and TiP" section documents every event,
test, field and known gap.
- Left out of the telemetry plan: a resource-load outcome (a missing
`TabularControlsResources` fails at XAML parse) and separate "reached
past the box" bits (`ColumnKinds` covers them).
- Commits: `TableView_Instance` (`1737209`), Initialize (`6687f88`),
per-operation tests (`1f82669`), review fixes (`927f474`), merge with
main after #12307 (`42b575b`, conflicts in `BeginEdit` and the sort
apply path), Copilot review fixes (`1f66475`). Review with whitespace
hidden.
2026-10-26 16:34:21 +05:30
Saharsh JaiswalandCopilot 53d167f57b build: refresh standalone WinUIDetails fallback
Update only the internal WinUIDetails fallback; preserve the OSS pin, monobuild overrides and companion versions.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 9d4612db-43aa-4271-86fa-b1b43d45d9c3
2026-10-26 16:24:50 +05:30
Neeraj VermaandCopilot 92621d39e3 Add standalone WinUI profiler executable baseline
Support packaged/unpackaged launch and running-process attach through an authenticated hello-only diagnostics TAP. Start independent CPU/GPU and process-memory combined graphs after the real TAP connection; preserve the target on cancellation, disconnect and shutdown.

Include self-contained x64/ARM64 builds, architecture-matched payload deployment, bounded metric histories and managed/native/UI/build-entry validation.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 0da43f78-cdc6-4dd3-b731-29dd185daded
2026-10-26 15:53:21 +05:30
ayushjai19 5aab9d7579 NavigationView: don't clip PaneFooter/PaneCustomContent item icons in closed compact pane (#12319)
## Fixes

Fixes #10415
Fixes #11108

## PR Type

- [x] Bugfix

## Description

A `NavigationViewItem` placed directly in `NavigationView.PaneFooter`
(or `PaneCustomContent`) has the right ~2px of its icon clipped when the
pane is closed in compact mode (`LeftCompact`, or `Left`/`Auto` with the
pane closed). `FooterMenuItems` and `MenuItems` are not affected.

**Root cause:** the left-pane item presenter template gives
`ContentGrid` a `Margin="0,0,14,0"` so content lines up with the
expand/collapse chevron. The `ClosedCompactAndTopLevelItem` presenter
state removes that margin, but
`NavigationViewItem::UpdateVisualStateForClosedCompact` only selects
that state when `IsTopLevelItem()` is true. `IsTopLevelItem` is set only
in `NavigationView::OnRepeaterElementPrepared`, so items that live in
`PaneFooter`/`PaneCustomContent` (not created by a NavigationView-owned
repeater) never get it. In a 48px compact pane the item's
`PresenterContentRootGrid` is 40px. The 14px margin leaves a 26px slot
for `ContentGrid`, which needs 40px for the icon column, so layout clips
it at x=30. The 16px icon spans x=16..32, so its right edge gets cut.

PR #5039 (#4482) already fixed the icon *width* binding for PaneFooter
items. This PR fixes the remaining *margin* problem.

### Current Behavior
In a closed compact pane, PaneFooter/PaneCustomContent items keep
`ContentGrid.Margin = 0,0,14,0` and the right ~2px of the icon is
clipped. A Message glyph measures x=16..29 instead of 16..31. In the
#11108 screenshot, the power icon is 2px narrower than the menu icons.

### New Behavior
`NavigationViewItem::UpdateVisualStateForClosedCompact` also treats an
item as root-level when it is hosted in the left pane's `PaneFooter` or
`PaneCustomContent`. A new helper,
`NavigationView::IsInLeftPaneFooterOrCustomContent`, walks up the visual
tree and returns true only if it reaches
`FooterContentBorder`/`PaneCustomContentBorder` before another
`NavigationViewItemBase` or the NavigationView itself. These items now
get exactly the same layout as top-level menu items: no clipping in
closed compact, and unchanged when the pane is open. Everything else
keeps the old `IsTopLevelItem()` value: NVIs in
`NavigationView.Content`, NVIs nested in another item, and
recycled/unparented items. The walk only runs while the pane is closed
compact, for items that aren't in a NavigationView-owned repeater.
`NavigationViewItem` also re-prepares on every `Loaded` (hooked once in
the constructor; SplitView subscriptions are re-pointed, not duplicated)
and then calls `ReparentRepeater()`. `NavigationViewItemBase::OnLoaded`
re-resolves the ancestor NavigationView for items outside an NV-owned
repeater. So an item reused across hosts gets the right closed compact
state in each host: MenuItems → PaneFooter → Content, Content →
MenuItems, or moved to another NavigationView. For hierarchical items
moved to another NavigationView, the child repeater stays wired to the
original NavigationView; that is pre-existing and out of scope.
## Customer Impact

User-facing visual fix. Footer buttons like "Exit"/"Log out" in a
compact NavigationView render their icon fully, the same as menu items.
It also covers NVIs in `PaneCustomContent` (reported in the #10415
comments). Apps no longer need the `CompactPaneLength=52` workaround.

## Regression Potential

- [x] Low risk — isolated change, limited scope

Only NVIs hosted in the left pane's PaneFooter/PaneCustomContent are
affected, and only while the pane is closed compact. Items in
`MenuItems`/`FooterMenuItems`, hierarchical children and flyout children
all go through NV-owned repeaters and are unchanged. NVIs in
`NavigationView.Content` are unchanged (covered by a negative test). In
Left (open), LeftMinimal and Top modes nothing changes. Every path that
changes the inputs (IsPaneOpen, PaneDisplayMode,
Compact/ExpandedModeThresholdWidth, resize in Auto, IsPaneVisible,
CompactPaneLength, footer content set or moved at runtime, template
re-apply) re-evaluates the state through the item's existing SplitView
listeners or `Loaded`. The runtime ones are covered by a test.
## How Has This Been Tested?

- [x] I have performed a self-review of my own code
- [x] I have added tests to cover my changes
- [x] Existing tests pass locally (see notes)

New API tests in `NavigationViewTests`:
- `VerifyPaneFooterItemIsNotClippedInClosedCompactPane`: `LeftCompact`
with a closed pane, a menu item, a PaneFooter NVI and a
PaneCustomContent NVI. Checks the presenter state, checks that the icon
column fits in ContentGrid's layout slot, and does an open → close round
trip.
- `VerifyContentAreaItemKeepsLayoutInClosedCompactPane` (negative): an
NVI in `NavigationView.Content` keeps its normal layout.
- `VerifyHierarchicalPaneFooterItemIsNotClippedInClosedCompactPane`: a
PaneFooter NVI with children isn't clipped.
- `VerifyItemReusedFromMenuItemsRefreshesClosedCompactStateOnEveryHost`:
an item realized in `MenuItems`, moved to `PaneFooter`, pane
opened/closed, then moved into `Content`. Checks the state and InfoBadge
placement in each host.
- `VerifyItemMovedFromContentToMenuItemsGetsClosedCompactState` and
`VerifyItemMovedToAnotherNavigationViewFollowsItsPane` (NavView A
PaneFooter → B PaneFooter → B MenuItems; the item follows B's pane
state).
- `VerifyPaneFooterItemClosedCompactStateFollowsRuntimeChanges`: the
footer is set after load, then runtime
`ExpandedModeThresholdWidth`/`CompactModeThresholdWidth`/`PaneDisplayMode`
changes, and the item is moved PaneFooter → PaneCustomContent → Content.

Results (full builds on the test VM):
- Test-only commit 88d024ef0 on main:
`VerifyPaneFooterItemIsNotClippedInClosedCompactPane` **fails** as
expected (PaneFooter/PaneCustomContent in
`NotClosedCompactAndTopLevelItem`, `IsLessThanOrEqual(40, 26)`).
- Red for the review-round tests (scratch = old condition + new tests,
not pushed): `VerifyContentAreaItemKeepsLayoutInClosedCompactPane`
**fails** (`AreEqual(NotClosedCompactAndTopLevelItem,
ClosedCompactAndTopLevelItem)`), and
`VerifyPaneFooterItemClosedCompactStateFollowsRuntimeChanges` **fails**
at "Moved to the content area". `VerifyPaneLayoutSwappingCollections`
passes there, which confirms the sweep failure below was a flake.
- Reverse/cross-NavigationView moves: both new tests **fail** on
bb2a413b3 (tests on the 0499ee207 product) and **pass** on
5e358f0d4/1b3323fa0. Final sweep on 5e358f0d4: API 42/48 (5
main-baseline failures + a since-fixed test bug), PaneBehaviorTests
33/34 (baseline), CommonTests 45/46 (one TAEF host-crash flake that
passed on re-run), SelectionTests 18/18, TopModeTests 17/17. **0
regressions vs main.**
- Reused-item test: **fails** on the test-only commit 540eb5dcd (still
`ClosedCompactAndTopLevelItem` in Content, InfoBadge column 0/Top) and
**passes** with the fix 0499ee207. API class 41/46 (the 5 failures are
the main baseline), `CommonTests.*PaneFooter*` 2/2.
- Commit 20648440b: **all 4 new tests pass**. Sweep:
`ApiTests.NavigationViewTests` 40/45 (the 5 failures also fail on main
866ba81a1), `PaneBehaviorTests` 33/34, `CommonTests.*PaneFooter*` 2/2.
The one PaneBehaviorTests failure
(`VerifyPaneLayoutSwappingCollections`) is a UIA `COMException
0x80040201` thrown in `TestSetupHelper` before the test page loads; it
passes on main. **0 regressions vs the main baseline.**
- Manual: a WinAppSDK 1.8 repro app with a layout dump +
`RenderTargetBitmap` showed footer `ContentGrid` margin `0,0,14,0` and
the glyph clipped at x=30. Forcing the fixed state restores the full
glyph.
## Screenshots (if appropriate)

Before (zoomed, same Message glyph): menu item vs PaneFooter item in
LeftCompact. The footer copy loses its right 2px. In the #11108
screenshot, the power icon measures x=21..34 vs x=21..36 for the menu
icons.
2026-10-26 15:17:38 +05:30
Saharsh JaiswalandCopilot a0a9858a91 Localization Update 20261019
Bring the TableView translations from the 19 October localization
update to main. The six TableView strings added in #11820 are now
translated in all 85 supported locales.

The pt-PT and ug-CN translations of the cell control type ("cell") are
left out because both mean "mobile phone". Those two locales keep the
English text until the translations are corrected.

Not included from the update: the localization resource package bump,
which is not on the OSS dependency feed, and the MapControl placeholder
files, which have no translations yet.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 92bba586-bebe-4dd6-8f1d-28a868960e3b
2026-10-26 15:05:35 +05:30
Nitin Chaudhary 4ce52241eb InkToolbar: make the toolbar's keyed resources visible to app XAML (#12296)
**What:** InkToolbar's keyed brushes, styles, and sizes can be used from
app XAML (for example `{StaticResource InkToolbarCommonButtonStyle}`).
Split out of #12163. XAML move only; no values change.

**Why:** On `main` every such reference fails with `0x802B000A`
(resource not found). The resources are in `InkToolbar.xaml`, which ends
up in the controls `generic.xaml`. XAML only uses that for default
styles; app `{StaticResource}` / `{ThemeResource}` lookups never search
it. Snipping Tool copied the resources into its own dictionary as a
workaround.

**UWP:** the resources were in the system `generic.xaml`, which app
lookups do search. The Windows SDK copy
(`UAP\10.0.26100.0\Generic\generic.xaml`) has 41 `InkToolbar*` brushes
and sizes in each theme plus 10 top-level `InkToolbar*` styles.

**Fix:** move them to `InkToolbar_themeresources.xaml`, which is merged
into `XamlControlsResources` like every other control's theme resources.
All 59 theme keys are defined in each of `Default`, `Light`, and
`HighContrast`.

**Tested:** a test app loads markup that references each key.

| Key | 2.5.4-experimental | `main` | This PR |
|---|---|---|---|
| `InkToolbarGlyphFontStyle`, `InkToolbarCommonButtonStyle`,
`InkToolbarFlyoutStyle` | fail | fail | **resolve** |
| `InkToolbarAccentColorForegroundThemeBrush`,
`InkToolbarButtonBackground`, `InkToolbarButtonWidth` | fail | fail |
**resolve** |
| `InkToolbarAccentColorThemeBrush` (UWP-only name) | fail | fail | fail
(never defined in WinUI) |

A default InkToolbar screenshot (light theme, 700×120 px) on `main` vs
this PR: 0 differing pixels. New API test:
`InkToolbarTests.InkToolbarKeyedResourcesAreAppVisibleTest`.
2026-10-26 11:09:12 +05:30
Akanksha Patel ff21107d94 Emit owning-element identity on remaining XAML framework ETW events (#12179)
## Fixes

<!-- Link either the public GitHub issue or the internal issue this PR
addresses. Remove the unused line. -->
<!-- PRs without a linked issue may be closed unless they are minor
documentation/typo fixes. -->

Combines #11959 and #12116 into one PR targeting `main`. No separate
issue is linked.

## PR Type

<!-- Check the type of change. Limit each PR to one type when possible.
-->

- [ ] Bugfix
- [ ] Feature
- [ ] Code style update (formatting, renaming)
- [ ] Refactoring (no functional changes, no API changes)
- [ ] Build related changes
- [ ] Documentation content changes
- [x] Other (please describe): Profiler-only ETW instrumentation and
core-object identity correlation.

## Description

<!-- Describe your changes in detail. -->

### Current Behavior
<!-- How does this work today? -->

Several XAML operation events lack a usable core-object identity,
particularly on both edges of an activity. This makes it difficult to
correlate layout, focus, selection, virtualization, hit-testing, and
related operations with visual-tree records. A generic dependency-object
pointer also cannot always be treated as a UI-element identity: a
Hyperlink, for example, is not a `CUIElement`.

Some existing events already identify their UI object using `ElementId`
or `ObjectPointer`. This PR does not rename those existing schemas.

### New Behavior
<!-- How will it work after this PR? -->

Adds a shared `XamlElementTracing` emitter and runtime identity
resolver, with **43 operation names (26 activities and 17 point events)
across 71 emission sites in 21 source files**.

#### Provider and build behavior

- The operation events are self-describing TraceLogging events on
**`Microsoft-Windows-XAML`**, GUID
`{531A35AB-63CE-4BCF-AA98-F88C7A89E455}`, using the existing
`XamlTelemetryLogging` registration.
- The existing four-tree events remain on
**`Microsoft-Windows-XAML-Profiler`**. Their schemas are unchanged.
Enable both providers when collecting operation-to-tree correlation
data.
- New instrumentation is guarded by `XAMLPROFILER_ENABLED`. Retail
builds retain their existing manifest events and payloads.
- Profiler-enabled builds generally replace the corresponding manifest
emission with the identity-bearing TraceLogging emission.
`RealizeTransition` is an additional per-element point inside the
existing pass-level activity. `GenerateMCContainer` uses a point at
container realization instead of the manifest Begin/End pair in profiler
builds.
- Identity resolution runs only when the operation provider is enabled
at Verbose level.
- Guarded `XamlProfilerTracing.h` includes move into the relevant
`precomp.h` files, replacing repeated includes in implementation files.

#### Identity payloads

| Subject | Fields emitted | Meaning |
|---|---|---|
| UI element, including a control | `ElementId` | The subject's core
`CUIElement*` address, serialized as `uint64_t`. |
| Non-UI dependency object with a known UI host | `objectpointer`,
`ElementId` | The subject's core `CDependencyObject*` address and its
associated UI host's `CUIElement*` address. |
| Non-UI dependency object without a known UI host | `objectpointer` |
The subject's core dependency-object address; no UI identity is
invented. |
| Null subject | `objectpointer = 0` | No `ElementId`, even if an owner
argument was supplied. |

Controls use the same `ElementId` field as other UI elements; no
redundant control-pointer field is emitted. These are core addresses,
not assigned IDs or DirectUI/WinRT wrapper addresses.

For non-UI subjects, known-owner correlation covers:

- Text elements such as Hyperlink: the existing containing
TextBlock/RichTextBlock lookup.
- `PrepareContainer`: the preparing ItemsControl.
- `SetupCCC`: the ListViewBase owner.
- `GenerateContainer` Stop: the generator host, when it supports
`IUIElement`.

A UI subject always keeps its own identity rather than being replaced by
its owner's. Arbitrary dependency-object parent walking is not added. A
containing text host is not necessarily the RichTextBlockOverflow
rendering a particular run.

`ElementId` can be joined with `ElementEnteredTree.ElementId` and
`CompPeerLinked.UIElementId` within the same process and object
lifetime. This does not guarantee that every operation has an entry
record in a particular capture, or that every entered element generates
an operation. Layout-pass events identify the layout root, not every
child measured or arranged.

#### Activity events

Both Start and Stop carry the subject's identity using the rules above.
`GenerateContainer` Start is the exception: it has no identity because
the container has not yet been resolved. Other operation-specific fields
are retained on the applicable edge.

| Event | Subject | Additional payload / edge behavior |
|---|---|---|
| `FireLayoutUpdated` | Layout root | Identity on Start and Stop. |
| `FireSizeChanged` | Layout root | Identity on Start and Stop. |
| `IndividualSizeChanged` | Element receiving the size-change
notification | Identity on Start and Stop. |
| `PutRootVisual` | Public root visual | Identity on Start and Stop. |
| `Layout` | Layout root | Identity on Start and Stop. |
| `Measure` | Layout root | Whole measure pass, distinct from existing
per-element `MeasureElement` events. |
| `Arrange` | Layout root | Whole arrange pass, distinct from existing
per-element `ArrangeElement` events. |
| `CancelTransitions` | Transition target | Identity on Start and Stop.
|
| `ProcessLayoutForTransition` | Transition target | Identity on Start
and Stop. |
| `UpdateFocus` | Requested target on Start; `pNewFocus` on Stop |
Identities can differ after focus redirection; Stop is also emitted on
cancellation/error paths. |
| `XYFocusEntered` | Current focused element or hosted component used
for navigation | Start includes `Direction`. |
| `ChangeSelection` | Owning text control | Identity on Start and Stop.
|
| `ExtendSelectionRange` | Owning text control | Identity on Start and
Stop. |
| `GenerateContainer` | Generated container on Stop | Start has no
identity; Stop resolves the container and optional UI host. |
| `GenerateItems` | Generating panel | Identity on Start and Stop. |
| `PlaceElement` | Realized container | Start includes `DataIndex`. |
| `PrepareContainer` | Container being prepared | Uses the preparing
ItemsControl as host only for a non-UI container. |
| `MeasureChild` | Child being measured | Identity on Start and Stop. |
| `VirtualizationMeasure` | WrapGrid | Identity on Start and Stop. |
| `VirtualizationAdd` | Container being added | Identity on Start and
Stop. |
| `VirtualizationCleanup` | Virtualizing panel | Identity on Start and
Stop. |
| `UpdateLogicalScrollData` | Virtualizing panel | Identity on Start and
Stop. |
| `GetElementCount` | Core object whose descendants are counted |
Identity on Start and Stop. |
| `GetBuiltInStyle` | Control, not the returned style | Stop includes
`StyleName`. |
| `HitTest` | Subtree being hit-tested | Identity on Start and Stop. |
| `SetupCCC` | Container being set up | Start includes `ItemIndex`; a
non-UI container can be linked to the ListViewBase owner. |

#### Point events

Each point carries the subject's identity plus the listed
operation-specific payload.

| Event | Subject | Additional payload |
|---|---|---|
| `RealizeTransition` | Transition element | None. |
| `TouchSelectionGripperShowBegin` | Gripper element | `IsStartGripper`,
`X`, `Y` |
| `TouchSelectionGripperShowEnd` | Gripper element | `IsStartGripper`,
`X`, `Y` |
| `TouchSelectionGripperHideBegin` | Gripper element | `IsStartGripper`,
`X`, `Y` |
| `TouchSelectionGripperHideEnd` | Gripper element | `IsStartGripper`,
`X`, `Y` |
| `TouchSelectionGripperReposition` | Gripper element |
`IsStartGripper`, `X`, `Y` |
| `GenerateMCContainer` | Realized container | `Index` |
| `VirtualizationIsEnabledByLayout` | ListViewBase |
`IsVirtualizationActive`, `ElementName`, `ClassName`, `ParentClassName`
|
| `OuterBoundsStats` | Hit-tested subtree | `RecalculatedCount`,
`ReusedCount` |
| `InnerBoundsStats` | Hit-tested subtree | `RecalculatedCount`,
`ReusedCount` |
| `ContentBoundsStats` | Hit-tested subtree | `RecalculatedCount`,
`ReusedCount` |
| `ChildBoundsStats` | Hit-tested subtree | `RecalculatedCount`,
`ReusedCount` |
| `HubSectionCount` | Hub | `SectionCount` |
| `FrameNavigated` | Frame, not its content | `Descriptor`,
`NavigationMode` |
| `FrameNavigating` | Frame, not its content | `Descriptor`,
`NavigationMode` |
| `SendInputScopeToRichEdit` | PasswordBox | `InputScope` |
| `SetIhmKeyboardSkin` | PasswordBox | `KeyboardSkin` |

#### Scope boundaries

- Existing `FrameworkElement_ApplyTemplate` and
`Control_RefreshTemplateBindings` events retain their `ObjectPointer`
fields. No duplicate `ElementId` field is added to them.
- Existing four-tree schemas and profiler-viewer ingestion/display are
unchanged.
- The added profiler identity test and performance inventory document
have been removed; neither remains in the final PR diff.

## Customer Impact

<!-- How does this change affect end users? Is it user-facing or infra
changes? -->

Diagnostic improvement for profiler-enabled builds: consumers can
attribute operations to core UI elements and identify supported
non-UI-to-UI relationships without relying only on activity nesting. No
public API or user-facing behavior change is intended; retail event
schemas remain unchanged.

## Regression Potential

<!-- Could this change cause regressions? What areas might be affected?
-->

- [x] Low risk — isolated change, limited scope
- [ ] Medium risk — touches shared components or public APIs
- [ ] High risk — architectural or breaking API change

Primary risks are profiler event attribution/pairing, conditional
payload interpretation, and PCH include coverage. The instrumentation is
compile-time gated; existing retail emissions are preserved.

## How Has This Been Tested?

<!-- Describe how you validated your changes. -->

- [x] I have performed a self-review of my own code
- [ ] I have added tests to cover my changes
- [ ] Existing tests pass locally

Validation for head `9ccaabc00dd653e675647afe21ec29f7bd1fbce7`:

| Command | Result |
|---|---|
| `.\initrun.ps1 msb /q
"dxaml\xcp\dxaml\dllsrv\winrt\native\Microsoft.ui.xaml.vcxproj"` |
Passed: current amd64chk/Debug runtime build, 0 warnings and 0 errors. |
| `git --no-pager diff --check origin/main...HEAD` | Passed. |
| `gh pr checks 12179 --repo microsoft/microsoft-ui-xaml` | Passed: all
reported GitHub checks were green when this description was updated.
This is not a claim that the full local test suite ran. |

Earlier development validation used FolderTreeAppCpp and an ETW capture
to confirm that container-operation identities matched visual-tree
entries, Hyperlink focus records linked to the containing TextBlock, and
UI-to-composition-to-WUC identities could be joined. That capture
predates the final field-name/control-field cleanup and is correlation
evidence, not a capture of the current payload schema.

Not run for this update: the full TAEF/API/interaction suites, a fresh
ETW capture of the final `ElementId` schema, or a new local Release
build. No claim is made that every listed event was exercised.

## Screenshots (if appropriate)

<!-- If you are making visual changes, include before/after screenshots.
-->

Not applicable; this PR changes diagnostic instrumentation, not UI
appearance.
2026-10-25 23:01:11 +05:30
Saharsh JaiswalandCopilot 1f66475147 TableView TiP: Copilot review fixes (fault attribution, contained faults)
- PrepareCellForEdit tags only the calls that run a CellEditingTemplate's
  content (the focus calls and the UpdateLayout that realizes it), and
  BeginEdit reads the tag, so TableView's own failure in the hook fails the
  test. IsAppEditor is removed.
- Each shaping verb takes its own contained-fault tally on every exit, and a
  verb a delegate starts inside another hands the outer tally back.
- A custom-comparer sort reports its contained comparer faults from the
  adapter it ranked with, however the sort ends.
- An unload while the first-row layout callback is still armed closes
  Initialize as unloaded_before_render.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 53d996ee-1cb6-468a-bfc9-e11af03b1f80
2026-10-25 11:23:06 +05:30
Morten NielsenandMike Crider f980ab26e3 Improve diagnostics for invalid ItemsSource values (#12335)
## Improves error reporting in #11248


## PR Type

- [ ] Bugfix
- [ ] Feature
- [ ] Code style update (formatting, renaming)
- [ ] Refactoring (no functional changes, no API changes)
- [ ] Build related changes
- [ ] Documentation content changes
- [x] Other (please describe): **Improved error messaging**

## Description

Replace the bare `E_INVALIDARG` in `ItemsControl::OnItemsSourceChanged`
with a descriptive, parameterized error identifying the property and
required collection interfaces.

### Current Behavior
When an ItemsSource value cannot be converted to a supported collection
interface, ItemsControl returns a bare E_INVALIDARG. This can surface as
“Value does not fall within the expected range,” without identifying the
property or explaining its requirements.

This is particularly difficult to diagnose when a .NET Native AOT
application lacks the generated collection interop support described in
#11248.

### New Behavior
Originate a descriptive error after all existing collection-conversion
attempts have failed:

> _The value of 'ItemsControl.ItemsSource' must be null or implement
IBindableIterable or IIterable<IInspectable>._

The message uses a reusable, parameterized error resource. The HRESULT
remains E_INVALIDARG, and collection conversion—including the CLR
tracker-wrapper fallback—remains unchanged.

The diagnostic describes the actual interface requirement without
assuming that every failure is caused by Native AOT configuration. This
change improves error reporting; it does not generate missing interop
support.

## Customer Impact

Developers receive an actionable diagnostic identifying the failing
property and required interfaces. Valid ItemsSource assignments and
end-user UI behavior are unchanged.

## Regression Potential

<!-- Could this change cause regressions? What areas might be affected?
-->

- [x] Low risk — isolated change, limited scope
- [ ] Medium risk — touches shared components or public APIs
- [ ] High risk — architectural or breaking API change

## How Has This Been Tested?

<!-- Describe how you validated your changes. -->

- [x] I have performed a self-review of my own code
- [x] I have added tests to cover my changes
- [ ] Existing tests pass locally

Added regression coverage across ItemsControl, ComboBox, and ListView
for:
- Invalid sources: exception type, E_INVALIDARG, and the explanatory
message.
- Valid sources: empty collections, collection updates, and clearing
ItemsSource with null.

Validation commands and results:

- `.\init.ps1 amd64chk` — passed.
- `.\initrun.ps1 msb /q
"dxaml\xcp\dxaml\dllsrv\winrt\native\Microsoft.ui.xaml.vcxproj"` —
passed with zero warnings and errors.
- `.\initrun.ps1 msb /q
"dxaml\test\native\external\controls\Microsoft.UI.Xaml.Tests.External.Controls.vcxproj"
/p:BuildProjectReferences=false` — passed with zero warnings and errors.

Runtime test results are pending; no passing runtime-test result is
claimed.
## Screenshots (if appropriate)

Not applicable; no visual changes.

---------

Co-authored-by: Mike Crider <45052236+codendone@users.noreply.github.com>
2026-10-23 14:55:03 -07:00
Mike Crider ebf444c106 Convert even more tests from UAP hosting mode to WPF hosting. (#12229)
Reduce the number of tests running in HostingMode UAP from 275 to 129.

## Fixes

This change is progress on #11907.

## PR Type

- [x] Other (please describe):
    * Switch more tests to run in the supported islands mode.

## Description

This change focuses on converting as many tests as possible which failed
mostly or entirely due to just needing updated visual masters for WPF
mode.

Additional details:
- Updates test setup, sizing, input handling, cleanup, and visual
masters to account for XAML Islands hosting differences and improve
reliability.
- Several tests were changed for more deterministic teardown to prevent
retained objects, final-release queue failures, and state leaking
between tests.
- The converted managed tests weren't actually running in UAP mode,
since the test infra doesn't support that. Updated test masters for
these tests tend to have many updated lines due to the masters being
very stale.

## How Has This Been Tested?

- [x] I have performed a self-review of my own code
- [x] Existing tests pass locally
2026-10-23 10:54:00 -07:00
neerajmsgithub 0df0a8869e Fix WebView2 callback ownership during dispatcher shutdown (#12361)
## Issue
Destructor of WebView2 is not getting called in WinUI3

## Fixes
Internal Issue: https://task.ms/60990130

## PR Type

<!-- Check the type of change. Limit each PR to one type when possible.
-->

- [x] Bugfix
- [ ] Feature
- [ ] Code style update (formatting, renaming)
- [ ] Refactoring (no functional changes, no API changes)
- [ ] Build related changes
- [ ] Documentation content changes
- [ ] Other (please describe):

## Description
Few operations like Visibility update (UpdateCoreWebViewVisibility) and
text scale update  captured a strong WebView2 reference in a delayed
action retained by a thread-pool timer. If that timer outlived UI
dispatcher shutdown, releasing the capture could trigger the control’s
final release on a worker thread. The framework then attempted to
enqueue native deletion onto the stopped dispatcher; the rejected
enqueue left the native control undestroyed.

<!-- Could this change cause regressions? What areas might be affected?
-->

- [x] Low risk — isolated change, limited scope
- [ ] Medium risk — touches shared components or public APIs
- [ ] High risk — architectural or breaking API change

## How Has This Been Tested?
Two Windows App SDK self-contained deployments used the same C++ sample
executable and identical runtime payloads except for the baseline/fixed
controls DLL. Native debugging held the actual visibility-timer
callbacks until the UI loop returned, deterministically exercising the
shutdown race without changing product code.


- [x] I have performed a self-review of my own code
- [ ] I have added tests to cover my changes
- [ ] Existing tests pass locally

## Screenshots (if appropriate)

<!-- If you are making visual changes, include before/after screenshots.
-->
2026-10-23 16:44:52 +05:30
Abhijeet JhaandCopilot c8872f79fd ResourceResolver::GetParentForResourceLookup: include ordinary flyouts
Remove the template-only gate while preserving mentor lookup and cycle detection. Use the existing app test root for cyclic-owner coverage and add ordinary-flyout resource and cycle regressions with event-based close synchronization.

Local validation: 190 AppPopup assertions and 14 targeted TAEF tests pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-10-23 15:37:53 +05:30
Saharsh JaiswalandCopilot 42b575bc75 Merge main into user/sahjaiswal/tableview-tip-followup
Brings in #12307 (TableView: templated column headers, UIA resize, sort
fixes, recycle perf, theming) and 11 other commits from main.

Conflicts, resolved by keeping both sides:
- TableView_Editing.cpp (BeginEdit): the TiP try/catch now wraps #12307's
  unwind-on-throw guard and ResetPendingBeginEdit.
- TableView_Sort.cpp: the typed Sorted rethrow and failure capture keep
  #12307's explicitClear, keptSourceSort and reconcile changes, and the
  comparer tally reset follows its early return for a source another
  table owns.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 53d996ee-1cb6-468a-bfc9-e11af03b1f80
2026-10-23 15:03:50 +05:30
Hitesh KumarandCopilot d5132fd2e4 TableView: templated column headers, UIA resize, sort fixes, recycle perf, theming (#12307)
## Fixes

| Internal issue | Type | Change |
|---|---|---|
| https://task.ms/64475625 | Bug | Column headers are a templated,
restylable `TableViewColumnHeader` with visual states |
| https://task.ms/64475623 | Bug | Header typography comes from the
header Style, not C++ local values |
| https://task.ms/64143451 | Bug | Header column separators are always
drawn (no new property); hide them by overriding
`TabularSurfaceHeaderSeparatorBrush` |
| https://task.ms/63996584 | Task | Column headers expose the UIA
Transform pattern so UIA clients can resize columns |
| https://task.ms/64475611 | Bug | Outer border uses new
`TabularSurfaceOuterBorderBrush` (`CardStrokeColorDefault`); grid-line
values were in #12349 |
| https://task.ms/64475629 | Bug | Default group header uses theme
tokens (SemiBold key style, 8px spacing); the item count inherits the
header `Foreground` |
| https://task.ms/64652961 | Task | Row recycling no longer regenerates
cells or refreshes row chrome twice (scroll performance) |
| https://task.ms/63790855 | Task | Sort: `CanSort` is enforced and
`SortByColumn(column, None)` always clears; a sort through a source
another table owns returns false; no spurious `Sorted`; an app-owned
sort survives a `CanSort`/`CanUserSortColumns` opt-out |
| https://task.ms/63787021 | Task | Cell automation-peer constructor
validates its arguments; `BeginEdit` rolls back when it throws |

Not changed: https://task.ms/64512732 (by design: Auto columns follow
content width), https://task.ms/64475627 (design decision: keep chevron
sort glyphs), https://task.ms/64513223 (investigation only; fix
deferred).

## PR Type

- [x] Bugfix
- [x] Feature
- [ ] Code style update (formatting, renaming)
- [ ] Refactoring (no functional changes, no API changes)
- [ ] Build related changes
- [x] Documentation content changes
- [ ] Other (please describe):

## Description

Follow-up to #12349 (merged) and #12285.

Column headers move from code-built Grids to a new templated
`TableViewColumnHeader`, restylable through
`TableView.ColumnHeaderStyle` or `TableViewColumn.HeaderStyle`. Header
peers gain the UIA Transform pattern for column resize. Sort behavior is
tightened around `CanSort`, opt-outs and shared `TableViewSource`
ownership. Row recycling reuses cells. Outer border, header lines and
the default group header follow Fluent tokens.

Review-driven fixes included here:
- The header Style's `TargetType` `TypeName` is kept alive while it is
compared; a Style with only `BasedOn` typed is applied, and its setters
are read before applying it seals the Style. Incompatible, untyped or
cyclic `BasedOn` Styles are ignored with a debug diagnostic.
- A header disabled by its Style reports `IsEnabled=false` and is not
invokable through UIA.
- UIA `Transform.Resize` converts physical pixels through the table's
full visual scale (not only `RasterizationScale`), and a width change
below the drag jitter deadband is written once, exactly.
- Disabling a header in its High Contrast hover/pressed state keeps the
disabled foreground (state order fixed); the disabled sort glyph follows
the text brush across theme changes.
- A `CanSort` opt-out made inside `BeginningEdit` is replayed after the
edit it let open closes, and rebuilds headers even when a `Sorted`
handler throws.
- Header rebuilds caused by `Content`/`Header` or `Columns` changes keep
focus in the header band, respect an app's own focus move, and release
`UIElement` headers back to the app.
- A disabled group header does not dim its item count twice. The count
opacity follows `ContentTemplate` changes while the header is disabled.

<details><summary>Product changes by file</summary>

| File | +/- | What changed | Items |
|---|---|---|---|
| `TableView/TableView.cpp` (+ .h) | +684 / −382 | `RebuildHeaders`
creates `TableViewColumnHeader` controls; applies
`ColumnHeaderStyle`/`HeaderStyle` with TargetType/BasedOn checks;
density MinHeight/Padding only when the Style doesn't set
them<br>`ReleaseHeaderCells` and header-focus handling for
removed/replaced columns, re-entrant rebuilds and app focus
moves<br>Header bottom rule thickness set on `PART_HeaderRow`; header
lines no longer follow `GridLinesVisibility`<br>Row prepare/clear
refresh chrome once; `TryResizeColumnFromAutomation` writes small widths
exactly | 64475625, 64475623, 64143451, 64652961, 63996584, 63790855 |
| `TableView/TableViewColumnHeader.cpp` (+ .h; replaces
`TableViewHeaderCell.h`) | +435 / −210 | New sealed templated
`ContentControl` with read-only `Column`<br>Resolves
`PART_ContentPresenter`, `PART_GridLine`, `PART_SortIndicatorHost`,
`PART_ResizeGripperHost`; hosts the sort glyph and gripper<br>Drives
`CommonStates`/`HighContrastStates`/`SortStates`; disabled sort glyph
bound to the text brush | 64475625, 64475623 |
| `TableView/TableViewRow.cpp` (+ .h) | +191 / −35 | Recycled rows keep
their cells unless cell automation peers exist; chrome refreshed once;
tooltips re-applied on recycle<br>`BeginCellEdit` restores display
element, edit state and focus on throw | 64652961, 63787021 |
| `TableView/TableView.xaml` | +128 / −18 | Default
`TableViewColumnHeader` Style/template: typography setters, visual
states, parts<br>Outer border uses `TabularSurfaceOuterBorderBrush`;
header lines use `TabularSurfaceHeaderSeparatorBrush`<br>Group header:
`TableViewGroupExpanderSpacing` (8), padding 8,8,12,8, key/count text
styles, count inherits `Foreground` | 64475625, 64475623, 64475611,
64475629 |
| `TableView/TableViewColumnHeaderAutomationPeer.cpp` (+ .h) | +127 / −9
| `ITransformProvider`: `Resize` converts physical px through the visual
scale; `CanResize` tracks gripper availability (pinned →
false)<br>`IsEnabled` follows the header; name read from the content
presenter | 63996584, 64475625 |
| `TableView/TableView_Sort.cpp` | +113 / −39 | `SortByColumn(None)`
bypasses the `CanSort` gate; other sorts refused<br>Sort through a
source owned by another table returns false; implicit clears keep the
app's sort and raise no `Sorted`; app-lit columns left alone on opt-out
| 63790855 |
| `TableView/TableView_Layout.cpp` | +74 / −14 | Realized-row walk only
when a visible Auto column exists<br>Transform `CanResize` changes
raised for existing header peers | 64652961, 63996584 |
| `TableView/TableView_Editing.cpp` | +63 / −15 | `BeginEdit` unwinds on
throw; `CanSort` opt-out during `BeginningEdit` queued until the edit
closes | 63787021, 63790855 |
| `TableView/TableViewCellAutomationPeer.cpp` (+ .h, `TableViewCell.h`)
| +48 / −0 | Public constructor throws `E_INVALIDARG` for null args,
negative/out-of-range index or a foreign column; internal path uses
`TrustedOwnerTag` | 63787021 |
| `TableView/TableViewGroupHeader.cpp` (+ .h) | +39 / −0 | Default
count's opacity is not applied twice when disabled | 64475629 |
| `TableView/TableView.idl` | +31 / −13 | `TableViewColumnHeader`,
`TableView.ColumnHeaderStyle`,
`TableViewColumn.HeaderStyle`<br>`CanSort`/`SortByColumn`/`ToggleSortDirection`/`GridLinesVisibility`
docs; cell-peer `E_INVALIDARG`; group-header parts | 64475625, 63790855,
64143451, 63787021 |
| `TableView/TableView_Columns.cpp` | +19 / −0 | Releases removed
columns' header cells; old `UIElement` `Header` returned to the app on
change | 64475625 |
| `TableView/TableViewColumn.cpp` | +7 / −0 | `HeaderStyle` change
queues a header rebuild | 64475625 |
| `TableView/TableViewSource.h` | +6 / −0 | `IsOwnedByOther` helper for
sort sync | 63790855 |
| `CommonStyles/TabularSurfaces_themeresources.xaml` | +5 / −2 | New
`TabularSurfaceOuterBorderBrush` (Dark/Light/HC); group count opacity
documented as secondary-over-primary text (0.77 Dark) | 64475611,
64475629 |
| `TableView/TableView.vcxitems` | +2 / −1 | Swap
`TableViewHeaderCell.h` for `TableViewColumnHeader.*` | 64475625 |
| Generated / metadata (`Generated/TableView.properties.*`,
`Generated/TableViewColumn.properties.*`,
`dll-tabular/XamlMetadataProviderGenerated.h`) | +123 / −0 | Codegen for
the new properties and type | 64475625 |

**Total: 17 rows, 29 product files, +2117 / −738.** Also: 19 test files
(+3718 / −32), 3 docs (+161 / −35), 6 sample files (+2 / −9).

</details>

### New preview API (needs API review)

- **`TableViewColumnHeader`**: sealed, templated `ContentControl`,
created only by `TableView`.
  - Read-only `Column` property.
- Template parts (optional): `PART_ContentPresenter`, `PART_GridLine`,
`PART_SortIndicatorHost`, `PART_ResizeGripperHost`.
- Visual state groups: `CommonStates`, `HighContrastStates`,
`SortStates`.
- **`TableView.ColumnHeaderStyle`**: Style applied to every column
header.
- **`TableViewColumn.HeaderStyle`**: per-column Style; wins over
`TableView.ColumnHeaderStyle`.

There is no `HeaderGridLinesVisibility` property. `GridLinesVisibility`
affects body lines only; header lines are always drawn. To hide them,
override `TabularSurfaceHeaderSeparatorBrush` with `Transparent`.

### Current Behavior
- Headers are built in C++ with no template, no visual states and forced
local typography, so apps can't restyle them. Header separators don't
show.
- Header peers report `HeaderItem` without Transform, so UIA clients
can't resize columns.
- `SortByColumn` ignores `CanSort`; `CanSort=false` on a sorted column
leaves the sort in place; sorting through a source another table owns
reports success; some implicit clears raise `Sorted(None)` while the
app's sort remains.
- The cell peer constructor accepts invalid arguments; a throw in
`BeginEdit` leaves edit state half-open.
- Recycling a row rebuilt every cell, refreshed chrome up to twice and
invalidated the table's measure.
- The outer border has no dedicated brush; the default group header uses
raw weights and off-grid spacing.

### New Behavior
- Headers use the templated `TableViewColumnHeader` (see API above);
typography, padding and brushes come from Style setters.
- Header peers implement `ITransformProvider` through the existing
resize path (Min/Max clamping, scale conversion; pinned columns report
`CanResize=false`).
- `CanSort=false` blocks header clicks, `SortByColumn` (except `None`)
and `ToggleSortDirection`, and clears the column's own active sort;
sorts through a source owned by another table return false; `Sorted` is
raised only when the table's sort state changes.
- Cell peer constructor throws `E_INVALIDARG` on bad input; `BeginEdit`
rolls back on failure.
- Recycled rows reuse their cells unless cell automation peers exist;
chrome refreshes once.

> **Visible changes**
> - Outer border uses `CardStrokeColorDefault`.
> - Header lines are always shown, even when `GridLinesVisibility` is
`None` or `Horizontal`.
> - Group header restyled: 8px spacing; the count follows the header
`Foreground`.
> - Disabled header text and sort glyph dim.
> - TableView samples no longer opt out of High Contrast backplates
app-wide.

## Customer Impact

Restylable column headers, visible header separators, Fluent-aligned
outer border and group headers, UIA column resize for assistive
technology, smoother scrolling and predictable sort events.

## Regression Potential

- [ ] Low risk — isolated change, limited scope
- [x] Medium risk — touches shared components or public APIs
- [ ] High risk — architectural or breaking API change

Header construction (focus restore, frozen columns, UIA peer, tooltips,
resize, sort glyph) moved to a templated control. Sort event semantics
are tighter: `CanSort` is enforced on programmatic sorts and fewer
`Sorted` events fire. Outer border color and always-on header lines
change visibly. Covered by new and existing tests.

## How Has This Been Tested?

- [x] I have performed a self-review of my own code
- [x] I have added tests to cover my changes
- [x] Existing tests pass locally

Full TableView API and interaction suites on test VMs: 877/882 pass at
224d10d5c; 3 Localization tests are [Ignore] and 2 intermittent failures
passed 3/3 on rerun. Product, test apps and TableView sample apps build
(x64 chk).

Also covered:
`VerifyDisabledGroupHeaderCountFollowsContentTemplateChanges`.

Key new tests:
- `VerifyColumnHeaderTemplateParts`, `VerifyColumnHeaderSortStates`,
`VerifyColumnHeaderTypographyHasNoLocalValues`
- `VerifyColumnHeaderStyleApplies`,
`VerifyBasedOnOnlyColumnHeaderStyleApplies`,
`VerifyIncompatibleColumnHeaderStyleIsIgnored`
- `VerifyHeaderGridLinesShowWhateverTheBodyGridLines`,
`VerifyTransparentHeaderSeparatorBrushHidesHeaderLines`,
`VerifyGridLineAndOuterBorderBrushesMatchFluentStrokeTokens`
- `VerifyDisablingHighContrastHoveredHeaderKeepsDisabledForeground`,
`VerifyDefaultGroupHeaderCountInheritsForegroundThatFollowsStates`
- `VerifyTransformResizeAccountsForAncestorScale`,
`VerifyTransformResizeSmallWidthChangeWritesOnce`,
`VerifyHeaderDisabledByStyleIsNotEnabledOrInvokable`
- `VerifySortByColumnRespectsCanSort`,
`VerifyImplicitClearKeepsSourceSort`,
`VerifyUngatingKeepsAppLitColumnWithoutEvents`,
`VerifySortOptOutDuringBeginningEditKeepsTheEditOpen`
- `VerifyRecycledRowWithoutCellPeersReusesItsCells`,
`VerifyHeaderFocusStaysInHeaderBandWhenColumnsReplaced`,
`VerifyBeginEditThatThrowsRollsBackAndAllowsALaterEdit`,
`VerifyCellPeerConstructorValidatesArguments`

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 94961bb8-d187-483c-bece-19e203752c67
2026-10-23 14:10:17 +05:30
SatwikKrSharma 42d204698a Add code-coverage-calculation skill: component code coverage from a local VM test run (#12254)
## Fixes

No linked issue. This adds agent tooling only and doesn't change product
code or test code.

## PR Type

- [ ] Bugfix
- [x] Feature
- [ ] Code style update (formatting, renaming)
- [ ] Refactoring (no functional changes, no API changes)
- [ ] Build related changes
- [ ] Documentation content changes
- [x] Other (please describe): new experimental agent skill under
`.github/skills`

## Description

Adds the experimental `code-coverage-calculation` skill to
`.github/skills/`, where Copilot CLI and agency discover skills
automatically (the same place as `build` and `test-on-vm`). It measures
code coverage of one WinUI control or component using only that
component's tests, run on a local Hyper-V VM against the local build.
The report numbers match the ADO Code Coverage tab.

### Current Behavior
Getting coverage for a single control needs a coverage pipeline run with
all tests, or manual instrumentation and collector setup. Agents can't
do it from a prompt.

### New Behavior
In this repo, the prompt `calculate coverage of control <name>` makes
the agent:
1. **Check prerequisites:** a local build, VS Enterprise code coverage,
`dotnet-coverage`, and Hyper-V rights.
2. **Gate on VM details (strict):** before every run, the agent asks the
user to confirm a cached VM and username or enter new details. It never
picks one silently. The password is typed in a separate window, never in
chat, and stored in the same encrypted cache `tools\run-tests-on-vm.ps1`
uses. The shared `tools\Set-VmCredential.ps1` then checks the logon and
that the user has an active desktop session, and only then replaces the
cached credential.
3. **Find the component and its tests:**
- `controls\dev\<Control>` (MUXC): it finds the folder by name or by its
`.idl` class, the `APITests` and `InteractionTests` classes, the test
filter(s), and the source-path regex.
- Not under `controls\dev`: it investigates `dxaml` (MUX) sources and
tests and **needs the user's approval** before running.
   - Found in neither place: it asks the user.
4. **Run:** it relinks MUXC with `/DEBUGTYPE:CV,FIXUP` outside
`BuildOutput`, instruments it (cached), runs the collector and tests on
the VM, then always restores the payload and the VM copies with hash
checks.
5. **Report:** per-file and per-function coverage, deduplicated by
(file, line) to match ADO, plus an HTML tree, written under
`BuildOutput\Coverage\<flavor>\<Component>` by default (git-ignored).

The skill is self-contained in this repo: everything it needs is in
`.github/skills/code-coverage-calculation/` plus the shared
`tools\Set-VmCredential.ps1`, and it doesn't refer to other repos, PRs,
builds or skills. Supported modules: `Microsoft.UI.Xaml.Controls.dll`,
`Microsoft.UI.Xaml.Controls.Tabular.dll` (TableView and the tabular
helpers) and `Microsoft.ui.xaml.dll`. Before every run the agent tells
the user what it changes on the VM, including the coverage pipe it opens
to all local users. `-TestFilter` accepts several filters, each run with
its own collector and merged in the report.

## Customer Impact

None for end users. This is developer and agent tooling only.

## Regression Potential

- [x] Low risk — isolated change, limited scope

The PR only adds new files under
`.github/skills/code-coverage-calculation/` and
`tools\Set-VmCredential.ps1`. During a run the skill changes only the
generated `TestPayload\<flavor>` folder and the VM's deployed payload,
and restores both with hash checks. The restore state is written before
anything is overwritten, so an interrupted run is restored at the start
of the next one, and a failed restore fails the command.

## How Has This Been Tested?

- End-to-end run on TitleBar before this PR (`*.TitleBarTests.*`, 24/24
passed, TitleBar sources at 81 % line coverage); payload, VM and
`BuildOutput` were checked back at their original hashes afterwards.
- All scripts parse without errors. Review fixes only changed failure
and cleanup paths: Step 1 and all `lib` scripts are code-identical to
the version used in that run (comments only).
- Step 5 old vs new on a real 88 MB `.coverage` file: identical
per-file, per-module and per-function CSVs and summary. Path keys now
also join for checkouts under folders like `C:\src`, and the function
list now covers components whose sources sit in subfolders
(PullToRefresh: 0 to 120 functions).
- Failure paths tested with mocked VM calls and a fake coverage tool. A
Step 3 failure keeps its error, downloads the collector log and closes
the session. A Step 4 VM mismatch fails and keeps the state. Step 2
restores a rebuilt payload to the new build, not the old one, and
re-instruments after a tool version change. The orchestrator stops the
transcript when Step 3 fails.
- The orchestrator was tested with stubbed steps: one filter gives the
same call sequence and run label as before, and two filters run Step 3
twice and pass both `.coverage` files to Step 5.
- `Set-VmCredential.ps1` rejects `VM\user` names and unknown VMs.
Against a real VM with a cached credential, it confirmed the logon and
an active console session, without prompting and without changing the
cache.
- A full coverage run has not been repeated from the repo copy.

- End-to-end run of the skill from this branch on TitleBar
(`*.TitleBarTests.*`, fresh `amd64chk` build of this branch, Hyper-V
VM): 32/32 tests passed, TitleBar 835/954 lines (87.53 %),
`TitleBar.cpp` 99.03 %. Payload and VM were restored to the original
DLLs afterwards. That run found the stale incremental-deploy bug fixed
in the last commit: reruns tested the original DLL or deployed the
instrumented DLL without `static_covrun64.dll`. The fix removes exactly
those 16 manifest entries. Rejecting a stale build was tested against an
older build (TitleBar: 0 matches, stops before instrumenting;
TeachingTip: 84 matches, runs).
- Second review round (`c0ef2a400`), checked with stub and mock tests
before and after the change:
- Step 2 fails on the 3rd of 4 copies: before the change, 2 copies
stayed instrumented with no state file; now Step 4 restores all 4.
- A failed `-RefreshPayload` or incomplete payload now stops the run; a
`te.exe` error is reported as a listing failure, not as 0 matches; IXMP
appx tests are now accepted by the check.
- A restore failure now fails the command after the report is written;
when Step 3 also failed, Step 3's error is still the one reported. A
leftover state file is restored before the next run.
- A baseline taken from `D:\src\baseline-repo` matched 0 of 15 TitleBar
files before the change and 15 of 15 after; an unrelated baseline now
shows a warning. Results without a baseline are unchanged on real
TitleBar coverage.
- `tools\Set-VmCredential.ps1` keeps the old cache when the desktop
isn't active.
- End-to-end VM run of the Tabular module from this branch: `-Module
Microsoft.UI.Xaml.Controls.Tabular.dll -TestFilter
'*.TableViewSortingTests.*'`, 35/35 passed in 3 min 41 s, TableView
3557/11779 lines (30.2 %) from that one test class. Payload and VM were
restored afterwards, and the output stays git-ignored.
- [x] I have performed a self-review of my own code
- [ ] I have added tests to cover my changes
- [ ] Existing tests pass locally
2026-10-23 14:05:24 +05:30
ayushjai19 1c9adcadd9 NavigationView: respect IsPaneOpen=false set before PaneDisplayMode=Left on launch (#7609) (#12325)
## Fixes

Fixes #7609

## PR Type

- [x] Bugfix

## Description

Setting `IsPaneOpen="False"` **before** `PaneDisplayMode="Left"` (XAML
attribute order, or code before the control is loaded) launched the
NavigationView with the pane open and `IsPaneOpen == true`. The reverse
order worked, so the result depended on property order.

Root cause: the `PaneDisplayMode` branch of
`NavigationView::OnPropertyChanged` unconditionally reset
`m_wasForceClosed`. Before the template is applied, that flag can only
be `true` because the app explicitly set `IsPaneOpen=false` (the
pre-template path added in #3197 for #2391). Clearing it made the first
`UpdateAdaptiveLayout` (Expanded) call `OpenPane()`.

Fix: only reset `m_wasForceClosed` on a `PaneDisplayMode` change once
the template has been applied at least once. A new never-reset
`m_templateAppliedOnce` is used rather than `m_appliedTemplate`, because
`m_appliedTemplate` is also false while a template is re-applied, and an
app's custom `GoToStateCore` can run in that window. That keeps
re-templating identical to main.

### Current Behavior
`<NavigationView IsPaneOpen="False" PaneDisplayMode="Left"/>` launches
with the pane open and `IsPaneOpen` becomes `true`.

### New Behavior
The pane launches closed, the same as `PaneDisplayMode="Left"
IsPaneOpen="False"` already did (matching the launch table in #3197).
Runtime `PaneDisplayMode` switches on a loaded control are unchanged:
for example, LeftMinimal -> Left still opens the pane, as designed
(#1702/#1787).

## Customer Impact

Apps that declare a collapsed Left pane in XAML get the state they asked
for without an `OnLoaded` workaround.

## Regression Potential

- [x] Low risk: isolated change, limited scope

The change only takes effect for a `PaneDisplayMode` change that happens
before the first `OnApplyTemplate` while the app has already set
`IsPaneOpen=false`. Post-template behavior is unchanged. This doesn't
conflict with #12315, which touches
`UpdateAdaptiveLayout`/`UpdateIsClosedCompact`.

## How Has This Been Tested?

- [x] I have performed a self-review of my own code
- [x] I have added tests to cover my changes
- [x] Existing tests pass (no failures beyond the known failures on
`origin/main` 866ba81a1)

New API test
`NavigationViewTests.VerifyIsPaneOpenFalseRespectedWhenSetBeforePaneDisplayModeLeft`.
It covers the code order, the reporter's exact XAML via
`XamlReader.Load`, IsPaneOpen=false -> LeftCompact -> Left, and a
control case where an unset IsPaneOpen still opens. It also has
trigger-audit cases (commit `a20ec32bb`): a pre-load `IsPaneOpen=true`
override, an Auto launch after a pre-template mode change, a runtime
LeftMinimal -> Left after a closed launch (the by-design open), and a
runtime LeftCompact -> Left after a closed launch (commit `ca15dfbdf`).
That last case is the one that detects a lost post-template flag reset.

Results on the shared test VM (full builds only):
- **GREEN** on fix commit `16a576bcc`: the new test **passed**
(`Total=1, Passed=1`).
- `*ApiTests.NavigationViewTests*`: 36 passed / 5 failed / 1 skipped.
All 5 failures (`VerifyVisualTree_OptimizedStyles`,
`VerifyVisualTree_OldStyles`,
`VerifyPaneDisplayModeAndDisplayModeMapping`,
`VerifyHeaderContentMarginOnTopNav`,
`VerifyHeaderContentMarginOnMinimalNav`) also fail on `origin/main`
(shared baseline). The related launch and runtime tests
`VerifyPaneDisplayModeAndIsPaneOpenInterplayOnNavViewLaunch` and
`VerifyPaneDisplayModeChangingPaneAccordingly` passed.
- `*NavigationViewTests.PaneBehaviorTests*`: 33/34 passed, including
`ForceIsPaneOpenToFalseOnLeftNavTest`, `PaneOpenForceCloseTest` and
`PaneDisplayModeLeftLeftCompactLeftMinimalTest`. The single failure,
`VerifyPaneLayoutSwappingCollections`, was an `ArgumentNullException` in
the UIA `ElementCache` during test setup, before any test logic ran.
That's an infra flake: it **passed** on rerun.
- RED: the original test-only run (`36c34192d`) failed as expected (3
closed-pane cases `AreEqual(False, True)`), but it used a gate build
mode that was later found to deploy a stale product DLL. A clean
full-build RED rerun on `36c34192d` confirmed the result: **Failed** on
cases 1–3 (`AreEqual(False, True)` for NavView and SplitView, `Total=1,
Failed=1, Blocked=0`).
- Trigger-audit cases on final head `a20ec32bb` (full build): the new
test with all 7 cases **passed**, along with
`VerifyPaneDisplayModeChangingPaneAccordingly` and
`VerifyPaneDisplayModeAndIsPaneOpenInterplayOnNavViewLaunch`.
- Round 2 (`ca15dfbdf`, full build): the new test with all 8 cases
**passed**, along with `VerifyPaneDisplayModeChangingPaneAccordingly`. A
scratch commit (not pushed) that deletes the post-template
`m_wasForceClosed` reset makes the LeftCompact -> Left case **fail**
(`IsTrue - NavigationView.IsPaneOpen` / `RootSplitView.IsPaneOpen after
runtime LeftCompact -> Left`), so the test guards both halves of the
guard.
- Round 3 (`b13c210ed`, re-templating review): the guard now uses
`m_templateAppliedOnce`. On the identical product code (full build), the
new test (all 8 cases), `VerifyPaneDisplayModeChangingPaneAccordingly`
and `VerifyPaneDisplayModeAndIsPaneOpenInterplayOnNavViewLaunch`
**passed**. A dedicated re-template test couldn't be added:
re-templating a NavigationView at runtime (`Template = null` and back,
or a new ControlTemplate) hits a framework assert (0xC0000420 in
Microsoft.UI.Xaml.dll) in the chk test build, even with no
PaneDisplayMode change. That path is covered by code inspection: the new
flag differs from main only before the first `OnApplyTemplate`.
2026-10-23 11:21:46 +05:30
Saharsh JaiswalandCopilot 927f474d48 TableView TiP: blame by exception type and count contained app faults
Review round 3. Attribution matched the last app HRESULT against a
control-wide counter, so a nested callback could overwrite it and an
unrelated exception with the same HRESULT could match. App code's
exceptions are now tagged where TableView calls it (CallerError, and
CallerOutOfMemory for an allocation failure, which stays a std::bad_alloc),
and the catch that decides an outcome reads the type. SelectionModel calls
TableView back across the ABI, which drops the C++ type, so the call into
it tags the exception again by its error object.

Column code is TableView's unless app code ran it: the editing hooks are
internal, so only a CellEditingTemplate's content (while the editor is
prepared) is the app's there, and only an app-derived column class owns its
display factory and sort member path. Expansion is always tracked and its
catch reads the tag; only a request that changes one group or node runs a
test.

A filter over a large source no longer drops into the small bucket: the
large flag counts the source before the filter, and the metrics and
TableView_Instance carry both counts. Initialize closes as
unloaded_before_render when the table is unloaded with rows and a body
viewport before any row was laid out. An app filter predicate, sort or group
key selector or custom comparer that throws is still contained, and now
writes one recoverable TableView_Error per operation with FaultCount.

Internal pipeline builds fail when Tabular falls back to the TiP stub. All
versions start at 1, since none has shipped.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 53d996ee-1cb6-468a-bfc9-e11af03b1f80
2026-10-23 02:13:31 +05:30
Saharsh JaiswalandCopilot a7483e3aed Merge main into user/sahjaiswal/tableview-tip-followup
Brings in #12349 (TableView low-risk fixes) and 35 other commits from main.
No conflicts.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 53d996ee-1cb6-468a-bfc9-e11af03b1f80
2026-10-22 23:22:20 +05:30
Sergio PedriandCopilot App 51dbbd540b Synchronize staggered entrance transition visibility (#12196)
## Fixes

<!-- Link either the public GitHub issue or the internal issue this PR
addresses. Remove the unused line. -->
<!-- PRs without a linked issue may be closed unless they are minor
documentation/typo fixes. -->

Fixes
[#8879](https://github.com/microsoft/microsoft-ui-xaml/issues/8879)

## PR Type

<!-- Check the type of change. Limit each PR to one type when possible.
-->

- [x] Bugfix
- [ ] Feature
- [ ] Code style update (formatting, renaming)
- [ ] Refactoring (no functional changes, no API changes)
- [ ] Build related changes
- [ ] Documentation content changes
- [ ] Other (please describe):

## Description

<!-- Describe your changes in detail. -->

### Current Behavior
<!-- How does this work today? -->

For staggered load transitions, `CTransition::SetupTransition` initially
hides the layout transition element and injects a discrete, time-zero
opacity keyframe to reveal it after the stagger delay. This animation
has zero natural duration, which prevents its conversion to a compositor
animation. The reveal therefore depends on a UI-thread tick, while the
entrance fade and translation run independently on the compositor.

These timelines can diverge: content can become visible partway through
its motion, or be revealed before the compositor motion is attached.
This is a candidate explanation for the intermittent entrance artifacts
reported in #8879, not yet proof that it accounts for every stutter in
the issue.

### New Behavior
<!-- How will it work after this PR? -->

Expand dynamic storyboard children before resolving duration and give
the injected reveal the transition storyboard's natural duration. This
allows the reveal to run on the compositor alongside the motion,
retaining the existing discrete time-zero keyframe and stagger delay
without intentionally changing the overall transition duration.

Add `ValidateStaggeredEntranceVisibilityTiming` to check the reveal's
explicit positive duration, discrete time-zero keyframe, and agreement
with the motion duration, across repeated loads with staggering enabled
and disabled. The test also verifies MockDComp's compositor tree after a
staggered reload, including the three attached local-opacity keyframe
animations and their stagger delays.

Changes are split into the runtime fix (`591dbdae9`) and regression
coverage (`5b30aa458`).

## Customer Impact

<!-- How does this change affect end users? Is it user-facing or infra
changes? -->

User-facing: staggered entrance reveals should remain synchronized with
compositor motion when the UI thread is delayed. No public API changes.

An out-of-tree reproduction restores the issue's Windows App SDK
1.4.230822000 baseline, original row layout, and two-page navigation
flow. A default-off timing experiment deliberately pauses the UI thread
for 250 ms after rendering callbacks and a compositor commit. In
captured runs, the historical runtime abruptly revealed delayed rows
together, while the patched branch continued revealing them
progressively.

The historical and branch apps have different SDK/.NET dependencies, so
this comparison supports the timing mechanism but is not an
otherwise-identical pre/post-patch experiment. Reliable reproduction of
the exact unstressed issue video remains unconfirmed. Very late
compositor attachment is also a remaining limitation.

## Regression Potential

<!-- Could this change cause regressions? What areas might be affected?
-->

- [ ] Low risk — isolated change, limited scope
- [x] Medium risk — touches shared components or public APIs
- [ ] High risk — architectural or breaking API change

The duration change is limited to the injected visibility animation for
delayed load transitions, but dynamic timeline expansion moves earlier
in shared transition setup. Other theme transitions and
staggered/non-staggered loads warrant coverage. Existing keyframes,
delays, and intended completion timing are preserved.

## How Has This Been Tested?

<!-- Describe how you validated your changes. -->

- [x] I have performed a self-review of my own code
- [x] I have added tests to cover my changes
- [x] Existing tests pass locally

Local native tests ran in the WPF host using Debug x64 binaries,
including the test-fixture correction in `cf54f1b7d` and the compositor
coverage in `e5696b8e5`. The fixture retains the Rectangle managed peers
through deferred storyboard creation and checks the captured storyboards
after the synchronous ticks, so verification failures report cleanly
rather than unwinding through the runtime callback. The original frozen
clock, two ticks, and staggering/reload coverage are preserved.

Commands below were run from the assembled `TestPayload\x64chk`
directory in an elevated shell:

**Regression repetition: passed 20/20 runs.** Each run covers two fresh
loads with staggering disabled and two with staggering enabled. This was
rerun successfully with the compositor snapshot check enabled.

```powershell
.\TE.exe Test\Microsoft.UI.Xaml.Tests.External.Foundation.dll /select:"@Name='*ThemeTransitionTests::ValidateStaggeredEntranceVisibilityTiming'" /p:HostingMode=WPF /p:SkipConsoleWindowMinimize /testtimeout:0:02 /unicodeOutput:false /reportLoadingIssue /testmode:loop /looptest:20
```

**Related transition tests: passed 24/24 runs** (eight tests, each
repeated three times), including `ValidateStaggeringWorks`, the new
regression, the ItemsControl timing helper, and the five ItemsControl
storyboard tests. This was also rerun successfully after adding the
compositor coverage.

```powershell
.\TE.exe Test\Microsoft.UI.Xaml.Tests.External.Foundation.dll /select:"@Name='*ThemeTransitionTests::ValidateStagger*' OR @Name='*ThemeTransitionTests::ValidateItemsControl*'" /p:HostingMode=WPF /p:SkipConsoleWindowMinimize /testtimeout:0:02 /unicodeOutput:false /reportLoadingIssue /testmode:loop /looptest:3
```

**Negative controls: failed as expected.** When only the explicit
reveal-duration assignment was temporarily removed, both non-staggered
loads passed and both staggered loads failed at the intended duration
assertion (`TimeSpan` expected, `Automatic` actual), with the test host
remaining alive.

An additional negative control temporarily forced the injected LTE
opacity animations to use UI-thread ticking while preserving their
positive duration and keyframes. All existing duration/keyframe
assertions passed, but the new compositor snapshot check failed: the
three local-opacity compositor animations were absent while the entrance
fade and translation animations remained attached. Both negative
controls used the single-run command below.

```powershell
.\TE.exe Test\Microsoft.UI.Xaml.Tests.External.Foundation.dll /select:"@Name='*ThemeTransitionTests::ValidateStaggeredEntranceVisibilityTiming'" /p:HostingMode=WPF /p:SkipConsoleWindowMinimize /testtimeout:0:02 /unicodeOutput:false /reportLoadingIssue
```

The patched runtime was restored before the successful repetition runs
above. All temporary diagnostics were removed. The full test suite and
other architectures/hosting modes were not run locally.

## Videos


https://github.com/user-attachments/assets/68fffca2-d637-49cb-8d8a-45331d9574b6

---------

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
2026-10-22 09:10:23 -07:00
5e5dc36a16 Publish localization resources to the OSS dependency feed (#12364)
## Fixes

No linked issue.

## PR Type

- [ ] Bugfix
- [ ] Feature
- [ ] Code style update (formatting, renaming)
- [ ] Refactoring (no functional changes, no API changes)
- [x] Build related changes
- [ ] Documentation content changes
- [ ] Other (please describe):

## Description

Make newly generated localization resource packages available to OSS
builds by publishing them to the OSS dependency feed before proposing
localization updates.

### Current Behavior

The localization pipeline does not publish its generated resource
package to the OSS dependency feed. A localization update can therefore
reference a package version that OSS builds cannot restore.

### New Behavior

Publish the same generated package and version to the shine-oss
`WinUI-Dependencies` feed, using the existing cross-organization
authentication pattern. Preserve existing publication behavior and stop
before proposing localization updates if OSS publication fails.

Update the localization documentation to describe dual-feed publishing
and its access requirements.

## Customer Impact

Enables OSS builds to restore newly published localization resources.
This is a build-infrastructure change with no runtime or public API
changes.

## Regression Potential

- [x] Low risk — isolated change, limited scope
- [ ] Medium risk — touches shared components or public APIs
- [ ] High risk — architectural or breaking API change

The publishing identity must have permission to publish to the OSS
dependency feed. Authentication or publication failures will block
localization updates rather than propose an unavailable package version.

## How Has This Been Tested?

- [x] I have performed a self-review of my own code
- [ ] I have added tests to cover my changes
- [ ] Existing tests pass locally

Local YAML and configuration checks confirm that both publication steps
target the same package/version, existing steps remain unchanged, and
OSS publication precedes localization updates.

Live pipeline publication and OSS restore validation are pending.

## Screenshots (if appropriate)

Not applicable; no visual changes.

Co-authored-by: Test User <test@example.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 83aa42a4-855c-4597-bf2e-e6e9239adbc3
2026-10-22 21:08:11 +05:30
ayushjai19 4bcbff6d6b NavigationView: fix pane toggle button clipped on first render (#12321)
## Fixes

Fixes #5854
Fixes #9034


## PR Type

- [x] Bugfix
- [ ] Feature
- [ ] Code style update (formatting, renaming)
- [ ] Refactoring (no functional changes, no API changes)
- [ ] Build related changes
- [ ] Documentation content changes
- [ ] Other (please describe):

## Description

`NavigationView::UpdatePaneToggleSize()` copies
`TemplateSettings.PaneToggleButtonWidth` into `TogglePaneButton.Width`.
On first load it runs from `OnApplyTemplate` (`UpdatePaneDisplayMode` →
`SetDisplayMode`) **before** `OnLoaded` → `UpdatePaneButtonsWidths()`
initializes that template setting, which is still at its default of 0.
As a result the button gets `Width = 0` and falls back to `MinWidth`
(`SmallerPaneToggleButtonWidth` = 40). Its template needs 48px (a 40px
icon column plus a 4px `LayoutRoot` margin on each side), so the hover
background and the hamburger glyph are clipped on the right. The width
is only corrected the next time something calls
`UpdatePaneToggleSize()`, for example when the pane is collapsed.

Fix: `UpdatePaneButtonsWidths()` now calls `UpdatePaneToggleSize()` when
`PaneToggleButtonWidth` actually changes.

Two follow-ups from review:
- **Effective open pane length.** With a `PaneTitle`, the toggle button
is stretched to the effective open pane length. `UpdateOpenPaneLength()`
(called from `SizeChanged` and from `OpenPaneLength` changes) now
re-applies the width when that length changes. Before, a runtime
`OpenPaneLength` change, or a NavigationView narrower than
`OpenPaneLength`, left the button at its old width.
- **Negative width.** In an open overlay pane with the close button
shown, the button width is `OpenPaneLength - 40`, which is negative when
`OpenPaneLength` < 40, and `Width(-x)` throws. `UpdatePaneToggleSize()`
now clamps it to 0.

### Current Behavior
A default `<NavigationView/>` whose pane starts open (`PaneDisplayMode`
left at `Auto`, width ≥ `ExpandedModeThresholdWidth`) renders
`TogglePaneButton` 40px wide (`Width=0`, `MinWidth=40`) instead of 48.
The hover background and the glyph are cut off until the pane is toggled
once. Also, changing `CompactPaneLength` at runtime doesn't resize the
toggle button until the next pane toggle.

### New Behavior
`TogglePaneButton` is `CompactPaneLength` (48) wide from the first
frame, matching what you get after a toggle and the visual-tree masters,
which already expect `Width=48`. Runtime `CompactPaneLength` changes
apply immediately.

## Customer Impact

Visible polish bug in the default NavigationView (hamburger hover state
clipped on launch) in WinUI 2 and WinUI 3, reported since 2021.

## Regression Potential

- [x] Low risk — isolated change, limited scope

Small change in three functions. Each new `UpdatePaneToggleSize()` call
is guarded so it only runs when its input actually changes:
`PaneToggleButtonWidth` (first load, `CompactPaneLength` changes) or the
effective open pane length (`OpenPaneLength` changes, and resizes
narrower than `OpenPaneLength`). Neither runs on every pane open/close.
The clamp only affects values that used to throw.
`UpdatePaneToggleSize()` already exists, is idempotent and null-guarded.
Top mode hides the toggle button. With a `PaneTitle` set, the button
keeps its existing `OpenPaneLength` path.

## How Has This Been Tested?

- [x] I have performed a self-review of my own code
- [x] I have added tests to cover my changes
- [x] Existing tests pass locally (failures match `main`; see below)

New API test
`NavigationViewTests.VerifyPaneToggleButtonWidthOnFirstRender`. It has 6
cases: `PaneDisplayMode` left at its default at 1200/800/500px, plus
explicit `Left`, `LeftCompact` and `LeftMinimal`. Each case checks that
the toggle button's `ActualWidth` equals `CompactPaneLength` on first
render and again after `CompactPaneLength = 60`.
New API tests (`NavigationViewTests`):
- `VerifyPaneToggleButtonWidthOnFirstRender`: 6 cases (`PaneDisplayMode`
left at its default at 1200/800/500px, plus explicit
`Left`/`LeftCompact`/`LeftMinimal`). It checks `ActualWidth ==
CompactPaneLength` on first render and again after `CompactPaneLength =
60`.
- `VerifyPaneToggleButtonWidthFollowsOpenPaneLengthWithPaneTitle`:
`PaneTitle`, `OpenPaneLength` 250 → 280, then the NavigationView
narrowed to 200.
- `VerifyPaneToggleButtonWidthIsNotNegativeWithSmallOpenPaneLength`:
@godlytalias's repro. Open LeftMinimal pane with the close button
visible, `OpenPaneLength = 32`, then `CompactPaneLength` 24 → 28.

All runs were full builds on the test VM:
- **Red: main's product code + the new tests** (scratch commit
61cf071e4): all 3 fail. `AreEqual(48, 40)` (default mode, Expanded,
first render); `AreEqual(60, 52)` ×5 (CompactPaneLength change);
`AreEqual(200, 250)` (narrowed NavigationView); `AreEqual(0, 280)` ×2
(small OpenPaneLength / CompactPaneLength with an open overlay pane).
- **Green: a3114f25f, `*ApiTests.NavigationViewTests*`:** 39/44. All 3
new tests pass. The 5 failures (`VerifyVisualTree_OptimizedStyles`,
`VerifyVisualTree_OldStyles`,
`VerifyPaneDisplayModeAndDisplayModeMapping`,
`VerifyHeaderContentMarginOnTopNav`,
`VerifyHeaderContentMarginOnMinimalNav`) also fail on `main` 866ba81a1.
- **`VerifyOverflowButtonRemainsVisibleAfterSelectingOnlyOverflowItem`**
crashed once (`0xC0000420`) on an earlier run of this PR. Since then it
passed 4/4 on e04412063 and again on a3114f25f, so that crash was a
flake.
- **`*NavigationViewTests.PaneBehaviorTests*` (3e3a52074):** 25/34. All
9 failures also fail on `main`, on the same source lines. Later commits
only add the `OpenPaneLength` refresh and the clamp.
Full analysis: see the investigation doc (root-cause trail, a diagnostic
run that confirmed `Width=0 / ActualWidth=40` on base, and the
regression analysis across all PaneDisplayModes).
## Screenshots (if appropriate)

Before: see the screenshots in #5854 and #9034. The right edge of the
hover background is cut off and the glyph is partly hidden.


<img width="1980" height="690" alt="5854-before-after"
src="https://github.com/user-attachments/assets/27243329-e8a0-40d2-bd8e-7cccc9482ea9"
/>
2026-10-22 15:58:52 +05:30
Abhijeet JhaandCopilot e8d5ddd1e4 ScrollViewer::OnPointerReleasedHandledEventsToo: clear stale press state
Keep handled-release cleanup and press counting inside ScrollViewer. Remove the core per-press event-state changes and preserve the existing normal focus decisions.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-10-22 15:53:10 +05:30
ayushjai19 c0587a63bf NavigationView: don't clip the LeftMinimal header when back and toggle buttons are hidden (#12316)
## Fixes

Fixes #9789


## PR Type

- [x] Bugfix

## Description

In `Minimal` display mode (`PaneDisplayMode="LeftMinimal"`, or `Auto` in
a narrow window), `HeaderContent` uses the theme margin
`NavigationViewMinimalHeaderMargin = -24,44,0,0`. The negative left
value is designed to pull the header back into the button slot that
`ContentLeftPadding` reserves for the pane toggle, back, or close
button: 40px - 24px = a 16px inset.
`UpdateBackAndCloseButtonsVisibility()` sizes `ContentLeftPadding` from
the buttons that are actually visible. When the back button, the close
button, *and* the pane toggle button are all hidden, the padding is 0,
so the header lands at x = -24 and gets clipped.

### Current Behavior
With `PaneDisplayMode="LeftMinimal"`, `IsBackButtonVisible="Collapsed"`
and `IsPaneToggleButtonVisible="False"`, the header is shifted 24px past
the left edge and its first characters are cut off. If either button is
shown, the header looks right.

### New Behavior
When the control is in Minimal mode and no back, close or pane toggle
button is visible, `ContentLeftPadding` keeps one pane-toggle-button
slot (`PaneToggleButtonWidth`, 40px by default). The header then has the
same 16px inset it has when exactly one button is visible. Nothing else
changes: when any button is visible the padding is identical to before,
and non-Minimal modes don't use this padding at all.

```cpp
if (useLeftPaddingForBackOrCloseButton && leftPaddingForBackOrCloseButton == 0.0)
{
    leftPaddingForBackOrCloseButton = GetPaneToggleButtonWidth();
}
```

`UpdateBackAndCloseButtonsVisibility()` now also runs after a runtime
change of `PaneDisplayMode` (so LeftMinimal→Top clears the slot) and of
`CompactModeThresholdWidth`/`ExpandedModeThresholdWidth` (in `Auto`
these can flip `DisplayMode` between Minimal and Compact/Expanded
without a resize). Before this, the SplitView `DisplayMode` callback
refreshed the padding while `DisplayMode` still held the *old* value, so
the padding went stale: 40px kept in Compact, or the clipped 0 back in
Minimal. Every other path that changes the display mode (resize,
`OnApplyTemplate`, `IsBackButtonVisible`, `IsPaneToggleButtonVisible`,
`IsPaneOpen`) already refreshed it.

## Customer Impact
User-facing. Apps that hide both NavigationView buttons in LeftMinimal
(or Auto when narrow) now see their whole header instead of a clipped
one.

## Regression Potential

- [x] Low risk: 7 lines in one function (only the "Minimal + no buttons
visible" case changes), plus two one-line refresh calls on property
changes that re-run the existing padding computation.

Modes checked: Left, LeftCompact, Top and Auto (wide) don't use
`ContentLeftPadding` (`useLeftPaddingForBackOrCloseButton` is false), so
they're unchanged. LeftMinimal and Auto (narrow) change only when no
button is visible. Pane open (close button shown) is unchanged. RTL
mirrors the Grid column, so it's fine. Possible visible difference: an
app that overrides `NavigationViewMinimalHeaderMargin` with a
non-negative left value **and** hides both buttons will see its header
move 40px right. That's the same offset those apps already get when one
button is visible.

Overlap with open PR #12258 (#5306): no conflict. That PR doesn't touch
`NavigationView.cpp`, and its test asserts `ContentLeftPadding == 80`
with both buttons visible, a path this PR doesn't change. Both PRs add
tests to `NavigationViewTests.cs`, but in different places.

## How Has This Been Tested?

- [x] I have performed a self-review of my own code
- [x] I have added tests to cover my changes:
`NavigationViewTests.VerifyHeaderIsNotClippedInLeftMinimalWhenBackAndPaneToggleButtonsAreHidden`.
It measures `HeaderContent`'s left offset with only the toggle button
visible and again with no buttons, then checks that the second offset is
≥ 0 and equal to the first.
- [x] Existing tests pass (run on a test VM, x64chk; see the results
below)

Results:
- **Red** (test-only commit `0fcb1e91f`): the new test fails with
`IsGreaterThanOrEqual(-24, 0)` / `AreEqual(16, -24)`. The header is at
x=-24 with no buttons and at x=16 with one button.
- **Green** (fix commit `85060bb04`): the new test passes (1/1).
- **Regression sweep** `*NavigationViewTests*` (API + Interaction) on
the fix commit: 121 passed, 58 failed, 1 skipped. The same sweep on
`origin/main` `866ba81a1`: 36 passed, 142 failed, 1 skipped. **Every one
of the 58 failures also fails on `origin/main`, so there are 0
regressions.** The 5 API failures
(`VerifyHeaderContentMarginOn{Minimal,Top}Nav`,
`VerifyPaneDisplayModeAndDisplayModeMapping`,
`VerifyVisualTree_{Old,Optimized}Styles`) are pre-existing visual-tree
`RenderSize`/OS-version diffs on this VM. The Interaction-test failures
are environmental and flaky there.

Review follow-ups (full builds, Oct 19; compared with a shared
`origin/main` `866ba81a1` baseline run on the same VM):
- `VerifyHeaderPaddingUpdatesWhenSwitchingBetweenLeftMinimalAndTop`
(with `2ad8d8434`): passes.
-
`VerifyHeaderPaddingUpdatesWhenCompactModeThresholdWidthChangesDisplayMode`:
**red** on test-only `2b9aa04ed` (`AreEqual(0, 40)` in Compact,
`AreEqual(40, 0)` back in Minimal), **green** on fix `e6d44591f`.
- Sweep on `e6d44591f`: `*ApiTests.NavigationViewTests*` 39/44, where
the 5 failures are the same 5 pre-existing failures as on main.
`*NavigationViewTests.PaneBehaviorTests*` 33/34, where the 1 failure
(`SelectingAnItemInLeftCompactOrLeftMinimalClosesPane`) also fails on
main. **0 regressions.**

## Screenshots (if appropriate)
After fix:
<img width="899" height="604" alt="image"
src="https://github.com/user-attachments/assets/04494ae2-cef3-4875-b30b-6b91eb1c0872"
/>
<img width="881" height="587" alt="image"
src="https://github.com/user-attachments/assets/85907aad-1abf-47fe-9f2f-5b49164515ce"
/>
2026-10-22 15:06:05 +05:30
Hitesh KumarandCopilot 83ebb939f7 TableView: low-risk fixes (keyboard group toggle, gripper cursor and visuals, Fluent grid lines, scroller lookup, samples) (#12349)
## Fixes

| Internal issue | Type | Change |
|---|---|---|
| https://task.ms/64512114 | Bug | Toggling a focused group header with
the keyboard no longer jumps the viewport to earlier groups |
| https://task.ms/64475631 | Bug | A missing
`TabularSurfaceGridLineBrush` is reported once per instance (debug
diagnostic) |
| https://task.ms/63787021 | Task (part) | Scroller ancestor lookup
stops at the TableView |
| https://task.ms/64475630 | Bug | Selection indicator seeded from
accent fill tiers; unused `TabularSurfaceHeaderForegroundBrush` removed
|
| https://task.ms/63790855 | Task (part) | Sort and scroller-structure
IDL docs match current behavior (comments only) |
| https://task.ms/64475633 | Bug | Samples: remove the extra card frame
around examples |
| https://task.ms/64475637 | Bug | Samples: opt out of automatic
high-contrast backplates |
| https://task.ms/64491943 | Bug | Test only: row banding follows the
element theme (app-side fix is theme-aware brushes) |
| https://task.ms/64475632 | Bug | ResizeGripper template collapsed to
one Border; overwritten row `MinHeight` setter removed |
| https://task.ms/64475628 | Bug | ResizeGripper: no accent hover line;
1px neutral line only while dragging |
| https://task.ms/64143434 | Bug | ResizeGripper shows the East-West
resize cursor; mouse captured while dragging, released on Escape,
capture loss, disable or unload |
| https://task.ms/64475611 | Bug (part) | Grid lines use the
`DividerStrokeColorDefault` values; the new outer-border key stays in
#12307 |

## PR Type

- [x] Bugfix
- [ ] Feature
- [ ] Code style update (formatting, renaming)
- [ ] Refactoring (no functional changes, no API changes)
- [ ] Build related changes
- [x] Documentation content changes
- [ ] Other (please describe):

## Description

First of two PRs split out of #12307. This one carries only small,
low-risk fixes with **no new API** (product: +158 / −72 lines; IDL
changes are comment-only; samples +51 / −52). New API and the larger
changes stay in #12307, which is stacked on this PR.

| File | +/- | Change |
|---|---|---|
| `TableView/TableView_Keyboard.cpp` | +14 / −1 |
`OnBodyBringIntoViewRequested` ignores the focus-rescue element (row or
group header) only while a group-toggle focus restore is pending; with
no body scroller, focus reveal goes through the app's ScrollViewer |
| `TableView/TableView.cpp` (+ .h) | +11 / −4 | Missing grid-line brush
logged once; `FindScrollViewerAncestor` stops at the TableView |
| `ResizeGripper/ResizeGripper.cpp` (+ .h) | +97 / −21 | Resize cursor;
mouse capture during drag, released on Escape, capture loss, disable and
unload |
| `ResizeGripper/ResizeGripper.xaml`,
`ResizeGripper_themeresources.xaml` | +18 / −26 | Template collapsed to
one Border; hover line removed; 1px neutral line only while dragging |
| `CommonStyles/TabularSurfaces_themeresources.xaml` | +8 / −15 |
Selection indicator uses `SystemAccentColorLight2`/`Dark1`; grid lines
use `DividerStrokeColorDefault` values; unused header foreground key
removed |
| `TableView/TableView.xaml` | +0 / −2 | Overwritten row `MinHeight`
setter removed |
| `TableView/TableView.idl`, `TableViewSource.idl` | +10 / −3 | Doc
comments only |

### Current Behavior
- Toggling a focused group header near the bottom of a grouped list with
the keyboard scrolls the viewport to unrelated earlier groups.
- A missing grid-line brush is silently replaced; the scroller lookup
can walk past the TableView into app content.
- The selection indicator uses the raw accent seed color.
- The column resize gripper shows no resize cursor and draws an accent
line on hover.
- Grid lines are darker than the Fluent divider stroke.
- Samples wrap every example in an extra card and let the system draw
high-contrast backplates over the control's own colors.

### New Behavior
- The focused group header stays in view after a keyboard toggle.
- In custom templates without a body ScrollViewer, keyboard focus
reveals the focused row through the app's ScrollViewer.
- A missing grid-line brush produces one debug diagnostic per instance;
the scroller lookup is bounded by the TableView.
- The selection indicator follows Fluent accent fill tiers (small
visible color change).
- The gripper shows the East-West resize cursor and holds it during a
drag; no hover line; a 1px neutral line shows only while dragging.
- Grid lines use the fainter Fluent divider values (visible change).
- Samples show the control directly and keep its high-contrast colors.

## Customer Impact

Keyboard group toggling keeps the user's place; column resizing shows
the expected cursor and Fluent visuals; selection indicator and grid
lines match Fluent tokens; cleaner samples.

## Regression Potential

- [x] Low risk — isolated change, limited scope
- [ ] Medium risk — touches shared components or public APIs
- [ ] High risk — architectural or breaking API change

The keyboard guard applies only while a group-toggle focus restore is
pending. The removed theme key is a preview key that nothing reads. The
gripper now captures the mouse during a drag; capture is released on
Escape, capture loss, disable and unload. Grid lines use the Fluent
divider values, a visible but intended change.

## How Has This Been Tested?

- [x] I have performed a self-review of my own code
- [x] I have added tests to cover my changes
- [x] Existing tests pass locally

Full TableView suites on test VMs: 639 API tests pass (3 Localization
tests are `[Ignore]`) and 150/150 interaction tests pass. Product, test
apps and TableView samples build (x64 chk). Four rounds of automated
review (code, WinUI, regression, security) until no High+ findings.

New tests: `VerifyFocusedBottomGroupToggleKeepsViewport`,
`VerifyFocusedGroupToggleAmongCollapsedHeadersKeepsViewport`,
`VerifyDroppedGroupToggleKeepsRowBringIntoView`,
`VerifyScrollerLookupStopsAtTheTableView`,
`VerifySelectionIndicatorBrushFollowsAccentFillTiers`,
`VerifyAlternatingRowBackgroundFollowsElementThemeOppositeToApp`,
`VerifyResizeGripperHoldsResizeCursor`,
`VerifyDisablingGripperMidDragCancelsResize`,
`VerifyEndDragOnUnloadedGripperRaisesDragCompleted`,
`VerifyRemovingTableMidDragCancelsResize`,
`VerifyResizeGripperSeparatorShowsOnlyWhileDragging`,
`VerifyGridLineBrushesMatchFluentStrokeTokens`; interaction tests
`GroupHeaderKeyboardToggleAtBottomKeepsViewport`,
`PointerOverGripperShowsResizeCursor`,
`PointerResizeEscapeReleasesCapture`,
`KeyboardNavigationRevealsRowInAppScrollerWithoutBodyScroller`.

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 94961bb8-d187-483c-bece-19e203752c67
2026-10-22 13:50:02 +05:30