diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml index bc5ea6d7..ffa1b7f5 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.yml +++ b/.github/ISSUE_TEMPLATE/bug-report.yml @@ -32,7 +32,6 @@ body: - "skill: winui-session-report" - "skill: winui-wpf-migration" - "tool: winui-analyzer (Roslyn)" - - "tool: winui-search" - "tool: winmd-cli" - "area: plugin / install" - "area: docs" diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index aba27a84..59a783af 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -29,9 +29,9 @@ The `pr-target-policy` CI check enforces this. -- [ ] Agent (`plugins/winui/agents/`) +- [ ] Agent (`plugins/winui/agents/`, `plugins/winui/agent-plugin/com.github.copilot/agents/`) - [ ] Skill: -- [ ] Tool: +- [ ] Tool: - [ ] Plugin metadata (`plugin.json`, `plugins/winui/`) - [ ] Repo-level docs / governance diff --git a/.github/codeql/codeql-config.yml b/.github/codeql/codeql-config.yml index 5011c560..19e1619d 100644 --- a/.github/codeql/codeql-config.yml +++ b/.github/codeql/codeql-config.yml @@ -6,4 +6,3 @@ paths-ignore: - '**/*Tests/*.cs' - '**/bin/**' - '**/obj/**' - - 'src/tools/winui-search/Data/**' diff --git a/.github/dependabot.yml b/.github/dependabot.yml index f0f490a5..80e11163 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -45,20 +45,6 @@ updates: prefix: "deps" include: "scope" - # winui-search CLI (gallery + toolkit scenario search) - - package-ecosystem: "nuget" - directory: "/src/tools/winui-search" - schedule: - interval: "weekly" - day: "monday" - open-pull-requests-limit: 5 - labels: - - "dependencies" - - "tool: winui-search" - commit-message: - prefix: "deps" - include: "scope" - # winmd-cli (WinMD inspector) - package-ecosystem: "nuget" directory: "/src/tools/winmd-cli" diff --git a/.github/skills/pr-review/SKILL.md b/.github/skills/pr-review/SKILL.md index ca2b31ff..38c3af0a 100644 --- a/.github/skills/pr-review/SKILL.md +++ b/.github/skills/pr-review/SKILL.md @@ -16,11 +16,12 @@ This repo is **not a regular C# product**. It ships: prompt + skill prompts (`SKILL.md` files). These are **Tier 3 instructions** that agents frequently ignore (see `dimensions/skill-tool-boundary.md`). Adding prose here is the *last resort*, not the first response to any problem. -- Three **in-repo C# tools** under `src/tools/` — the WinUI 3 Roslyn analyzer, - `winmd-cli`, and `winui-search`. These are **Tier 1 enforcement** and the - preferred place to land behavior changes. -- **Committed binary payloads** (analyzer DLL, `winui-search.exe`, - `Microsoft.WindowsAppSDK.Analyzers.targets`) inside `plugins/winui/agent-plugin/skills/` +- Two **in-repo C# tools** under `src/tools/` — the WinUI 3 Roslyn analyzer + and `winmd-cli`. These are **Tier 1 enforcement** and the preferred place + to land behavior changes that belong in this repository. +- **Committed analyzer payloads** (DLL and + `Microsoft.WindowsAppSDK.Analyzers.targets`) inside + `plugins/winui/agent-plugin/skills/` that must stay in sync with their sources. CI provenance jobs will fail the PR if they drift, but it's better to flag the drift in review. @@ -114,14 +115,13 @@ focus. Common buckets in this repo: | `plugins/winui/agent-plugin/skills//references/` | skill-content (references discipline) | | `plugins/winui/agent-plugin/skills//*.ps1` (e.g. `BuildAndRun.ps1`, `Analyze-Session.ps1`) | tool-correctness, payloads-and-tests | | `plugins/winui/agent-plugin/skills/winui-dev-workflow/analyzer/` | payloads-and-tests (committed analyzer payload) | -| `plugins/winui/agent-plugin/skills/winui-design/winui-search.exe` | payloads-and-tests (committed AOT exe) | -| `plugins/winui/agents/winui-dev.agent.md` | skill-content, docs-and-manifests | +| `plugins/winui/{agents,agent-plugin/com.github.copilot/agents}/winui-dev.agent.md` | skill-content, docs-and-manifests | | `plugins/winui/agent-plugin/plugin.json` | docs-and-manifests | | `.github/plugin/marketplace.json` | docs-and-manifests | | `src/tools/winui-analyzer/Microsoft.WindowsAppSDK.Analyzers/` | tool-correctness, payloads-and-tests | | `src/tools/winui-analyzer/Microsoft.WindowsAppSDK.Analyzers.Tests/` | payloads-and-tests | | `src/tools/winui-analyzer/RULES.md` / `CHANGELOG.md` | docs-and-manifests | -| `src/tools/winmd-cli/`, `src/tools/winui-search/` | tool-correctness | +| `src/tools/winmd-cli/` | tool-correctness | | `scripts/build-tools.ps1` | payloads-and-tests | | `.github/workflows/` | docs-and-manifests (CI), payloads-and-tests (provenance) | | `README.md`, `SECURITY.md`, `SUPPORT.md` | docs-and-manifests | @@ -234,7 +234,7 @@ verdict. - **No file output.** Stdout only, unless the user explicitly asked for a file. - **No build/test execution.** Flag staleness (analyzer DLL not refreshed, - `winui-search.exe` not refreshed, `RULES.md` not updated) but do not run + `RULES.md` not updated) but do not run `scripts/build-tools.ps1` or `dotnet test` yourself — they are slow and the contributor will run them. - **Signal-to-noise.** Reject sub-agent findings that are pure style nits, diff --git a/.github/skills/pr-review/dimensions/_shared-contract.md b/.github/skills/pr-review/dimensions/_shared-contract.md index 62f75faf..3e5769ff 100644 --- a/.github/skills/pr-review/dimensions/_shared-contract.md +++ b/.github/skills/pr-review/dimensions/_shared-contract.md @@ -98,7 +98,7 @@ high. The bar for adding tooling enforcement is lower. is too scenario-specific. - Trigger-phrasing problems in `description:` frontmatter that would cause the wrong agent activation. -- Stale committed payloads (analyzer DLL, `winui-search.exe`, +- Stale committed analyzer payloads (DLL or `Microsoft.WindowsAppSDK.Analyzers.targets`) that will fail CI provenance. - Manifest / version / agent-file drift that ships broken artifacts to @@ -136,8 +136,8 @@ change should land. Cite the tier on every `skill-content` and | Tier | Type | Reliability | Examples in this repo | |------|------|-------------|------------------------| -| **0** | Environment / harness defaults | Highest — agent never sees it | `dotnet new` template choice, `BuildAndRun.ps1` defaults, prerequisite checks in `winui-setup` | -| **1** | Tooling enforcement | High — produces errors/warnings the agent must address | `Microsoft.WindowsAppSDK.Analyzers` rules, `winui-search.exe` query results, `winmd.exe` API verification, `winapp` CLI exit codes | +| **0** | Environment / harness defaults | Highest — agent never sees it | `winapp new` template choice, `BuildAndRun.ps1` defaults, prerequisite checks in `winui-setup` | +| **1** | Tooling enforcement | High — produces errors/warnings the agent must address | `Microsoft.WindowsAppSDK.Analyzers` rules, `winapp find-ui` query results, `winmd.exe` API verification, `winapp` CLI exit codes | | **2** | Templates / scaffolding | Medium — structural, applied at creation time | `Microsoft.WindowsAppSDK.WinUI.CSharp.Templates`, starter project files | | **3** | Instructions / skills | Lowest — advisory, frequently ignored | `SKILL.md` content, `winui-dev.agent.md` rules, `references/*.md` | diff --git a/.github/skills/pr-review/dimensions/docs-and-manifests.md b/.github/skills/pr-review/dimensions/docs-and-manifests.md index 5fbe35ce..a445cebb 100644 --- a/.github/skills/pr-review/dimensions/docs-and-manifests.md +++ b/.github/skills/pr-review/dimensions/docs-and-manifests.md @@ -21,13 +21,14 @@ When code or skills change, these need to keep up: - `plugins/winui/{.claude-plugin,.codex-plugin}/plugin.json` and `openclaw.plugin.json` — legacy-client adapters pointing to the canonical `agent-plugin/skills/` directory. -- `plugins/winui/agents/winui-dev.agent.md` — the orchestrator agent - prompt; mentions specific skills by name and lists default-loaded - skills. +- `plugins/winui/agents/winui-dev.agent.md` and + `plugins/winui/agent-plugin/com.github.copilot/agents/winui-dev.agent.md` — + compatibility and Copilot orchestrator prompts; mention specific skills by + name and list default-loaded skills. - `src/tools/winui-analyzer/RULES.md` — rule catalog (per-rule entry required for every shipped diagnostic; IDs are immutable). - `src/tools/winui-analyzer/CHANGELOG.md` — analyzer-scoped changelog. -- Per-tool READMEs: `src/tools/{winui-analyzer,winmd-cli,winui-search}/README.md`. +- Per-tool READMEs: `src/tools/{winui-analyzer,winmd-cli}/README.md`. - `SECURITY.md`, `SUPPORT.md`, `THIRD_PARTY_NOTICES.md`, `cgmanifest.json` — only relevant when dependencies or contact surfaces change. @@ -40,10 +41,10 @@ When code or skills change, these need to keep up: - **New skill added under `plugins/winui/agent-plugin/skills//`** without a matching row in `README.md`'s "eight skills" table → **high**. -- **Skill renamed.** `plugins/winui/agents/winui-dev.agent.md` - references skills by name (e.g. "Load the `winui-dev-workflow` - skill"). Renames must update every mention in the agent file - *and* in any sibling skill that links to it. → **high**. +- **Skill renamed.** Both orchestrator agent files reference skills by name + (e.g. "Load the `winui-dev-workflow` skill"). Renames must update every + mention in both agent files and in any sibling skill that links to it. + → **high**. - **Skill removed without README update.** Same as above, inverse. - **Skill description copy doesn't match `description:` frontmatter.** README's table is hand-curated; the canonical text lives in the @@ -102,7 +103,7 @@ When code or skills change, these need to keep up: walks `find plugins/winui/agent-plugin/skills -type f -name SKILL.md`. New skills outside this glob won't be validated → **medium**. - Any CI step's hardcoded file path - (e.g. `plugins/winui/agent-plugin/skills/winui-design/winui-search.exe`) + (e.g. `plugins/winui/agent-plugin/skills/winui-dev-workflow/analyzer/Microsoft.WindowsAppSDK.Analyzers.dll`) changed in the diff but not in the workflow → **high**. ### Other docs diff --git a/.github/skills/pr-review/dimensions/payloads-and-tests.md b/.github/skills/pr-review/dimensions/payloads-and-tests.md index c33af89d..b24fc946 100644 --- a/.github/skills/pr-review/dimensions/payloads-and-tests.md +++ b/.github/skills/pr-review/dimensions/payloads-and-tests.md @@ -6,10 +6,10 @@ Set `Domain: payloads-and-tests` on every finding. ## What this dimension owns -This repo commits **prebuilt binary payloads** alongside source for -two of its tools, and the CI `pr-validation` workflow has provenance -jobs that fail the PR if those payloads drift from source. This -dimension's job is to flag drift *before* the contributor pushes. +This repo commits the analyzer's **prebuilt payloads** alongside source, +and the CI `pr-validation` workflow has provenance jobs that fail the PR +if those payloads drift from source. This dimension's job is to flag +drift *before* the contributor pushes. The payloads: @@ -17,10 +17,9 @@ The payloads: |---|---|---| | `plugins/winui/agent-plugin/skills/winui-dev-workflow/analyzer/Microsoft.WindowsAppSDK.Analyzers.dll` | `src/tools/winui-analyzer/Microsoft.WindowsAppSDK.Analyzers/` | `analyzer-provenance` (sha256 + size delta) | | `plugins/winui/agent-plugin/skills/winui-dev-workflow/analyzer/Microsoft.WindowsAppSDK.Analyzers.targets` | `src/tools/winui-analyzer/Microsoft.WindowsAppSDK.Analyzers/Microsoft.WindowsAppSDK.Analyzers.targets` | `analyzer-targets-sync` (byte-identical) | -| `plugins/winui/agent-plugin/skills/winui-design/winui-search.exe` | `src/tools/winui-search/` | `winui-search-provenance` (smoke + size ±10%) | -Refresh command: `./scripts/build-tools.ps1` (no flags) rebuilds all -three tools and refreshes both payloads. The contributor will run +Refresh command: `./scripts/build-tools.ps1` (no flags) rebuilds both +C# tools and refreshes the analyzer payloads. The contributor will run this — you only flag drift. ## What to look for @@ -39,21 +38,11 @@ this — you only flag drift. Same pattern but for `Microsoft.WindowsAppSDK.Analyzers.targets`. CI `analyzer-targets-sync` requires byte-identical files. → **high**. -- **`winui-search` source touched, exe not refreshed.** Diff - includes `src/tools/winui-search/**` *but not* - `plugins/winui/agent-plugin/skills/winui-design/winui-search.exe` → **high**. - CI `winui-search-provenance` runs smoke tests (`list`, `search - tabview` → must include `gallery-tabview`) and a ±10% size - comparison. - **Payload-only change (no source).** The inverse — committed DLL - or exe updated without a corresponding source diff. Either the + or `.targets` updated without a corresponding source diff. Either the source was already on `main` (fine — this is a refresh PR) or someone hand-edited the binary (red flag). → **medium**, ask the contributor to confirm. -- **`winui-search` data files updated without rebuild.** Diff - touches `src/tools/winui-search/Data/*.json` *but not* the - committed exe. The data is **embedded** at build time — JSON - changes have no effect until the exe is republished. → **high**. ### Analyzer test coverage @@ -124,10 +113,8 @@ findings, but additionally: ## Severity guide for this dimension -- Source touched but committed payload not refreshed (DLL, .targets, - or exe) → **high** (CI provenance will fail). -- `winui-search` data JSON edited without exe rebuild → **high** - (the change is invisible at runtime). +- Source touched but committed payload not refreshed (DLL or .targets) + → **high** (CI provenance will fail). - New analyzer rule with no test → **high**. - New tool not wired into `build-tools.ps1` → **medium**. - Allowlist change without regression test → **medium**. diff --git a/.github/skills/pr-review/dimensions/skill-content.md b/.github/skills/pr-review/dimensions/skill-content.md index 25ddd8a1..7234ef2f 100644 --- a/.github/skills/pr-review/dimensions/skill-content.md +++ b/.github/skills/pr-review/dimensions/skill-content.md @@ -14,8 +14,9 @@ This dimension reviews **prose changes** to: - `plugins/winui/agent-plugin/skills//SKILL.md` (the 8 shipped skills) - `plugins/winui/agent-plugin/skills//references/*.md` (deep-dive references loaded on demand) -- `plugins/winui/agents/winui-dev.agent.md` (the orchestrator agent - prompt) +- `plugins/winui/agents/winui-dev.agent.md` and + `plugins/winui/agent-plugin/com.github.copilot/agents/winui-dev.agent.md` + (orchestrator agent prompts) - `.github/skills//SKILL.md` (repo-internal skills like this one) The audience for this content is **AI coding agents** (Copilot CLI, @@ -62,7 +63,7 @@ priors. Every line of prose must pull its weight. re-state rules already covered in a sibling skill — link or reference instead. Flag when the same checklist appears twice. - **Restating help text.** Bullets that re-document what `winapp - --help`, `winui-search list`, or `winmd --help` already prints are + --help`, `winapp find-ui --help`, or `winmd --help` already prints are pure context inflation. - **"Best practices" laundry lists** with no concrete change in agent behavior (e.g. "follow YAGNI / DRY / KISS") — these are universally @@ -89,8 +90,8 @@ priors. Every line of prose must pull its weight. read. - **References that should be tool data.** A long reference file that is essentially a catalogue of WinUI controls, snippets, or API - signatures duplicates `winui-search.exe`'s data. Flag and emit a - paired `skill-tool-boundary` finding (Tier 1 alternative). + signatures duplicates `winapp find-ui` or `winmd` data. Flag and emit + a paired `skill-tool-boundary` finding (Tier 1 alternative). ### Trigger / activation hygiene diff --git a/.github/skills/pr-review/dimensions/skill-tool-boundary.md b/.github/skills/pr-review/dimensions/skill-tool-boundary.md index a5451f31..5f757a0a 100644 --- a/.github/skills/pr-review/dimensions/skill-tool-boundary.md +++ b/.github/skills/pr-review/dimensions/skill-tool-boundary.md @@ -20,8 +20,8 @@ consider them before defaulting to Tier 3 prose. | Tier | Type | Reliability | In-repo examples | |------|------|-------------|-------------------| -| **0** | Environment / harness defaults | Highest — agent never sees it | `dotnet new` template choice baked into `winui-dev-workflow`, `BuildAndRun.ps1` defaults, `winui-setup` prerequisite checks | -| **1** | Tooling enforcement | High — produces diagnostics agent must address | `Microsoft.WindowsAppSDK.Analyzers` rules (WUI0xxx-WUI4xxx), `winui-search.exe` queries, `winmd.exe` API verification, `winapp` CLI exit codes | +| **0** | Environment / harness defaults | Highest — agent never sees it | `winapp new` template choice, `BuildAndRun.ps1` defaults, `winui-setup` prerequisite checks | +| **1** | Tooling enforcement | High — produces diagnostics agent must address | `Microsoft.WindowsAppSDK.Analyzers` rules (WUI0xxx-WUI4xxx), `winapp find-ui` queries, `winmd.exe` API verification, `winapp` CLI exit codes | | **2** | Templates / scaffolding | Medium — structural, applied once | `Microsoft.WindowsAppSDK.WinUI.CSharp.Templates`, starter `.csproj` defaults | | **3** | Instructions / skills | Lowest — advisory, frequently ignored | `SKILL.md` content, `winui-dev.agent.md` rules, `references/*.md` | @@ -53,10 +53,11 @@ This is the most common drift. Symptoms: This is what `winmd.exe` is for — recommend invoking it from the skill instead of duplicating the rule. - A new list of **WinUI control names or sample patterns**. This is - what `winui-search.exe` is for. The skill should *describe how to + what `winapp find-ui` is for. The skill should *describe how to query* the tool, not embed the catalogue. -- A new bullet that says **"after building, do X"**. This usually - belongs in `BuildAndRun.ps1` (Tier 0) so the agent gets it for free. +- A new bullet that says **"after building, do X"**. General build/run + behavior belongs in the upstream `winapp` command so every caller gets it; + reserve `BuildAndRun.ps1` for analyzer injection and diagnostic defaults. - A new "common error" entry that boils down to a missing prerequisite — that belongs in `winui-setup` (Tier 0/1). @@ -64,8 +65,10 @@ For each such finding: - Severity: **medium** (would be high if the analyzer/tool clearly could enforce it but the contributor chose prose). - Recommendation: name the specific Tier 1 hook — "Add an analyzer - rule under `WUI20xx` (runtime/layout/XAML pitfalls)", "Extend - `winui-search` index", "Add a step to `BuildAndRun.ps1`". + rule under `WUI20xx` (runtime/layout/XAML pitfalls)", "Improve the + upstream `winapp find-ui` corpus", or "Improve the relevant upstream + `winapp` subcommand". Recommend `BuildAndRun.ps1` only for analyzer or + diagnostic-default behavior. ### Skill prose that should be a Tier 2 (template) change @@ -139,9 +142,6 @@ Less common but real: than a real WinUI pitfall. Analyzer noise erodes trust in the whole catalog. Recommend converting to skill guidance (Tier 3) or dropping. -- A new `winui-search` synonym hack that encodes a single - contributor's mental model rather than a generally useful query - alias. - A new `winmd-cli` flag that exists only to match one skill's exact output format — couplings like this should be inverted (skill adapts to tool, not vice versa). @@ -179,8 +179,9 @@ justification, the addition is misplaced — emit a finding. - New skill prose duplicating an existing analyzer rule → **medium** (Tier 3, recommend cite-the-rule-instead). -- New skill prose that should clearly have been a new analyzer rule - / new `winui-search` data / new `BuildAndRun.ps1` step → **high** +- New skill prose that should clearly have been a new analyzer rule, + an upstream `winapp find-ui` improvement, or a new `BuildAndRun.ps1` + step → **high** if the change is large and the Tier 1 path is straightforward; **medium** otherwise. - New skill prose that should clearly have been a `winapp` CLI diff --git a/.github/skills/pr-review/dimensions/tool-correctness.md b/.github/skills/pr-review/dimensions/tool-correctness.md index 681032d9..7110602f 100644 --- a/.github/skills/pr-review/dimensions/tool-correctness.md +++ b/.github/skills/pr-review/dimensions/tool-correctness.md @@ -19,7 +19,6 @@ C# / PowerShell code under: - `src/tools/winui-analyzer/Microsoft.WindowsAppSDK.Analyzers/` — Roslyn analyzer (netstandard2.0). - `src/tools/winmd-cli/` — Native-AOT WinRT/.NET metadata indexer. -- `src/tools/winui-search/` — Native-AOT BM25 search exe. - `plugins/winui/agent-plugin/skills/winui-dev-workflow/BuildAndRun.ps1` - `plugins/winui/agent-plugin/skills/winui-session-report/Analyze-Session.ps1` - `scripts/build-tools.ps1` @@ -58,7 +57,7 @@ directly break agent sessions. **medium**; cache lookups via `RegisterCompilationStartAction` instead. -### Native AOT (winmd-cli & winui-search) +### Native AOT (winmd-cli) - **AOT-incompat reflection.** No `Activator.CreateInstance(Type)`, no `Assembly.GetTypes()`-then-reflect, no `JsonSerializer` without @@ -68,11 +67,9 @@ directly break agent sessions. `IL3050` / `IL2104` warnings under `PublishAot=true`. Suppressions must include a justifying comment. - **Single-file assumptions.** Don't read `Assembly.Location` or - `AppContext.BaseDirectory + relative file` in winui-search / - winmd-cli new code; both ship as single-file exes and these paths - behave differently from the source-build dev experience. -- **Embedded resources.** `winui-search` data is embedded JSON; new - resource names must match `EmbeddedResource` items in the csproj. + `AppContext.BaseDirectory + relative file` in winmd-cli new code; it + ships as a single-file exe and these paths behave differently from + the source-build dev experience. ### Repo-specific PowerShell rules diff --git a/.github/workflows/pr-validation.yml b/.github/workflows/pr-validation.yml index 89f0ed29..6b21a5c3 100644 --- a/.github/workflows/pr-validation.yml +++ b/.github/workflows/pr-validation.yml @@ -35,9 +35,6 @@ jobs: - name: Test Microsoft.WindowsAppSDK.Analyzers run: dotnet test src/tools/winui-analyzer/Microsoft.WindowsAppSDK.Analyzers.Tests/Microsoft.WindowsAppSDK.Analyzers.Tests.csproj -c Release --no-build --logger "console;verbosity=normal" - - name: Build winui-search - run: dotnet build src/tools/winui-search/winui-search.csproj -c Release - - name: Build winmd-cli run: dotnet build src/tools/winmd-cli/winmd.csproj -c Release @@ -104,91 +101,6 @@ jobs: echo "::warning::Analyzer DLL hash differs but size delta is small ($SIZE_DELTA bytes) — likely deterministic-build drift across SDK versions, not a source change. Investigate before merging." fi - winui-search-provenance: - name: winui-search.exe provenance - runs-on: windows-latest - steps: - - name: Checkout - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - - name: Setup .NET - uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 - with: - dotnet-version: 10.0.x - - - name: Smoke-test the committed winui-search.exe - shell: pwsh - run: | - # The skill ships a prebuilt unsigned Native AOT winui-search.exe. - # We can't compare hashes against a CI rebuild reliably (AOT codegen - # has small non-determinism across toolchain patch versions). Instead - # we (a) prove the committed exe runs and produces real catalogue - # output, and (b) cross-publish from source and compare sizes with a - # generous tolerance to catch "source changed but exe wasn't - # rebuilt and recommitted" — the failure mode that actually matters. - - $committed = "plugins/winui/agent-plugin/skills/winui-design/winui-search.exe" - if (-not (Test-Path $committed)) { - Write-Host "::error::Committed winui-search.exe not found at $committed" - exit 1 - } - - $listOutput = & $committed list 2>&1 | Out-String - if ($LASTEXITCODE -ne 0 -or $listOutput -notmatch 'Available patterns') { - Write-Host "::error::Committed winui-search.exe failed smoke test (list)." - Write-Host $listOutput - exit 1 - } - - $searchOutput = & $committed search "tabview" 2>&1 | Out-String - if ($LASTEXITCODE -ne 0 -or $searchOutput -notmatch 'gallery-tabview') { - Write-Host "::error::Committed winui-search.exe failed smoke test (search 'tabview' did not return gallery-tabview)." - Write-Host $searchOutput - exit 1 - } - - Write-Host "Committed winui-search.exe smoke test passed." - $committedSize = (Get-Item $committed).Length - Write-Host "Committed size: $committedSize bytes" - "COMMITTED_SIZE=$committedSize" | Out-File -Append -FilePath $env:GITHUB_ENV - - - name: Cross-publish winui-search from source - shell: pwsh - run: | - dotnet publish src/tools/winui-search/winui-search.csproj ` - -c Release -r win-x64 --self-contained true ` - /p:PublishAot=true /p:StripSymbols=true --nologo - if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } - - - name: Compare CI-built size vs committed size - shell: pwsh - run: | - $built = "src/tools/winui-search/bin/Release/net10.0/win-x64/publish/winui-search.exe" - if (-not (Test-Path $built)) { - Write-Host "::error::CI-built winui-search.exe not found at $built" - exit 1 - } - $builtSize = (Get-Item $built).Length - $committedSize = [int]$env:COMMITTED_SIZE - $delta = $builtSize - $committedSize - $absDelta = [Math]::Abs($delta) - $pctDelta = [Math]::Round(($absDelta / [double]$committedSize) * 100, 2) - - Write-Host "Committed: $committedSize bytes" - Write-Host "CI-built: $builtSize bytes" - Write-Host "Delta: $delta bytes ($pctDelta%)" - - # 10% tolerance: AOT codegen can produce small variations across - # SDK patch versions, but a real source change (new commands, new - # data files, etc.) will move the binary by far more than 10%. - if ($pctDelta -gt 10) { - Write-Host "::error::winui-search.exe size differs by $pctDelta% — likely source changed without rebuilding the committed exe." - Write-Host "::error::Run: ./scripts/build-tools.ps1, then commit the refreshed plugins/winui/agent-plugin/skills/winui-design/winui-search.exe" - exit 1 - } else { - Write-Host "::notice::winui-search.exe size delta $pctDelta% is within tolerance." - } - validate-plugin-manifest: name: Validate Agent Plugins package runs-on: ubuntu-latest diff --git a/.pipelines/templates/build.yaml b/.pipelines/templates/build.yaml index e0bd8e1e..19f96bee 100644 --- a/.pipelines/templates/build.yaml +++ b/.pipelines/templates/build.yaml @@ -6,7 +6,7 @@ steps: - task: PowerShell@2 - displayName: Build C# tools (analyzer, winmd-cli, winui-search) + displayName: Build C# tools (analyzer, winmd-cli) inputs: pwsh: true filePath: $(System.DefaultWorkingDirectory)\scripts\build-tools.ps1 diff --git a/CHANGELOG.md b/CHANGELOG.md index bb5c20f4..e9b70e20 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,11 +23,19 @@ The `version-bump` and `changelog-entry` CI jobs enforce this. ### Added +- WinApp CLI 0.6 integration: new projects use `winapp new`, and WinUI + control/sample discovery uses `winapp find-ui`. - Added reusable SVG and 512 px PNG WinUI artwork for marketplace listings. ### Changed - Adopted the [Agent Plugins 1.0 specification](https://agent-plugins.org/specification) and [Agent Skills specification](https://agentskills.io/specification) for portable skill packaging. The conforming package now has its own `plugins/winui/agent-plugin` root, while Claude Code, OpenAI Codex, and OpenClaw retain a containing compatibility package because their required legacy root files are not valid Agent Plugins extension namespaces. +- The skills now require WinApp CLI 0.6 or later. `BuildAndRun.ps1` is a thin + wrapper over project-mode `winapp run`; it keeps only the bundled analyzer + injection and default crash diagnostics while WinApp CLI handles restore, + build, output discovery, runtime setup, registration, and launch. +- `winui-setup` no longer installs the WinUI template pack separately because + `winapp new` manages templates on demand. - `winui-setup` now gives harness-neutral post-setup guidance while preserving the GitHub Copilot CLI invocation example. @@ -35,6 +43,10 @@ The `version-bump` and `changelog-entry` CI jobs enforce this. ### Removed +- The in-repo `winui-search` source, unsigned executable payload, dependency + metadata, and CI provenance job; WinApp CLI 0.6's `winapp find-ui` is now the + single supported search surface. + ### Deprecated ## [0.5.0] — 2026-07-21 diff --git a/README.md b/README.md index d515a7d3..a8bac56d 100644 --- a/README.md +++ b/README.md @@ -23,10 +23,10 @@ Install the Copilot CLI plugin "winui" from microsoft/win-dev-skills, then set u 1. Run: copilot plugin marketplace add microsoft/win-dev-skills 2. Run: copilot plugin install winui@win-dev-skills -3. Make sure these prerequisites are present (check first; .NET only installs if missing, but WinApp CLI and templates always upgrade to latest): - - .NET SDK >= 8.0 (run `dotnet --list-sdks`; if none >= 8.0, `winget install --id Microsoft.DotNet.SDK.10 --exact --silent --accept-package-agreements --accept-source-agreements`) - - WinApp CLI: must be >= 0.3 (parse `winapp --version`); if missing or older, `winget install --id Microsoft.WinAppCLI`. THEN regardless run `winget upgrade --id Microsoft.WinAppCLI` to get the latest. - - WinUI 3 templates: always run `dotnet new install Microsoft.WindowsAppSDK.WinUI.CSharp.Templates` (after refreshing $env:Path) — it upgrades in place if already installed. +3. Make sure these prerequisites are present (check first and change only what is missing or too old): + - .NET SDK >= 8.0.100 (run `dotnet --list-sdks`; if none qualifies, `winget install --id Microsoft.DotNet.SDK.10 --exact --silent --accept-package-agreements --accept-source-agreements`) + - WinApp CLI: must be >= 0.6.0 (parse the standalone version line from `winapp --version`); if missing, `winget install --id Microsoft.WinAppCli`; if older, `winget upgrade --id Microsoft.WinAppCli`. + - Do not install WinUI templates separately — WinApp CLI 0.6+ installs and updates them on demand through `winapp new`. - Developer Mode (DWORD HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock\AllowDevelopmentWithoutDevLicense == 1) — ASK ME first before triggering UAC; if I decline, just print the elevated command for me to run later. 4. Print a short summary of what was installed vs already present, then tell me to start a new Copilot CLI, activate the "winui-dev" agent, and to ask it to build an app. ``` @@ -130,9 +130,8 @@ Once setup is done, try a real task: | Tool | Minimum | Recommended | Install command | |---|---|---|---| | Git | 2.54 | 2.54+ | `winget install Git.Git` | -| .NET SDK | 8.0 | 10.0 | `winget install Microsoft.DotNet.SDK.10` | -| WinApp CLI | 0.3 | latest | `winget install Microsoft.WinAppCLI` | -| WinUI 3 templates | — | latest | `dotnet new install Microsoft.WindowsAppSDK.WinUI.CSharp.Templates` | +| .NET SDK | 8.0.100 | 10.0 | `winget install Microsoft.DotNet.SDK.10` | +| WinApp CLI | 0.6.0 | latest | `winget install Microsoft.WinAppCli` | | Developer Mode | enabled | enabled | DWORD `AllowDevelopmentWithoutDevLicense` set to `1` | Visual Studio is **not required** — these skills build and run entirely with dotnet. Neither setup path will install it; if you want it as an IDE, run: @@ -142,11 +141,11 @@ winget install Microsoft.VisualStudio.Community --override "--add Microsoft.Visu ``` > [!NOTE] -> **Older Windows App SDK versions had a XAML-compiler bug** under `dotnet build`: a malformed `.xaml` file produced no useful diagnostic — the build just failed with a cryptic `MSB3073` (`XamlCompiler.exe ... exited with code 1`) and no indication of which `.xaml` was wrong. This is **fixed in current releases** — Windows App SDK **≥ 2.1.3** on the 2.x line and **≥ 1.8** on the 1.x line. If you hit a cryptic build failure with no XAML diagnostic, **update the `Microsoft.WindowsAppSDK` NuGet package to the latest version**. The `winui-dev-workflow` [`BuildAndRun.ps1`](plugins/winui/agent-plugin/skills/winui-dev-workflow/BuildAndRun.ps1) helper builds with `dotnet build` by default and can optionally use Visual Studio's MSBuild via `-UseMSBuild`. +> **Older Windows App SDK versions had a XAML-compiler bug** under `dotnet build`: a malformed `.xaml` file produced no useful diagnostic — the build just failed with a cryptic `MSB3073` (`XamlCompiler.exe ... exited with code 1`) and no indication of which `.xaml` was wrong. This is **fixed in current releases** — Windows App SDK **≥ 2.1.3** on the 2.x line and **≥ 1.8** on the 1.x line. If you hit a cryptic build failure with no XAML diagnostic, **update the `Microsoft.WindowsAppSDK` NuGet package to the latest version**. WinApp CLI 0.6+ builds the project directly through `winapp run `. ## Why a Copilot CLI plugin? -Modern Windows app development covers a lot of ground — XAML and Fluent Design, MVVM, MSIX packaging, code signing, Store submission, accessibility, theming, UI automation. AI agents working from generic web context tend to mix WinUI 3 with older stacks (UWP, WPF), miss the packaged-execution model, or stop short of running and verifying what they built. These skills **stay in the WinUI 3 lane end-to-end** — from `dotnet new` through a signed MSIX — and pair the agent with tools that give it real, ground-truth answers instead of guesses. +Modern Windows app development covers a lot of ground — XAML and Fluent Design, MVVM, MSIX packaging, code signing, Store submission, accessibility, theming, UI automation. AI agents working from generic web context tend to mix WinUI 3 with older stacks (UWP, WPF), miss the packaged-execution model, or stop short of running and verifying what they built. These skills **stay in the WinUI 3 lane end-to-end** — from `winapp new` through a signed MSIX — and pair the agent with tools that give it real, ground-truth answers instead of guesses. The result: you ask `copilot -p "create a WinUI 3 photo viewer with thumbnails and EXIF metadata"`, and the agent picks the right template, scaffolds the project, designs the XAML with theming and accessibility in mind, wires up MVVM correctly, builds, fixes errors with real diagnostics, launches through the right packaged-execution pipeline, and (if you ask) drives the running app through UI automation to validate it works. @@ -171,7 +170,6 @@ plugins/winui/ Legacy-client compatibility package root agents/ The Copilot orchestrator agent src/tools/ Source for the in-repo tools shipped with the skills winmd-cli/ Native-AOT WinRT/.NET metadata indexer (winmd.exe) - winui-search/ Native-AOT search over WinUI Gallery + Toolkit + Reactor (winui-search.exe) winui-analyzer/ Microsoft.WindowsAppSDK.Analyzers Roslyn analyzer scripts/ Helper scripts (see scripts/build-tools.ps1) ``` @@ -186,14 +184,14 @@ Each skill is a focused, self-contained playbook. The agent loads `winui-design` | Skill | What it does | |---|---| -| **`winui-dev-workflow`** | Build and run workflow — project creation from templates, the `BuildAndRun.ps1` helper, `winapp run`, error diagnosis, prerequisites. Use when building, running, or fixing build errors. | -| **`winui-design`** | UI design and XAML correctness — layout planning, control selection, Fluent Design, theming (Light/Dark/HighContrast), typography, spacing, brushes, accessibility, data-binding review. Bundles `winui-search.exe` for grounded control lookup against the WinUI Gallery, Community Toolkit, and Reactor catalogue. | +| **`winui-dev-workflow`** | Build and run workflow — `winapp new`, project-mode `winapp run`, the analyzer-injecting `BuildAndRun.ps1` helper, crash diagnosis, and prerequisites. | +| **`winui-design`** | UI design and XAML correctness — layout planning, control selection, Fluent Design, theming (Light/Dark/HighContrast), typography, spacing, brushes, accessibility, data-binding review, and grounded sample lookup with `winapp find-ui`. | | **`winui-code-review`** | Code-quality review before committing — MVVM compliance, `x:Bind` correctness, accessibility, theming, security, performance. Catches what the compiler and UI tests won't. | | **`winui-ui-testing`** | Automated UI testing — generates a batch test script, runs all tests in one pass, reads results. Covers element assertions, interactions, value checks (TextBox, ComboBox, ToggleSwitch), file pickers, flyouts, dialogs, persistence, accessibility audits. | | **`winui-packaging`** | MSIX packaging, code signing, and distribution — release builds, certificate generation (`winapp cert generate`), trust, signing (`winapp sign`), self-contained deployment, GitHub Actions CI/CD, and Microsoft Store submission. | | **`winui-wpf-migration`** | WPF → WinUI 3 migration — namespace replacement, control mapping (`DataGrid` → `ListView`, `WrapPanel` → `ItemsRepeater`, `TabControl` → `TabView`), `Dispatcher` → `DispatcherQueue`, `System.Drawing` → `BitmapImage`, MVVM conversion to CommunityToolkit.Mvvm, `DynamicResource` → `ThemeResource`. | | **`winui-session-report`** | Diagnostic report on the current or a recent Copilot session. Runs only after an explicit request for session feedback, agent debugging, or a review of what happened during a build session. | -| **`winui-setup`** | Install and verify machine prerequisites — .NET SDK 10, the WinApp CLI, the WinUI 3 .NET templates, and Developer Mode. Idempotent. **Explicit confirmation required** — if selected without an explicit setup request, the skill stops before running checks or installations and asks the user to confirm. | +| **`winui-setup`** | Install and verify machine prerequisites — .NET SDK 8.0.100+, WinApp CLI 0.6+, and Developer Mode. Templates are managed on demand by `winapp new`. Idempotent and **explicit confirmation required**. | ## The tools we lean on @@ -201,8 +199,7 @@ Skills are *prompts plus playbooks*. They get their actual leverage from a small ### External tools the skills depend on -* **[`winapp` CLI](https://github.com/microsoft/winappcli)** (`winget install Microsoft.WinAppCLI`) — the command-line driver for installing, running, signing, packaging, and **automating** WinUI 3 / WinAppSDK apps. **Without `winapp`, these skills wouldn't be possible.** Packaged WinUI 3 apps can't just be launched as a `.exe` — they need to be installed and started through the right activation pipeline. `winapp run` does exactly that and streams the app's debug output back to the agent so it can see crashes and exceptions instead of staring at silence. `winapp ui` powers the entire `winui-ui-testing` skill: enumerating elements, asserting state, driving controls, capturing accessibility audits — all from the command line, all scriptable, all readable by an AI agent. `winapp manifest` and `winapp pack` are what makes `winui-packaging` able to take a build all the way to a signed MSIX. `winapp` is being built **in parallel** with these skills, in lockstep — every time a skill needed a new automation surface or a tighter feedback loop, that requirement landed in `winapp` first. -* **[`Microsoft.WindowsAppSDK.WinUI.CSharp.Templates`](https://www.nuget.org/packages/Microsoft.WindowsAppSDK.WinUI.CSharp.Templates)** — the new `dotnet new` templates for WinUI 3 + Windows App SDK. The dev-workflow skill uses these as the canonical scaffold so every new project starts from the same supported baseline. +* **[`winapp` CLI 0.6+](https://github.com/microsoft/winappcli)** (install with `/winui-setup`) — the command-line driver for scaffolding, discovering UI samples, building, running, signing, packaging, and **automating** WinUI 3 / WinAppSDK apps. `winapp new` manages the official WinUI template pack and creates projects; `winapp find-ui` returns grounded Gallery/Toolkit/core samples; project-mode `winapp run` builds a `.csproj` and launches packaged or unpackaged output; `winapp ui` powers the UI-testing skill; and `winapp manifest`/`winapp package` carry builds through signed MSIX creation. ### In-repo tools — what's running on your machine @@ -212,8 +209,7 @@ Several skills ship helper binaries and PowerShell scripts that run under your u |---|---|---|---| | **`Microsoft.WindowsAppSDK.Analyzers.dll`** (Roslyn analyzer) | [`src/tools/winui-analyzer/`](src/tools/winui-analyzer/) | Catches common WinUI 3 / WinAppSDK pitfalls at build time: UWP namespace leaks, `Window.Current`, `CoreDispatcher`, `WebView2` without `EnsureCoreWebView2Async`, raw `TabView` content, attached-property syntax bugs, removed ONNX GenAI APIs, the old field-backed `[ObservableProperty]` pattern, and more. Every rule ships at `Warning` severity (no `Error`s) and includes a `helpLinkUri`. Verified against source on every PR by the `analyzer-provenance` CI job. | Publish as the `Microsoft.WindowsAppSDK.Analyzers` NuGet package; skill stops shipping the prebuilt DLL and projects pick it up via ``. | | **`winmd.exe`** (winmd-cli) | [`src/tools/winmd-cli/`](src/tools/winmd-cli/) | Native-AOT WinRT/.NET metadata indexer. The agent uses it to verify an API actually exists and has the signature it thinks it does — *before* writing code that won't compile. Reads `.winmd` and managed `.dll` metadata from NuGet, the Windows SDK, and WinAppSDK and returns the same XML doc text Visual Studio IntelliSense uses. | Publish as a `dotnet tool` on NuGet, or fold relevant subcommands into [`winappcli`](https://github.com/microsoft/winappcli). | -| **`winui-search.exe`** (winui-search) | [`src/tools/winui-search/`](src/tools/winui-search/) | Native-AOT BM25 search over [WinUI Gallery](https://github.com/microsoft/WinUI-Gallery), [CommunityToolkit/Windows](https://github.com/CommunityToolkit/Windows), and [microsoft-ui-reactor](https://github.com/microsoft/microsoft-ui-reactor) scenarios. Lets the agent see real shipping samples for a control before writing a single line of XAML. Embedded JSON snapshots ship offline; live refresh via `winui-search update`. **Distributed today as a prebuilt unsigned exe inside the `winui-design` skill payload**, verified on every PR by the `winui-search-provenance` CI job. | Same as `winmd-cli` — `dotnet tool`, fold into `winappcli`, or expose over a small MCP server. | -| **`BuildAndRun.ps1`** | [`plugins/winui/agent-plugin/skills/winui-dev-workflow/BuildAndRun.ps1`](plugins/winui/agent-plugin/skills/winui-dev-workflow/BuildAndRun.ps1) | Builds with `dotnet build` (checks Developer Mode, auto-detects platform, injects the WinAppSDK analyzer), then hands off to `winapp run`. Can optionally build with Visual Studio's MSBuild via `-UseMSBuild`. | The MSBuild path is now optional — current Windows App SDK releases surface XAML errors under `dotnet build`, so it defaults to `dotnet build`. Kept as a convenience wrapper; candidate to fold into [`winappcli`](https://github.com/microsoft/winappcli). | +| **`BuildAndRun.ps1`** | [`plugins/winui/agent-plugin/skills/winui-dev-workflow/BuildAndRun.ps1`](plugins/winui/agent-plugin/skills/winui-dev-workflow/BuildAndRun.ps1) | Thin wrapper over project-mode `winapp run`: injects the bundled WinAppSDK analyzer through a temporary MSBuild props file and enables crash diagnostics by default. WinApp CLI owns restore, build, architecture/output discovery, runtime setup, registration, and launch. | Remove when the analyzer is published as a NuGet package and projects can reference it directly. | | **`Analyze-Session.ps1`** | [`plugins/winui/agent-plugin/skills/winui-session-report/Analyze-Session.ps1`](plugins/winui/agent-plugin/skills/winui-session-report/Analyze-Session.ps1) | Reads your local Copilot session events and produces a `session-report.md` for bug filing. **The report can include excerpts of your prompts, file paths, and command output — review it before sharing.** The skill prints a privacy notice when it runs. | Fold into the `copilot` CLI as a session-report subcommand, or publish as a `dotnet tool`. | If any of this is a deal-breaker for your environment, please [open an issue](https://github.com/microsoft/win-dev-skills/issues) — that feedback is what determines how quickly each item moves out of "preview, ships from repo" into "signed package on a registry". @@ -221,10 +217,9 @@ If any of this is a deal-breaker for your environment, please [open an issue](ht ### Building the in-repo tools yourself ```powershell -# Build all three tools (AOT-publishes winmd-cli and winui-search), run the -# analyzer test suite, and refresh both committed payloads (analyzer DLL inside -# winui-dev-workflow, winui-search.exe inside winui-design). This is the same -# build the pr-validation workflow runs in CI. +# Build both C# tools, run the analyzer test suite, AOT-publish winmd-cli, +# and refresh the committed analyzer payload. This is the same build the +# pr-validation workflow runs in CI. ./scripts/build-tools.ps1 ``` @@ -232,7 +227,6 @@ Per-tool READMEs cover what they do and how to consume them in more detail: * [`src/tools/winui-analyzer/README.md`](src/tools/winui-analyzer/README.md) — analyzer + rule catalog * [`src/tools/winmd-cli/README.md`](src/tools/winmd-cli/README.md) — `winmd` CLI usage -* [`src/tools/winui-search/README.md`](src/tools/winui-search/README.md) — `winui-search` CLI usage ## Pinning to a release diff --git a/RELEASING.md b/RELEASING.md index 99114a76..aa8a525f 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -168,7 +168,7 @@ the CI workflows alone are not enough. 2. **Branch protection on `staging`** (CRITICAL — strict mode is REQUIRED, not optional): - Require PR before merging. - Require status checks: `build-tools`, `analyzer-provenance`, - `winui-search-provenance`, `validate-plugin-manifest`, + `validate-plugin-manifest`, `validate-skill-frontmatter`, `analyzer-targets-sync`, `version-sync`, `staging-up-to-date-with-main`. - **"Require branches to be up to date before merging" — MUST be on.** diff --git a/THIRD_PARTY_NOTICES.md b/THIRD_PARTY_NOTICES.md index 7682b588..33f776c7 100644 --- a/THIRD_PARTY_NOTICES.md +++ b/THIRD_PARTY_NOTICES.md @@ -9,87 +9,6 @@ embedded data snapshots, or significant runtime dependencies change. For machine-readable component governance metadata, see [`cgmanifest.json`](cgmanifest.json). ---- - -## 1. WinUI-Gallery (microsoft/WinUI-Gallery) - -- **Source:** https://github.com/microsoft/WinUI-Gallery -- **License:** MIT -- **Used as:** - - Embedded JSON snapshot of control scenarios in - `src/tools/winui-search/Data/gallery-scenarios.json` and - `src/tools/winui-search/Data/gallery-tags.json`. - - Live fetch target for `src/tools/winui-search/GalleryFetcher.cs`, - which downloads sample C#/XAML on demand from `main`. - -The Gallery is owned by the same WinUI engineering team that owns this -repository. Snapshots are regenerated periodically; see -[`scripts/`](scripts) for the regeneration tooling. - -``` -MIT License - -Copyright (c) Microsoft Corporation. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -``` - ---- - -## 2. Windows Community Toolkit (CommunityToolkit/Windows) - -- **Source:** https://github.com/CommunityToolkit/Windows -- **License:** MIT -- **Used as:** - - Embedded JSON snapshot of toolkit scenarios in - `src/tools/winui-search/Data/toolkit-scenarios.json` and - `src/tools/winui-search/Data/toolkit-tags.json`. - - Live fetch target for `src/tools/winui-search/ToolkitFetcher.cs`, - which downloads sample C#/XAML on demand from `main`. - -``` -MIT License - -Copyright (c) .NET Foundation and Contributors. -All Rights Reserved. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -``` - ---- - ## NuGet runtime dependencies The C# tools under `src/tools/` reference the following NuGet packages. diff --git a/cgmanifest.json b/cgmanifest.json index bae406c7..ae30de04 100644 --- a/cgmanifest.json +++ b/cgmanifest.json @@ -2,30 +2,6 @@ "$schema": "https://json.schemastore.org/component-detection-manifest.json", "version": 1, "registrations": [ - { - "component": { - "type": "git", - "git": { - "repositoryUrl": "https://github.com/microsoft/WinUI-Gallery", - "commitHash": "HEAD" - } - }, - "developmentDependency": false, - "license": "MIT", - "_comment": "Source of embedded JSON snapshots in src/tools/winui-search/Data/gallery-*.json and runtime fetch target for GalleryFetcher.cs. Owned by the same WinUI team." - }, - { - "component": { - "type": "git", - "git": { - "repositoryUrl": "https://github.com/CommunityToolkit/Windows", - "commitHash": "HEAD" - } - }, - "developmentDependency": false, - "license": "MIT", - "_comment": "Source of embedded JSON snapshots in src/tools/winui-search/Data/toolkit-*.json and runtime fetch target for ToolkitFetcher.cs." - }, { "component": { "type": "nuget", diff --git a/plugins/winui/agent-plugin/com.github.copilot/agents/winui-dev.agent.md b/plugins/winui/agent-plugin/com.github.copilot/agents/winui-dev.agent.md index 2bdf5984..512c4a44 100644 --- a/plugins/winui/agent-plugin/com.github.copilot/agents/winui-dev.agent.md +++ b/plugins/winui/agent-plugin/com.github.copilot/agents/winui-dev.agent.md @@ -14,8 +14,8 @@ You build WinUI 3 desktop apps following this process: understand requirements Before continuing -1. Load the `winui-dev-workflow` skill — it has `BuildAndRun.ps1` for building and running your app -2. Load the `winui-design` skill — it has Fluent Design rules, control selection, XAML correctness, and theming guidance, **and it bundles `winui-search.exe` for grounded control lookup against the WinUI Gallery, Community Toolkit, and Reactor catalogue** +1. Load the `winui-dev-workflow` skill — it uses WinApp CLI 0.6+ for scaffolding and project-mode build/run, with `BuildAndRun.ps1` adding the bundled analyzer +2. Load the `winui-design` skill — it has Fluent Design rules, control selection, XAML correctness, theming guidance, and grounded `winapp find-ui` sample lookup ## Best Practices diff --git a/plugins/winui/agent-plugin/skills/winui-code-review/SKILL.md b/plugins/winui/agent-plugin/skills/winui-code-review/SKILL.md index 9c10520c..ead3dcb8 100644 --- a/plugins/winui/agent-plugin/skills/winui-code-review/SKILL.md +++ b/plugins/winui/agent-plugin/skills/winui-code-review/SKILL.md @@ -9,7 +9,7 @@ Run a code review **after the app builds and before committing**. This catches q ### How to Review -Read through the project's XAML and C# files and check each section below. The `Microsoft.WindowsAppSDK.Analyzers` Roslyn analyzer ships with the `winui-dev-workflow` skill and is injected into your build when you compile via the `BuildAndRun.ps1` script that ships with that skill — the script drops a temporary `Directory.Build.props` into the project that loads the analyzer DLL and its `.targets`, then cleans up after the build. Plain `dotnet build` (or VS) does **not** load the analyzer automatically; if you want it to surface as build diagnostics outside the script, add the `` and `` to your project's own `Directory.Build.props` (or wait for the planned NuGet package). +Read through the project's XAML and C# files and check each section below. The `Microsoft.WindowsAppSDK.Analyzers` Roslyn analyzer ships with the `winui-dev-workflow` skill and is injected when `BuildAndRun.ps1` calls project-mode `winapp run`. The wrapper supplies a temporary file through the environment-backed MSBuild `CustomAfterDirectoryBuildProps` hook, preserving SDK composition and each project's normal `Directory.Build.props` discovery (including referenced projects), then restores the environment and removes the temporary file. Plain `winapp run`, `dotnet build`, and Visual Studio do **not** load the analyzer automatically; to enable it outside the wrapper, add the `` and `` entries to the project's own `Directory.Build.props` (or wait for the planned NuGet package). The analyzer catches a curated set of WinUI 3 / Windows App SDK issues with categorized 4-digit IDs: diff --git a/plugins/winui/agent-plugin/skills/winui-design/SKILL.md b/plugins/winui/agent-plugin/skills/winui-design/SKILL.md index 16be5252..ffe08050 100644 --- a/plugins/winui/agent-plugin/skills/winui-design/SKILL.md +++ b/plugins/winui/agent-plugin/skills/winui-design/SKILL.md @@ -1,22 +1,23 @@ --- name: winui-design -description: "Use when designing, reviewing, or fixing WinUI 3: layout planning, control choice, Fluent Design alignment, Light/Dark/High Contrast theming, typography, spacing, brushes, accessibility, and XAML data-binding design. Load before authoring new XAML, reviewing UI PRs, migrating desktop UI to WinUI, or choosing between WinUI controls/patterns." +description: "Use when designing, reviewing, or fixing WinUI 3: sample and control discovery with winapp find-ui, layout planning, control choice, Fluent Design alignment, Light/Dark/High Contrast theming, typography, spacing, brushes, accessibility, and XAML data-binding design. Load before authoring new XAML, reviewing UI PRs, migrating desktop UI to WinUI, or choosing between WinUI controls/patterns. Also use when asked to search WinUI samples, find a WinUI Gallery or Community Toolkit example, or find a control that does something." --- ## Search samples before writing XAML -This skill ships `winui-search.exe` alongside this `SKILL.md` (≈100 WinUI Gallery controls, every Windows Community Toolkit scenario, 90+ Reactor declarative-C# controls, curated platform-integration patterns; each result returns full code — XAML + C#, or C#-only for Reactor — plus pitfall notes). **Front-load lookups, then code** — don't interleave. +WinApp CLI 0.6+ provides grounded control and sample discovery through `winapp find-ui`. **Front-load lookups, then code**: ```powershell -.\winui-search.exe search "" "" ... # batch one focused query per feature (BM25 likes focused phrasing) -.\winui-search.exe get ... # batch up to 3 IDs — full XAML + C# + pitfall notes -.\winui-search.exe list # browse all patterns (heavy — prefer search) -.\winui-search.exe update # force cache refresh +winapp find-ui "" # compact matches + scenario IDs +winapp find-ui --id # full XAML/C# + prerequisite notes +winapp find-ui --id --id --json # batch, structured output +winapp find-ui --list # browse all default-source scenarios +winapp find-ui "" --refresh # force a corpus refresh ``` -Search covers controls **and** platform integration (file pickers, Share, JumpList, drag-drop, app lifecycle, dialogs) — front-load all lookups before writing XAML; **don't interleave** search with coding. +Default search covers the WinUI Gallery, Windows Community Toolkit, and curated core patterns. Reactor's C#-only/MVU samples are opt-in with `--source reactor`; use them only for Reactor projects. The Gallery/Toolkit/Reactor corpus is fetched and cached by WinApp CLI, while core patterns work offline. ## App-shape anchors @@ -40,7 +41,7 @@ Before writing XAML, map the requirement to a platform control. These mappings e - **Input:** Text → `TextBox`; number → `NumberBox`; search → `AutoSuggestBox`; date → `CalendarDatePicker`; boolean → `ToggleSwitch`; pick one from 2–3 → `RadioButtons`; pick one from 4+ → `ComboBox`. - **Feedback:** Blocking decision → `ContentDialog`; contextual action → `Flyout` / `MenuFlyout`; onboarding / hint → `TeachingTip`; inline status / async progress → `InfoBar`; system notification → `AppNotification`. -If the mapping above doesn't fit, search `winui-search.exe` before improvising. +If the mapping above doesn't fit, run `winapp find-ui ""` before improvising. ## Window sizing (WinUI 3 specifics) diff --git a/plugins/winui/agent-plugin/skills/winui-design/references/brushes-and-icons.md b/plugins/winui/agent-plugin/skills/winui-design/references/brushes-and-icons.md index a45eb059..cc433dcd 100644 --- a/plugins/winui/agent-plugin/skills/winui-design/references/brushes-and-icons.md +++ b/plugins/winui/agent-plugin/skills/winui-design/references/brushes-and-icons.md @@ -4,7 +4,7 @@ Load this when looking up a specific brush key by purpose, deciding between WinU Sources: [XAML theme resources](https://learn.microsoft.com/en-us/windows/apps/develop/platform/xaml/xaml-theme-resources), [Icons for Windows apps](https://learn.microsoft.com/en-us/windows/apps/design/style/icons), [Segoe Fluent Icons font](https://learn.microsoft.com/en-us/windows/apps/design/style/segoe-fluent-icons-font), `IconElement` / `IconSource` API references on Microsoft Learn. -For runnable samples (full XAML + C# with the right `Glyph` codepoints, brush keys in context, etc.) prefer `winui-search.exe search ""`. +For runnable samples (full XAML + C# with the right `Glyph` codepoints, brush keys in context, etc.) prefer `winapp find-ui ""`, then fetch the best scenario with `winapp find-ui --id `. --- @@ -159,7 +159,7 @@ FontIcon with Segoe Fluent Icons: The `SymbolThemeFontFamily` theme resource is the canonical font reference — it resolves to Segoe Fluent Icons on Windows 11 and falls back to Segoe MDL2 Assets on Windows 10. Never hard-code the font family. -Glyph codepoint lookup: use the [Segoe Fluent Icons font page](https://learn.microsoft.com/en-us/windows/apps/design/style/segoe-fluent-icons-font) for the canonical table, or pull a worked sample with `winui-search.exe search "icon button"`. +Glyph codepoint lookup: use the [Segoe Fluent Icons font page](https://learn.microsoft.com/en-us/windows/apps/design/style/segoe-fluent-icons-font) for the canonical table, or pull a worked sample with `winapp find-ui "icon button"`. ### When icon-only is OK diff --git a/plugins/winui/agent-plugin/skills/winui-design/winui-search.exe b/plugins/winui/agent-plugin/skills/winui-design/winui-search.exe deleted file mode 100644 index 29b1af71..00000000 Binary files a/plugins/winui/agent-plugin/skills/winui-design/winui-search.exe and /dev/null differ diff --git a/plugins/winui/agent-plugin/skills/winui-dev-workflow/BuildAndRun.ps1 b/plugins/winui/agent-plugin/skills/winui-dev-workflow/BuildAndRun.ps1 index 18baa8ca..5ced9d6c 100644 --- a/plugins/winui/agent-plugin/skills/winui-dev-workflow/BuildAndRun.ps1 +++ b/plugins/winui/agent-plugin/skills/winui-dev-workflow/BuildAndRun.ps1 @@ -1,333 +1,178 @@ <# .SYNOPSIS -Builds and optionally runs a WinUI 3 / .NET project. +Runs a WinUI 3 project with WinApp CLI 0.6+ and the bundled analyzer. .DESCRIPTION -One command to build and run: .\BuildAndRun.ps1 MyApp.csproj +WinApp CLI owns input resolution, restore, build, architecture selection, +output discovery, runtime setup, package registration, and launch. This thin +wrapper forwards its arguments unchanged, injects +Microsoft.WindowsAppSDK.Analyzers through MSBuild, and enables +--debug-output by default for attached runs. -- Checks Developer Mode is enabled (required for packaged WinUI apps) -- Auto-detects platform (x64/ARM64), defaults to Debug, auto-restores -- Builds with dotnet build by default; pass -UseMSBuild to build with Visual Studio's MSBuild instead -- After successful build, finds the output folder and runs with winapp run -- Pass -SkipRun to build without launching -- Pass -Symbols to add --symbols (optional Symbol Server fallback for non-WinUI native frames) +Use WinApp's `--args ""` form for application arguments; PowerShell +consumes an unquoted `--` delimiter when it invokes another PowerShell script. .EXAMPLE -.\BuildAndRun.ps1 MyApp.csproj # Build + run -.\BuildAndRun.ps1 MyApp.csproj -SkipRun # Build only -.\BuildAndRun.ps1 MyApp.csproj -UseMSBuild # Build with Visual Studio MSBuild instead of dotnet build -.\BuildAndRun.ps1 MyApp.csproj -Symbols # Build + run with --debug-output --symbols (optional Symbol Server fallback) -.\BuildAndRun.ps1 MyApp.csproj /p:Configuration=Release # Override config +.\BuildAndRun.ps1 +.\BuildAndRun.ps1 MyApp.csproj -c Release --arch arm64 +.\BuildAndRun.ps1 . --detach --json +.\BuildAndRun.ps1 . --symbols #> -param( - [Parameter(Position = 0)] - [string]$Project, - [switch]$SkipRun, - [switch]$Detach, - [switch]$UseMSBuild, - [switch]$Symbols, - [Parameter(ValueFromRemainingArguments)] - [string[]]$ExtraArgs -) - $ErrorActionPreference = 'Stop' +$minimumWinAppVersion = [version]'0.6.0' +$arguments = @($args) -# Accept --detach (CLI style) as an alias for -Detach (PS style) -if ($ExtraArgs -contains '--detach') { - $Detach = $true - $ExtraArgs = $ExtraArgs | Where-Object { $_ -ne '--detach' } +$winapp = Get-Command winapp -ErrorAction SilentlyContinue +if (-not $winapp) { + Write-Error "WinApp CLI 0.6 or later is required. Run /winui-setup, then retry." + exit 1 } -# Accept --use-msbuild (CLI style) as an alias for -UseMSBuild (PS style) -if ($ExtraArgs -contains '--use-msbuild') { - $UseMSBuild = $true - $ExtraArgs = $ExtraArgs | Where-Object { $_ -ne '--use-msbuild' } +$installedWinAppVersion = $null +foreach ($line in @(& winapp --version 2>$null)) { + $match = [regex]::Match( + [string]$line, + '^\s*v?(?\d+\.\d+\.\d+)(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?\s*$' + ) + if ($match.Success) { + $installedWinAppVersion = [version]$match.Groups['version'].Value + } } - -# Accept --symbols (CLI style) as an alias for -Symbols (PS style) -if ($ExtraArgs -contains '--symbols') { - $Symbols = $true - $ExtraArgs = $ExtraArgs | Where-Object { $_ -ne '--symbols' } +if (-not $installedWinAppVersion) { + Write-Error "Could not determine the WinApp CLI version. Run /winui-setup, then retry." + exit 1 } - -# Extra args are MSBuild-style flags like /p:Platform=x64 -$extraArgs = $ExtraArgs - -# -- 0. Check Developer Mode -- -$devMode = $false -try { - $regPath = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock" - if (Test-Path $regPath) { - $val = Get-ItemProperty $regPath -Name AllowDevelopmentWithoutDevLicense -ErrorAction SilentlyContinue - if ($val.AllowDevelopmentWithoutDevLicense -eq 1) { $devMode = $true } - } -} catch {} - -if (-not $devMode) { - Write-Host "ERROR: Developer Mode is not enabled." -ForegroundColor Red - Write-Host "WinUI 3 packaged apps require Developer Mode to deploy and run." -ForegroundColor Red - Write-Host "Enable it: Settings > System > For developers > Developer Mode" -ForegroundColor Yellow +if ($installedWinAppVersion -lt $minimumWinAppVersion) { + Write-Error "WinApp CLI $minimumWinAppVersion or later is required; found $installedWinAppVersion. Run /winui-setup to upgrade." exit 1 } -# -- 1. Find the .csproj if not specified -- -if (-not $Project) { - $csprojFiles = Get-ChildItem -Path . -Filter "*.csproj" -Depth 0 - if ($csprojFiles.Count -eq 1) { - $Project = $csprojFiles[0].Name - } elseif ($csprojFiles.Count -gt 1) { - Write-Error "Multiple .csproj files found. Specify which one: .\BuildAndRun.ps1 .csproj" - exit 1 - } else { - Write-Error "No .csproj file found in current directory." - exit 1 - } +$analyzerDir = Join-Path $PSScriptRoot 'analyzer' +$analyzerDll = Join-Path $analyzerDir 'Microsoft.WindowsAppSDK.Analyzers.dll' +$analyzerTargets = Join-Path $analyzerDir 'Microsoft.WindowsAppSDK.Analyzers.targets' +if (-not (Test-Path -LiteralPath $analyzerDll -PathType Leaf) -or + -not (Test-Path -LiteralPath $analyzerTargets -PathType Leaf)) { + Write-Error "The bundled WinUI analyzer payload is incomplete. Reinstall the winui plugin." + exit 1 } -# -- 2. Auto-detect platform -- -$detectedPlatform = if ($env:PROCESSOR_ARCHITECTURE -eq "ARM64") { "ARM64" } else { "x64" } -$detectedConfig = "Debug" - -$hasPlatform = $extraArgs | Where-Object { $_ -match "^[/|-]p:Platform=" } -$hasConfig = $extraArgs | Where-Object { $_ -match "^[/|-]p:Configuration=" } -$hasRestore = $extraArgs | Where-Object { $_ -match "^[/|-]restore$|^[/|-]t:restore$|^--restore$" } - -# Extract actual values if overridden -if ($hasPlatform -and $hasPlatform -match "Platform=(\w+)") { $detectedPlatform = $Matches[1] } -if ($hasConfig -and $hasConfig -match "Configuration=(\w+)") { $detectedConfig = $Matches[1] } - -$autoArgs = @() -if (-not $hasPlatform) { $autoArgs += "/p:Platform=$detectedPlatform" } -if (-not $hasConfig) { $autoArgs += "/p:Configuration=$detectedConfig" } -if (-not $hasRestore) { $autoArgs += "/restore" } - -# -- 3. Find build tool -- -# dotnet build is the default. Current Windows App SDK releases (>= 2.1.3 on the -# 2.x line, >= 1.8 on the 1.x line) surface XAML compiler errors under dotnet -# build, so MSBuild is only used when explicitly requested via -UseMSBuild. -$msbuild = $null - -if ($UseMSBuild) { - $vswhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" - if (Test-Path $vswhere) { - $vsPath = & $vswhere -latest -requires Microsoft.Component.MSBuild -property installationPath 2>$null - if ($vsPath) { - $candidate = Join-Path $vsPath "MSBuild\Current\Bin\MSBuild.exe" - if (Test-Path $candidate) { $msbuild = $candidate } - } +$valueOptions = @( + '--manifest', '--output-appx-directory', '--args', '--exe', '--executable', + '-c', '--configuration', '--arch', '-r', '--runtime', '-f', '--framework', + '-p', '--property', '--project' +) +$debugSpecified = $false +$jsonOutput = $false +$noLaunch = $false +$detach = $false + +function Resolve-BooleanOption { + param( + [System.Text.RegularExpressions.Match]$Match, + [ref]$Index, + [object[]]$Tokens + ) + + if ($Match.Groups['value'].Success) { + return $Match.Groups['value'].Value -ieq 'true' } - if (-not $msbuild) { - Write-Host "--> -UseMSBuild requested but Visual Studio MSBuild was not found; using dotnet build." -ForegroundColor Yellow + if ($Index.Value + 1 -lt $Tokens.Count -and + [string]$Tokens[$Index.Value + 1] -match '^(?i:true|false)$') { + $Index.Value++ + return [string]$Tokens[$Index.Value] -ieq 'true' } + return $true } -# -- 4. Build -- -$defaultArgs = @("/nologo") -$hasVerbosity = $extraArgs | Where-Object { $_ -match "^[/|-]v(erbosity)?:" } -if (-not $hasVerbosity) { $defaultArgs += "/v:m" } +for ($i = 0; $i -lt $arguments.Count; $i++) { + $token = [string]$arguments[$i] -# -- 4a. Inject Microsoft.WindowsAppSDK.Analyzers if available -- -$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path -# Look for pre-built analyzer DLL in the skill folder first, then fall back to source tree -$analyzerDll = Join-Path $scriptDir "analyzer\Microsoft.WindowsAppSDK.Analyzers.dll" -$analyzerTargets = Join-Path $scriptDir "analyzer\Microsoft.WindowsAppSDK.Analyzers.targets" -if (-not (Test-Path $analyzerDll)) { - $analyzerDll = Join-Path $scriptDir "..\..\tools\winui-analyzer\Microsoft.WindowsAppSDK.Analyzers\bin\Release\netstandard2.0\Microsoft.WindowsAppSDK.Analyzers.dll" - $analyzerTargets = Join-Path $scriptDir "..\..\tools\winui-analyzer\Microsoft.WindowsAppSDK.Analyzers\Microsoft.WindowsAppSDK.Analyzers.targets" -} + if ($token -eq '--') { + Write-Error 'PowerShell consumes an unquoted -- delimiter for script calls. Pass application arguments with --args "".' + exit 1 + } -$analyzerArgs = @() -$tempBuildProps = $null -if (Test-Path $analyzerDll) { - $analyzerDll = (Resolve-Path $analyzerDll).Path - $analyzerTargets = (Resolve-Path $analyzerTargets).Path + if ($valueOptions -icontains $token) { + if ($i + 1 -lt $arguments.Count) { + $value = [string]$arguments[++$i] + if ($token -in '-p', '--property' -and + $value -match '(?i)^CustomAfterDirectoryBuildProps\s*=') { + Write-Error "CustomAfterDirectoryBuildProps is reserved for loading the bundled WinUI analyzer." + exit 1 + } + } + continue + } - # Inject via temporary Directory.Build.props (works with both MSBuild and dotnet build) - $projectDir = Split-Path (Resolve-Path $Project) -Parent - if (-not $projectDir) { $projectDir = "." } - $tempBuildProps = Join-Path $projectDir "Directory.Build.props" - $existingProps = $null + if ($token -match '(?i)^(?:-p|--property)[:=](?.*)$') { + if ($Matches['value'] -match '(?i)^CustomAfterDirectoryBuildProps\s*=') { + Write-Error "CustomAfterDirectoryBuildProps is reserved for loading the bundled WinUI analyzer." + exit 1 + } + continue + } - if (Test-Path $tempBuildProps) { - $existingProps = Get-Content $tempBuildProps -Raw + $booleanMatch = [regex]::Match($token, '(?i)^--debug-output(?:=(?true|false))?$') + if ($booleanMatch.Success) { + $debugSpecified = $true + [void](Resolve-BooleanOption -Match $booleanMatch -Index ([ref]$i) -Tokens $arguments) + continue } + $booleanMatch = [regex]::Match($token, '(?i)^--json(?:=(?true|false))?$') + if ($booleanMatch.Success) { + $jsonOutput = Resolve-BooleanOption -Match $booleanMatch -Index ([ref]$i) -Tokens $arguments + continue + } + $booleanMatch = [regex]::Match($token, '(?i)^--no-launch(?:=(?true|false))?$') + if ($booleanMatch.Success) { + $noLaunch = Resolve-BooleanOption -Match $booleanMatch -Index ([ref]$i) -Tokens $arguments + continue + } + $booleanMatch = [regex]::Match($token, '(?i)^--detach(?:=(?true|false))?$') + if ($booleanMatch.Success) { + $detach = Resolve-BooleanOption -Match $booleanMatch -Index ([ref]$i) -Tokens $arguments + } +} - # Only create if one doesn't already exist (don't overwrite user's file) - if (-not $existingProps) { - @" +$tempBuildProps = Join-Path ([System.IO.Path]::GetTempPath()) "winui-build-$([guid]::NewGuid().ToString('N')).props" +$escapedAnalyzerDll = [System.Security.SecurityElement]::Escape((Resolve-Path -LiteralPath $analyzerDll).Path) +$escapedAnalyzerTargets = [System.Security.SecurityElement]::Escape((Resolve-Path -LiteralPath $analyzerTargets).Path) +$propsContent = @" - + - + -"@ | Set-Content $tempBuildProps - Write-Host "--> Microsoft.WindowsAppSDK.Analyzers: enabled" -ForegroundColor DarkGray - } else { - $tempBuildProps = $null # Don't clean up a pre-existing file - Write-Host "--> Microsoft.WindowsAppSDK.Analyzers: skipped (existing Directory.Build.props)" -ForegroundColor DarkGray - } +"@ + +$runArgs = $arguments +if (-not $debugSpecified -and -not $jsonOutput -and -not $noLaunch -and -not $detach) { + $runArgs += '--debug-output' } -Write-Host "" +$runExitCode = 1 +$previousCustomAfterProps = $env:CustomAfterDirectoryBuildProps try { - if ($msbuild) { - Write-Host "--> Building with MSBuild (Platform: $detectedPlatform, Config: $detectedConfig)" -ForegroundColor Cyan - Write-Host "--> MSBuild: $msbuild" -ForegroundColor DarkGray - $allArgs = $defaultArgs + $autoArgs + @($Project) + $extraArgs - & $msbuild $allArgs - $buildExit = $LASTEXITCODE + Set-Content -LiteralPath $tempBuildProps -Value $propsContent -Encoding utf8 + # Microsoft.Common.props accepts a semicolon-delimited import list; the .NET SDK + # composes its own UseArtifactsOutputPath.props hook the same way. + $env:CustomAfterDirectoryBuildProps = if ($previousCustomAfterProps) { + "$previousCustomAfterProps;$tempBuildProps" } else { - Write-Host "--> Building with dotnet build (Platform: $detectedPlatform, Config: $detectedConfig)" -ForegroundColor Cyan - $dotnetArgs = @($Project) - foreach ($a in ($autoArgs + $extraArgs)) { - if ($a -match "^[/|-]restore$|^[/|-]t:restore$") { - # dotnet build restores by default - } elseif ($a -match "^[/|-]p:(.+)$") { - $dotnetArgs += "-p:$($Matches[1])" - } elseif ($a -notmatch "\.(csproj|sln)$") { - $dotnetArgs += $a - } - } - & dotnet build @dotnetArgs - $buildExit = $LASTEXITCODE + $tempBuildProps } + & winapp run @runArgs + $runExitCode = $LASTEXITCODE } finally { - # Always clean up the temp Directory.Build.props we created — even on - # Ctrl-C, throws, or unexpected exits. Otherwise the user's project - # gets a stray file pointing at our analyzer that subsequent vanilla - # `dotnet build` invocations will fail to resolve. - if ($tempBuildProps -and (Test-Path $tempBuildProps)) { - Remove-Item $tempBuildProps -Force -ErrorAction SilentlyContinue - } -} - -if ($buildExit -ne 0) { - Write-Host "" - Write-Host "BUILD FAILED (exit code $buildExit)" -ForegroundColor Red - exit $buildExit -} - -Write-Host "" -Write-Host "BUILD SUCCEEDED" -ForegroundColor Green - -# -- 5. Run with winapp -- -if ($SkipRun) { - Write-Host "--> Skipping run (-SkipRun)" -ForegroundColor DarkGray - exit 0 -} - -# Find the build output directory -$rid = $detectedPlatform.ToLower() -$projectDir = Split-Path (Resolve-Path $Project) -Parent -if (-not $projectDir) { $projectDir = "." } - -# Search for the output folder pattern: bin\\\\win-\ -$binDir = Join-Path $projectDir "bin\$detectedPlatform\$detectedConfig" -if (-not (Test-Path $binDir)) { - Write-Host "WARNING: Build output not found at $binDir -- skipping run" -ForegroundColor Yellow - exit 0 -} - -# Find the TFM folder (e.g., net10.0-windows10.0.26100.0) -$tfmDirs = Get-ChildItem $binDir -Directory | Where-Object { $_.Name -match "^net\d" } -if (-not $tfmDirs) { - Write-Host "WARNING: No TFM folder found in $binDir -- skipping run" -ForegroundColor Yellow - exit 0 -} - -$tfmDir = $tfmDirs | Sort-Object Name -Descending | Select-Object -First 1 -$outputDir = Join-Path $tfmDir.FullName "win-$rid" -if (-not (Test-Path $outputDir)) { - # Try without RID subfolder - $outputDir = $tfmDir.FullName -} - -# Check winapp is available -$winapp = Get-Command winapp -ErrorAction SilentlyContinue -if (-not $winapp) { - Write-Host "WARNING: winapp CLI not found in PATH -- skipping run" -ForegroundColor Yellow - Write-Host "Build output at: $outputDir" - exit 0 -} - -# MAX_PATH guard. winapp builds the loose layout at \AppX and package -# registration reads every file in it, so a deep build-output path -# (bin/////...) can push individual payload files past the -# 260-character limit even when $outputDir itself is comfortably under it. The failure -# surfaces from the WinRT PackageManager as an opaque HRESULT -- 0x80073CF9, or "Failed -# to reach state Staged", or a "Manifest file not found" against the staged copy -- -# none of which name the real cause. -# -# Measure the tree that is already on disk rather than guessing from $outputDir's -# length: the longest path the layout will hold is \AppX\. Skip an AppX folder left by a previous run so its prefix isn't counted -# twice. -$maxPath = 260 -$layoutPrefix = 'AppX\' -$existingLayout = (Join-Path $outputDir 'AppX') + '\' -$outputDirLen = $outputDir.TrimEnd('\').Length -$deepestRelative = 0 -foreach ($file in (Get-ChildItem $outputDir -Recurse -File -ErrorAction SilentlyContinue)) { - if ($file.FullName.StartsWith($existingLayout, [System.StringComparison]::OrdinalIgnoreCase)) { continue } - $relativeLen = $file.FullName.Length - $outputDirLen - 1 - if ($relativeLen -gt $deepestRelative) { $deepestRelative = $relativeLen } -} -$projectedLen = $outputDirLen + 1 + $layoutPrefix.Length + $deepestRelative - -$appxOutDir = $null -if ($projectedLen -ge $maxPath) { - # Key the staging folder on $outputDir, which already encodes the project path, - # platform, configuration, TFM and RID. That preserves the per-variant isolation - # the default \AppX location gave us: two projects that happen to share - # a name -- or the Debug and Release builds of one project -- must not overwrite - # each other's registered payload. - $appName = [System.IO.Path]::GetFileNameWithoutExtension($Project) - if (-not $appName) { $appName = "App" } - $sha = [System.Security.Cryptography.SHA256]::Create() - try { - $keyBytes = $sha.ComputeHash([System.Text.Encoding]::UTF8.GetBytes($outputDir.ToLowerInvariant())) - } finally { - $sha.Dispose() - } - $key = -join ($keyBytes[0..3] | ForEach-Object { $_.ToString('x2') }) - - # LOCALAPPDATA rather than TEMP: the registered package holds a live reference to - # this folder for as long as the app is deployed, so it has to survive temp-file - # cleanup. It is also shorter than %TEMP%, which helps rather than hurts here. - $appxOutDir = Join-Path $env:LOCALAPPDATA "winapp-layout\$appName-$key" - - Write-Host "--> Layout would reach $projectedLen chars (limit $maxPath); staging the AppX layout to" -ForegroundColor Yellow - Write-Host " $appxOutDir instead." -ForegroundColor Yellow - - if (($appxOutDir.Length + 1 + $deepestRelative) -ge $maxPath) { - Write-Host "WARNING: even that path exceeds MAX_PATH. Move the project closer to the drive root." -ForegroundColor Red - } - - # New-Item -Force leaves an existing directory's contents alone, so purge first: a - # payload file dropped since the last build (a removed PackageReference, a TFM or - # architecture switch) would otherwise linger in a live-registered layout. - if (Test-Path -LiteralPath $appxOutDir) { - Get-ChildItem -LiteralPath $appxOutDir -Force | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue + if ($null -eq $previousCustomAfterProps) { + Remove-Item Env:\CustomAfterDirectoryBuildProps -ErrorAction SilentlyContinue + } else { + $env:CustomAfterDirectoryBuildProps = $previousCustomAfterProps } - New-Item -ItemType Directory -Path $appxOutDir -Force | Out-Null + Remove-Item -LiteralPath $tempBuildProps -Force -ErrorAction SilentlyContinue } -Write-Host "" -if ($Detach) { - $runArgs = @($outputDir, '--detach', '--json') - if ($appxOutDir) { $runArgs += @('--output-appx-directory', $appxOutDir) } - Write-Host "--> Launching app in background..." -ForegroundColor Cyan - & winapp run @runArgs -} else { - $runArgs = @($outputDir, '--debug-output') - if ($Symbols) { $runArgs += '--symbols' } - if ($appxOutDir) { $runArgs += @('--output-appx-directory', $appxOutDir) } - Write-Host "--> Launching app: winapp run $($runArgs -join ' ')" -ForegroundColor Cyan - Write-Host " The script will stay running while the app is open." -ForegroundColor DarkGray - Write-Host " Debug output and exceptions will appear below." -ForegroundColor DarkGray - Write-Host "" - & winapp run @runArgs -} \ No newline at end of file +exit $runExitCode diff --git a/plugins/winui/agent-plugin/skills/winui-dev-workflow/SKILL.md b/plugins/winui/agent-plugin/skills/winui-dev-workflow/SKILL.md index d9ae09db..bf745f0a 100644 --- a/plugins/winui/agent-plugin/skills/winui-dev-workflow/SKILL.md +++ b/plugins/winui/agent-plugin/skills/winui-dev-workflow/SKILL.md @@ -1,16 +1,16 @@ --- name: winui-dev-workflow -description: "Build and run workflow for WinUI 3 apps — project creation, BuildAndRun.ps1 script, winapp run, error diagnosis, and prerequisites. Use when building, running, or fixing build errors in a WinUI 3 project." +description: "Build and run workflow for WinUI 3 apps with WinApp CLI 0.6+ — project creation with winapp new, project-mode winapp run, BuildAndRun.ps1 analyzer integration, crash diagnosis, and prerequisites. Use when creating, building, running, or fixing build errors in a WinUI 3 project." --- ### Create or Open a Project -**New app** — scaffold with a template: +**New app** — let WinApp CLI install/update the official templates and scaffold: ```powershell -dotnet new winui-mvvm -n +winapp new --name --template winui-mvvm --template-version latest --use-defaults cd ``` -Creates an MVVM project with CommunityToolkit.Mvvm, TitleBar, MicaBackdrop, and Frame navigation. Do NOT `mkdir` first — `-n` creates the folder. +Run `winapp new --list` to discover the currently installed template short names. Do not install the template pack separately and do not create the output directory first. **Existing app** — read the `.csproj` to understand: - `` (e.g., `net10.0-windows10.0.26100.0`) @@ -26,42 +26,49 @@ Never specify `--version` — omitting it gets the latest stable and avoids outd ### Build & Run -Use the `BuildAndRun.ps1` script (included with this skill) — it handles everything: +WinApp CLI 0.6+ builds a `.csproj` and launches it directly: ```powershell -.\BuildAndRun.ps1 +winapp run . --debug-output +winapp run .\MyApp.csproj -c Release --arch arm64 ``` -**Invoke the script with `mode: "async"`.** The script stays attached to the running app so a `mode: "sync"` call blocks your turn for the entire lifetime of the app. The output contains the PID of the running app once the app starts, which looks like this: -``` -✅ launched (PID: 12345) +For normal development, prefer the included `BuildAndRun.ps1` wrapper. It invokes project-mode `winapp run`, injects the bundled `Microsoft.WindowsAppSDK.Analyzers`, and turns on `--debug-output` by default: + +```powershell +.\BuildAndRun.ps1 ``` -What the script does automatically: -1. Checks Developer Mode is enabled (fails fast if not) -2. Finds the `.csproj` in the current directory -3. Auto-detects platform (x64 or ARM64) -4. Builds with `dotnet build` (or Visual Studio MSBuild if you pass `-UseMSBuild`) -5. Finds the build output folder -6. Launches with `winapp run --debug-output` +**Invoke attached runs with `mode: "async"`.** The command stays attached while the app is open, so a synchronous call blocks for the app's lifetime. The output contains the running app's PID. -**Options:** -```powershell -.\BuildAndRun.ps1 # auto-find csproj, build, run (should use async invocation) -.\BuildAndRun.ps1 MyApp.csproj # explicit project -.\BuildAndRun.ps1 -Detach # run in detached mode, no debug output or exceptions (safe to use mode: "sync") -.\BuildAndRun.ps1 -SkipRun # build only (safe to use mode: "sync") -.\BuildAndRun.ps1 -Symbols # build + run, adding --symbols (optional Symbol Server fallback) -.\BuildAndRun.ps1 /p:Configuration=Release # override defaults +The wrapper only adds repository-specific analyzer and debug defaults. WinApp CLI handles: +1. Project restore and build +2. Configuration, architecture, runtime, and framework selection +3. Packaged versus unpackaged detection +4. Build-output and executable discovery +5. Windows App Runtime setup +6. Package registration and launch + +**Options and forwarded WinApp arguments:** ``` +.\BuildAndRun.ps1 # one top-level csproj; attached diagnostics +.\BuildAndRun.ps1 .\MyApp.csproj # explicit project +.\BuildAndRun.ps1 .\MyApp.csproj -c Release # forwarded to winapp run +.\BuildAndRun.ps1 .\MyApp.csproj --arch arm64 # forwarded to winapp run +.\BuildAndRun.ps1 . --detach --json # return after launch; emit PID as JSON +.\BuildAndRun.ps1 . --symbols # add Symbol Server-backed native symbols +.\BuildAndRun.ps1 --args "--flag value" # pass application arguments +``` + +The wrapper accepts the same `.csproj`, `.sln`/`.slnx`, directory, and `--project` inputs as `winapp run`. -**If build fails:** Read ALL errors, batch-fix them in one pass, then run `BuildAndRun.ps1` again. +**If build fails:** Read all errors, batch-fix them in one pass, then rerun the same command. **If the app crashes on launch:** `read_powershell` the shell — first-chance exceptions appear in the output. See the crash-diagnosis section below for WinUI stowed-exception triage. ### Diagnosing Crashes with `winapp run` -For WinUI apps, `--debug-output` (the `BuildAndRun.ps1` default) runs a **stowed-exception triage** on crash, surfacing the real WinUI/XAML error behind an opaque `0x8000FFFF` / `E_FAIL` — plus a fully symbolicated native dispatch stack (symbols auto-download, so `--debug-output` alone is enough). The **first** crash also downloads debugger components and can take a few minutes — it looks like a hang but it's caching; point `WINAPP_DBGTOOLS_DIR` at an existing *Debugging Tools for Windows* install to skip it. Later runs use the cache. +For WinUI apps, `--debug-output` (the wrapper default) runs a **stowed-exception triage** on crash, surfacing the real WinUI/XAML error behind an opaque `0x8000FFFF` / `E_FAIL`. The first crash downloads debugger components and can take a few minutes; point `WINAPP_DBGTOOLS_DIR` at an existing *Debugging Tools for Windows* install for offline/locked-down environments. Add `--symbols` for richer native frames. ### Common Errors @@ -69,15 +76,16 @@ For WinUI apps, `--debug-output` (the `BuildAndRun.ps1` default) runs a **stowed |-------|-----| | Developer Mode not enabled | Settings → System → For developers → On | | CS0234/CS0246 missing type | Add `using` or `dotnet add package` | -| NETSDK1136 platform required | BuildAndRun.ps1 handles this automatically | +| NETSDK1136 platform required | Target a Windows TFM (for example `net10.0-windows10.0.26100.0`); use `-f ` when the project already multi-targets | | XLS0414 XAML type not found | Add `xmlns` declaration | | XDG0062 binding path missing | Check `x:Bind` property exists on ViewModel | | Blank window after launch | `x:Bind` defaults to `OneTime` — add `Mode=OneWay` | | App silently exits | Use `winapp run`, never run the .exe directly | -| App crashes with opaque `0x8000FFFF` / `E_FAIL` | Run under `--debug-output` (BuildAndRun.ps1 default) — WinUI stowed-exception triage surfaces the real XAML error + symbolicated native stack. `-Symbols` optional, not required | +| App crashes with opaque `0x8000FFFF` / `E_FAIL` | Run under `--debug-output` (BuildAndRun.ps1 default) — WinUI stowed-exception triage surfaces the real XAML error + symbolicated native stack. `--symbols` is optional | | XAML compiler crashes silently | Remove any `PresentationCore.dll` / `System.Windows` references | | MSB3073 / `XamlCompiler.exe ... exited with code 1`, no `.xaml` named | Old WindowsAppSDK XAML-compiler bug — update `Microsoft.WindowsAppSDK` NuGet to latest (≥ 2.1.3, or ≥ 1.8 on the 1.x line) | -| 0x80073CF6 package install failed | Run `winapp init`, check manifest publisher matches cert | +| 0x80073CF6 package install failed | Check the manifest publisher and Developer Mode; apps from `winapp new` need no separate `winapp init` | +| 0x80073CF9 / "Failed to reach state Staged" on a deeply nested project | For a packaged app, rerun with `--output-appx-directory "$env:LOCALAPPDATA\winapp-layout\--"`, or move the repo closer to the drive root. Keep the directory unique per configuration and architecture — a registered development package holds a live reference to it, so Debug and Release must not share one — and empty it before reuse so payload files dropped since the last build do not linger | | 0x8007000B bad image format | Wrong platform target — use x64 or ARM64, not AnyCPU | ### Prerequisites @@ -86,19 +94,18 @@ For WinUI apps, `--debug-output` (the `BuildAndRun.ps1` default) runs a **stowed |-------------|---------|------------------------------|-----------------| | Windows 10 v1903+ | — | — | — | | Developer Mode | enabled | enabled | Settings → Advanced → Developer Mode → On | -| .NET SDK | 8.0 | 10.0 | `winget install Microsoft.DotNet.SDK.10` | -| winapp CLI | 0.3 | latest | `winget install Microsoft.WinAppCLI` | -| WinUI templates | any | latest | `dotnet new install Microsoft.WindowsAppSDK.WinUI.CSharp.Templates` | +| .NET SDK | 8.0.100 | 10.0 | `winget install Microsoft.DotNet.SDK.10` | +| WinApp CLI | 0.6.0 | latest | `/winui-setup` | -If any of these are missing when you try to access them — `winapp` or `dotnet` not recognized, the WinUI templates aren't installed, Developer Mode is off — **do not try to install them yourself and do not try to work around it**. Stop and tell the user the prerequisite is missing and ask them to run `/winui-setup` (a user-invoked skill that installs and verifies everything). Once they've finished, retry the failed command. +If `winapp`/`dotnet` is missing or too old, or Developer Mode is off, **do not install it ad hoc or work around it**. Ask the user to run `/winui-setup`, then retry. `winapp new` manages the WinUI template pack itself. ### Critical Rules -- ❌ NEVER run the packaged .exe directly — always use `winapp run` or `BuildAndRun.ps1` +- ❌ NEVER run the packaged .exe directly — always use project-mode `winapp run` or `BuildAndRun.ps1` - ❌ NEVER add `None` to work around launch issues - ❌ NEVER delete `Package.appxmanifest` - ❌ NEVER use `AnyCPU` — always x64 or ARM64 ### References -- `BuildAndRun.ps1` — included with this skill, handles build + run automatically +- `BuildAndRun.ps1` — included with this skill; adds the bundled analyzer and diagnostic defaults to `winapp run` diff --git a/plugins/winui/agent-plugin/skills/winui-packaging/SKILL.md b/plugins/winui/agent-plugin/skills/winui-packaging/SKILL.md index 5aa403b7..6832b53c 100644 --- a/plugins/winui/agent-plugin/skills/winui-packaging/SKILL.md +++ b/plugins/winui/agent-plugin/skills/winui-packaging/SKILL.md @@ -7,7 +7,7 @@ description: "MSIX packaging, code signing, and distribution for WinUI 3 apps | Task | Command | |------|---------| -| Build for release | `.\BuildAndRun.ps1 /p:Configuration=Release` | +| Build for release | `.\BuildAndRun.ps1 . -c Release --arch x64 --no-launch` | | Package + sign | `winapp package --cert devcert.pfx` | | Generate + sign + package | `winapp package --generate-cert --install-cert` | | Generate dev certificate | `winapp cert generate` | @@ -18,12 +18,14 @@ description: "MSIX packaging, code signing, and distribution for WinUI 3 apps ### End-to-End Workflow #### Step 1: Build for Release -Use the BuildAndRun.ps1 script from the `winui-dev-workflow` skill to build your app in Release configuration without launching it: +Build the project in Release configuration without launching it. Use the `BuildAndRun.ps1` wrapper from the `winui-dev-workflow` skill — plain `dotnet build` does **not** load the bundled `Microsoft.WindowsAppSDK.Analyzers`, so release builds would ship without the analyzer gate that development builds get: ```powershell -.\BuildAndRun.ps1 /p:Configuration=Release -SkipRun +.\BuildAndRun.ps1 . -c Release --arch x64 --no-launch ``` +`--no-launch` builds and registers a development package without starting the app. Run `winapp unregister` before installing the signed `.msix` in Step 5, so the development registration does not conflict with the packaged identity. + #### Step 2: Generate Certificate (one-time) ```powershell winapp cert generate --manifest . @@ -90,6 +92,7 @@ jobs: ``` **CI/CD tips:** +- Use plain `dotnet build` on the runner, not `BuildAndRun.ps1` — the wrapper registers a development package and needs the plugin's local analyzer payload, neither of which belongs in CI. Enforce analyzer coverage on the dev machine instead. - Use `--quiet` for clean output - Use `--if-exists skip` with `cert generate` to avoid failures on re-runs - Store production PFX as a repository secret diff --git a/plugins/winui/agent-plugin/skills/winui-session-report/Analyze-Session.ps1 b/plugins/winui/agent-plugin/skills/winui-session-report/Analyze-Session.ps1 index c3a1425c..9759c1b5 100644 --- a/plugins/winui/agent-plugin/skills/winui-session-report/Analyze-Session.ps1 +++ b/plugins/winui/agent-plugin/skills/winui-session-report/Analyze-Session.ps1 @@ -287,17 +287,51 @@ function Get-ErrorSummary { return @{ HasError = $true; Summary = ($errSummary | Select-Object -Unique) } } +function Test-NoBuildEnabled { + param([string]$Command) + + $match = [regex]::Match( + $Command, + '(?i)(?:^|\s)--no-build(?:=(?true|false)|\s+(?true|false))?(?=\s|$)' + ) + if (-not $match.Success) { return $false } + + $value = if ($match.Groups['inline'].Success) { + $match.Groups['inline'].Value + } elseif ($match.Groups['spaced'].Success) { + $match.Groups['spaced'].Value + } else { + 'true' + } + return $value -ieq 'true' +} + +function Test-BuildCapableCommand { + param([string]$Command) + + if ($Command -match '\bdotnet build\b|\bmsbuild\b') { + return $true + } + if ($Command -match 'BuildAndRun|\bwinapp run\b') { + return -not (Test-NoBuildEnabled -Command $Command) + } + return $false +} + function Get-TurnCategory { param($Turn) $toolNames = $Turn.Tools | ForEach-Object { $_.Name } $hasSkill = $Turn.SkillInvocations.Count -gt 0 $shellCmd = { param($t) ($t.Name -in 'powershell', 'shell') } - $hasBuild = $Turn.Tools | Where-Object { (& $shellCmd $_) -and ($_.Args.command -match 'dotnet build|MSBuild|BuildAndRun|msbuild') } - $hasRun = $Turn.Tools | Where-Object { (& $shellCmd $_) -and ($_.Args.command -match 'winapp run|BuildAndRun(?!.*-SkipRun)') } + $hasBuild = $Turn.Tools | Where-Object { + if (-not (& $shellCmd $_)) { return $false } + return Test-BuildCapableCommand -Command $_.Args.command + } + $hasRun = $Turn.Tools | Where-Object { (& $shellCmd $_) -and ($_.Args.command -match 'winapp run|BuildAndRun') } $hasGit = $Turn.Tools | Where-Object { (& $shellCmd $_) -and ($_.Args.command -match '\bgit\b') } $hasBuildError = $Turn.Tools | Where-Object { $_.HasError -and (& $shellCmd $_) } - $hasScaffold = $Turn.Tools | Where-Object { $_.Args.command -match 'dotnet new|New-Item.*Directory' } + $hasScaffold = $Turn.Tools | Where-Object { $_.Args.command -match 'winapp new|dotnet new|New-Item.*Directory' } $isDiagnosing = $Turn.Tools | Where-Object { (& $shellCmd $_) -and ($_.Args.command -match 'XamlCompiler|output\.json|input\.json|-v d\b|-v:d|-verbosity|Select-String.*error|obj\\|temp_output|Remove-Item.*obj|Get-Content.*log|Get-Process') } @@ -764,33 +798,45 @@ if ($includeSubagents) { foreach ($sa in $parsed.Subagents) { $allTurns += $sa.Turns } } -$buildAttempts = ($allTurns | Where-Object { $_.Category -in 'build-ok', 'build-fix' }).Count -$buildSuccesses = ($allTurns | Where-Object { $_.Category -eq 'build-ok' }).Count -$buildFailures = ($allTurns | Where-Object { $_.Category -eq 'build-fix' }).Count +$buildAttemptTurns = @($allTurns | Where-Object { + $_.Tools | Where-Object { + if ($_.Name -notin 'powershell', 'shell') { return $false } + return Test-BuildCapableCommand -Command $_.Args.command + } +}) +$buildFailureTurns = @($buildAttemptTurns | Where-Object { + $_.Tools | Where-Object { + if (-not $_.HasError -or $_.Name -notin 'powershell', 'shell') { return $false } + return Test-BuildCapableCommand -Command $_.Args.command + } +}) +$buildWorkflowAttempts = $buildAttemptTurns.Count +$buildWorkflowFailures = $buildFailureTurns.Count +$buildWorkflowSuccesses = $buildWorkflowAttempts - $buildWorkflowFailures $buildErrors = @() foreach ($t in $allTurns) { foreach ($tool in $t.Tools) { - if ($tool.HasError -and $tool.Name -in 'powershell', 'shell' -and $tool.Args.command -match '\bdotnet build\b|\bmsbuild\b|BuildAndRun\.ps1|BuildAndRun ' -and $tool.ErrorSummary.Count -gt 0) { + if ($tool.HasError -and $tool.Name -in 'powershell', 'shell' -and $tool.Args.command -match '\bdotnet build\b|\bmsbuild\b|BuildAndRun\.ps1|BuildAndRun |\bwinapp run\b' -and $tool.ErrorSummary.Count -gt 0) { $buildErrors += @{ Turn = $t.TurnNum; Errors = $tool.ErrorSummary } } } } -$buildAndRunUsed = $allTurns | Where-Object { - $_.Tools | Where-Object { $_.Name -in 'powershell', 'shell' -and $_.Args.command -match 'BuildAndRun' } +$winappWorkflows = $allTurns | Where-Object { + $_.Tools | Where-Object { $_.Name -in 'powershell', 'shell' -and $_.Args.command -match 'BuildAndRun|\bwinapp run\b' } } $rawDotnetBuilds = $allTurns | Where-Object { $_.Tools | Where-Object { $_.Name -in 'powershell', 'shell' -and $_.Args.command -match 'dotnet build' -and $_.Args.command -notmatch 'BuildAndRun' } } -if ($buildAndRunUsed -and -not $rawDotnetBuilds) { - $buildScriptStatus = "Used BuildAndRun.ps1 for all builds" -} elseif ($buildAndRunUsed -and $rawDotnetBuilds) { - $buildScriptStatus = "Mixed: raw 'dotnet build' $($rawDotnetBuilds.Count)x, BuildAndRun.ps1 $($buildAndRunUsed.Count)x" +if ($winappWorkflows -and -not $rawDotnetBuilds) { + $projectBuildStatus = "Used winapp run / BuildAndRun.ps1 workflows" +} elseif ($winappWorkflows -and $rawDotnetBuilds) { + $projectBuildStatus = "Mixed: raw 'dotnet build' $($rawDotnetBuilds.Count)x, winapp run / BuildAndRun.ps1 $($winappWorkflows.Count)x" } elseif ($rawDotnetBuilds) { - $buildScriptStatus = "NOT USED: raw 'dotnet build' $($rawDotnetBuilds.Count)x, never used BuildAndRun.ps1" + $projectBuildStatus = "Raw 'dotnet build' used $($rawDotnetBuilds.Count)x; no winapp run / BuildAndRun.ps1 detected" } else { - $buildScriptStatus = "No build commands detected" + $projectBuildStatus = "No build commands detected" } $skillTimeline = @() @@ -853,13 +899,6 @@ if ($objCleans -ge 2) { } $toolingIssues = @() -if ($rawDotnetBuilds -and $rawDotnetBuilds.Count -gt 0) { - $toolingIssues += @{ - Area = "BuildAndRun.ps1" - Issue = $buildScriptStatus - Suggestion = "Agent should use BuildAndRun.ps1 for builds - it includes the Roslyn analyzer, auto-detects platform, and handles common errors." - } -} if ($buildErrors | Where-Object { $_.Errors -match 'MSB3073' }) { $toolingIssues += @{ Area = "XAML Compiler" @@ -868,7 +907,7 @@ if ($buildErrors | Where-Object { $_.Errors -match 'MSB3073' }) { } } $devWorkflowEntry = $skillTimeline | Where-Object { $_.Skill -match 'winui-dev-workflow' } | Select-Object -First 1 -$firstBuildTurn = ($allTurns | Where-Object { $_.Category -in 'build-ok', 'build-fix' } | Select-Object -First 1).TurnNum +$firstBuildTurn = ($buildAttemptTurns | Select-Object -First 1).TurnNum if ($devWorkflowEntry -and $rawDotnetBuilds -and $devWorkflowEntry.Turn -gt $firstBuildTurn) { $toolingIssues += @{ Area = "Skill timing" @@ -974,11 +1013,11 @@ if ($includeSubagents) { $md += "## Build Analysis" $md += "" -$md += "- **Attempts:** $buildAttempts ($buildSuccesses success, $buildFailures failed)" -$md += "- **BuildAndRun.ps1:** $buildScriptStatus" +$md += "- **Build-capable workflow attempts:** $buildWorkflowAttempts ($buildWorkflowSuccesses completed without a command error, $buildWorkflowFailures command failures)" +$md += "- **Project build workflow:** $projectBuildStatus" $md += "" if ($buildErrors.Count -gt 0) { - $md += "**Build errors encountered:**" + $md += "**Build/run command errors encountered:**" $md += "" foreach ($be in $buildErrors) { $md += "Turn $($be.Turn):" diff --git a/plugins/winui/agent-plugin/skills/winui-session-report/SKILL.md b/plugins/winui/agent-plugin/skills/winui-session-report/SKILL.md index aa2f5aa5..8e39f27c 100644 --- a/plugins/winui/agent-plugin/skills/winui-session-report/SKILL.md +++ b/plugins/winui/agent-plugin/skills/winui-session-report/SKILL.md @@ -54,7 +54,7 @@ Detection rules: 2. **Review the generated report** — read `session-report.md` and summarize key findings for the user: - How many turns, how long, token usage - What skills were loaded and when - - Build success/failure pattern + - Build/run workflow and command-failure pattern - Any stuck patterns or tooling issues detected 3. **Add your own observations** — append a section to the report with any additional context: @@ -64,7 +64,7 @@ Detection rules: 4. Include any tooling improvements or recommendations based on the analysis. - Are there rules that need to be added to the Roslyn analyzer to prevent common mistakes detected during the session? - - Were there bugs or issues with winapp run or the BuildAndRun.ps1 script? + - Were there bugs or issues with `winapp new`, project-mode `winapp run`, `winapp find-ui`, or the BuildAndRun.ps1 wrapper? - Are there features that could be added to lower the number of turns required to complete a task? ### What the Report Covers @@ -76,7 +76,7 @@ Detection rules: | Turn Breakdown | Turns and tokens by category (building, coding, exploring, subagent dispatch, etc.) | | Skills | Which were invoked and when, including from inside subagent transcripts | | Subagents | (Claude Code only) Per-agent breakdown of dispatched subagents and their work | -| Build Analysis | Build attempts, failures, errors, whether BuildAndRun.ps1 was used | +| Build Analysis | Build-capable workflow attempts, command failures/errors, and whether project-mode winapp run / BuildAndRun.ps1 was used | | Stuck Patterns | Build loops, repeated file reads, obj/ clean cycles | | Tooling Issues | Auto-detected improvement opportunities | | Turn Detail | Every turn with tools used and errors flagged, parent and subagent transcripts shown separately | diff --git a/plugins/winui/agent-plugin/skills/winui-setup/SKILL.md b/plugins/winui/agent-plugin/skills/winui-setup/SKILL.md index bd979a24..d9853366 100644 --- a/plugins/winui/agent-plugin/skills/winui-setup/SKILL.md +++ b/plugins/winui/agent-plugin/skills/winui-setup/SKILL.md @@ -1,137 +1,132 @@ --- name: winui-setup -description: "Install and verify the prerequisites the win-dev-skills WinUI 3 toolchain depends on — .NET SDK 10, the WinApp CLI, the WinUI 3 .NET templates, and Developer Mode. Use only when the user explicitly asks to set up or repair the toolchain. Do not invoke automatically when another skill reports a missing prerequisite; tell the user what is missing and ask them to invoke this skill." +description: "Install and verify the prerequisites the win-dev-skills WinUI 3 toolchain depends on — .NET SDK 8.0.100+, WinApp CLI 0.6+, and Developer Mode. Use only when the user explicitly asks to set up or repair the toolchain. Do not invoke automatically when another skill reports a missing prerequisite; tell the user what is missing and ask them to invoke this skill." --- ### Purpose -Install and verify the prerequisites every other `winui-*` skill assumes are already present on the machine. +Install and verify the prerequisites every other `winui-*` skill assumes. WinApp CLI 0.6 owns WinUI template discovery and installation through `winapp new`; **do not install the template pack separately**. > [!IMPORTANT] > Run this skill only when the user explicitly asks to set up or repair the toolchain. If it is loaded without an explicit request, do not run checks or installations; explain what the skill changes and wait for confirmation. -This skill is **idempotent** — every step checks first, skips if already satisfied, prints `[OK] already installed` and moves on. Re-running on a fully set-up machine is a fast no-op. +This skill is idempotent: detect everything first, install or upgrade only what is needed, and print one final summary. ### Steps -The first thing to do is **batch all detection up front** — run every check in parallel/together so you can show the user the full picture before installing anything. Then install only what's missing. - #### Detect everything -Run all of these together; collect the results: +Run these checks together so the user sees the full state before anything changes: ```powershell -# .NET SDK — accept any installed SDK >= 8.0 -$dotnetSdks = (& dotnet --list-sdks 2>$null) -replace ' \[.*$','' -$dotnetOk = $dotnetSdks | ForEach-Object { [version]($_ -split '-')[0] } | - Where-Object { $_.Major -ge 8 } | Select-Object -First 1 - -# WinApp CLI — needs to be present AND >= 0.3 +$minimumDotNet = [version]'8.0.100' +$minimumWinApp = [version]'0.6.0' + +# .NET SDK — project-mode winapp run requires SDK 8.0.100+ +$dotnetSdks = @(& dotnet --list-sdks 2>$null) | ForEach-Object { + $text = ($_ -replace ' \[.*$','').Trim() + $parsed = $null + if ([version]::TryParse(($text -split '-')[0], [ref]$parsed)) { $parsed } +} +$dotnetVersion = $dotnetSdks | + Where-Object { $_ -ge $minimumDotNet } | + Sort-Object -Descending | + Select-Object -First 1 +$dotnetOk = $null -ne $dotnetVersion + +# WinApp CLI — require 0.6+ for winapp new, find-ui, and project-mode run +$winappCmd = Get-Command winapp -ErrorAction SilentlyContinue $winappVersion = $null -$winappOk = $false -$winappCmd = Get-Command winapp -ErrorAction SilentlyContinue if ($winappCmd) { - $raw = (& winapp --version 2>$null) -as [string] - if ($raw) { - $base = ($raw -split '-')[0] # strip "-prerelease.N" if present - try { - $winappVersion = [version]$base - $winappOk = $winappVersion -ge [version]'0.3' - } catch {} + foreach ($line in @(& winapp --version 2>$null)) { + $match = [regex]::Match( + [string]$line, + '^\s*v?(?\d+\.\d+\.\d+)(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?\s*$' + ) + if ($match.Success) { + $parsed = $null + if ([version]::TryParse($match.Groups['version'].Value, [ref]$parsed)) { + $winappVersion = $parsed + } + } } } - -# WinUI 3 templates -$templatesOk = [bool](dotnet new list winui 2>$null | Select-String 'winui-mvvm' -Quiet) +$winappOk = $winappVersion -ge $minimumWinApp # Developer Mode $devModeOk = ((Get-ItemProperty ` - -Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock' ` - -Name AllowDevelopmentWithoutDevLicense -ErrorAction SilentlyContinue + -Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock' ` + -Name AllowDevelopmentWithoutDevLicense -ErrorAction SilentlyContinue ).AllowDevelopmentWithoutDevLicense) -eq 1 ``` -Print a one-shot status table so the user sees what you're about to do: +Print a one-shot status table: +```text +.NET SDK >= 8.0.100 [OK] found 10.0.100 +WinApp CLI >= 0.6.0 [!] found 0.5.1 — will upgrade +Developer Mode [X] disabled — needs admin to enable ``` -.NET SDK ≥ 8 ✅ found 10.0.100 (or ❌ missing — will install Microsoft.DotNet.SDK.10) -WinApp CLI ⚠ found 0.3.1 — will upgrade to latest - (or ❌ missing/too old — will install Microsoft.WinAppCLI) -WinUI 3 templates ✅ found — will reinstall to make sure they're at latest -Developer Mode ❌ disabled — needs admin to enable -``` - -> **Always upgrade WinApp CLI and the WinUI templates** even when they're already present — they ship breaking changes between releases and the rest of the `winui-*` skills assume latest. The minimum bar is "WinApp CLI ≥ 0.3 and templates installed at all"; the goal is "both at latest". #### Install what's missing -Skip anything already-OK from detection. The remaining steps: +##### .NET SDK -##### .NET SDK (only if no SDK ≥ 8.0 was found) +Only when no SDK at or above `8.0.100` was found: ```powershell winget install --id Microsoft.DotNet.SDK.10 --exact --silent --accept-package-agreements --accept-source-agreements ``` -`.NET 8.0` is the floor. If the user already has 8.0, 9.0, or 10.0 installed (any patch), the requirement is met — do not install another SDK side-by-side. +Do not install another SDK when 8.0.100+, 9.x, or 10.x is already present. -##### WinApp CLI — install if missing/old, then always upgrade +##### WinApp CLI -If `$winappOk` is false (missing or `< 0.3`), install it. Then **always** run `winget upgrade` regardless, so even already-present installs get bumped to latest: +If `winapp` is missing, install it. If it is present but below 0.6.0, try to upgrade it. Skip both commands when the installed version already meets the minimum: ```powershell -# Install only if missing or too old -winget install --id Microsoft.WinAppCLI --exact --silent --accept-package-agreements --accept-source-agreements +# When winapp is missing +winget install --id Microsoft.WinAppCli --exact --silent --accept-package-agreements --accept-source-agreements -# Always — upgrade to latest (no-op if already at latest) -winget upgrade --id Microsoft.WinAppCLI --exact --silent --accept-package-agreements --accept-source-agreements +# When winapp is present but older than 0.6.0 +winget upgrade --id Microsoft.WinAppCli --exact --silent --accept-package-agreements --accept-source-agreements ``` -##### Refresh `$env:Path` - -If you installed the .NET SDK or anything else via winget in this session, **refresh PATH** so subsequent steps can find the new tools. Without this, `dotnet new install` will fail with "command not found" even though the SDK is on disk: +Refresh PATH after any winget install or upgrade: ```powershell -$env:Path = [Environment]::GetEnvironmentVariable('Path','Machine') + ';' + [Environment]::GetEnvironmentVariable('Path','User') +$env:Path = [Environment]::GetEnvironmentVariable('Path','Machine') + ';' + + [Environment]::GetEnvironmentVariable('Path','User') ``` -##### WinUI 3 .NET templates — always reinstall to get latest +Run the version detection again. If the result is still below `0.6.0`, report the actual version and mark setup failed; do not continue with old command fallbacks. -Run this every time, whether or not `$templatesOk` was true. `dotnet new install` against an already-installed template package upgrades it in place to the latest version: +> `winapp new` installs the official `Microsoft.WindowsAppSDK.WinUI.CSharp.Templates` pack on demand and can update it with `--template-version latest`. Do not run `dotnet new install` during setup. -```powershell -dotnet new install Microsoft.WindowsAppSDK.WinUI.CSharp.Templates -``` - -##### Developer Mode (ask the user first!) +##### Developer Mode (ask first) -Developer Mode is the DWORD `AllowDevelopmentWithoutDevLicense` under `HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock`. Setting it requires admin, which means a UAC prompt will pop up. **Do not just trigger UAC out of nowhere — ask the user first** so they're not surprised by the elevation prompt. Use language like: - -> Developer Mode is currently disabled. Enabling it requires a one-time admin elevation (a UAC prompt will appear). Would you like me to enable it now? (yes / no / I'll do it later) - -Only if the user agrees, re-elevate **only this step** via UAC: +Developer Mode requires admin elevation. **Ask the user before triggering UAC.** Only if they agree, elevate this one operation: ```powershell Start-Process powershell -Verb RunAs -ArgumentList @( - '-NoProfile','-Command', - "New-Item -Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock' -Force | Out-Null; " + - "Set-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock' " + - "-Name AllowDevelopmentWithoutDevLicense -Type DWord -Value 1" + '-NoProfile','-Command', + "New-Item -Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock' -Force | Out-Null; " + + "Set-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock' " + + "-Name AllowDevelopmentWithoutDevLicense -Type DWord -Value 1" ) -Wait ``` -If the user declines (either says no, or accepts but then dismisses the UAC prompt), do not abort the whole skill. Print the literal command above so they can run it later from an elevated PowerShell, and continue to the summary. +If the user declines or dismisses UAC, continue to the summary and print the command for later use. -### Final summary — always print this +### Final summary -After everything, print a single-table summary so the user knows exactly what changed: +Always print a single summary: -``` +```text ==== winui-setup summary ==== -.NET SDK ≥ 8 ⏭ already present (9.0.313) -WinApp CLI ✅ upgraded to 0.4.0 (or ✅ installed, ⏭ already at latest, ❌ failed) -WinUI 3 templates ✅ updated to latest -Developer Mode ✅ enabled (or ⏭ skipped — user declined, or ❌ failed: ) +.NET SDK >= 8.0.100 [>] already present (10.0.100) +WinApp CLI >= 0.6.0 [OK] upgraded to 0.6.0 +Developer Mode [OK] enabled ``` You're ready. If the current harness exposes the `winui-dev` orchestrator agent, @@ -145,10 +140,11 @@ For GitHub Copilot CLI, for example: ### Things to NOT do -- ❌ **Do not install Visual Studio.** It is not required — these skills build and run with the dotnet and winapp clis. -- ❌ **Do not install or upgrade the user's AI coding harness** as part of this skill. `winui-setup` manages Windows/WinUI development prerequisites only. -- ❌ **Do not elevate the entire session** — only step 5 needs admin. Elevating earlier steps would install winget packages into the admin user's profile instead of the user's, which is wrong. -- ❌ **Do not skip the PATH refresh** — agents that skip it install the SDK and then immediately fail on `dotnet new install`. -- ❌ **Do not trigger UAC for Developer Mode without asking the user first** — the prompt is jarring if it pops up unannounced. Always confirm before elevating. -- ❌ **Do not silently retry on failure.** If a `winget install` fails (no network, package source down, permissions), record the error in the summary table and move on. Let the user see what failed. -- ❌ **Do not install .NET 10 if the machine already has any .NET SDK ≥ 8.0** — the floor is 8.0, and adding another SDK side-by-side wastes disk space. +- Do not install Visual Studio; these skills build and run with `dotnet` and `winapp`. +- Do not install or upgrade the user's AI coding harness; this skill manages Windows/WinUI development prerequisites only. +- Do not install the WinUI template pack separately; `winapp new` owns it in 0.6+. +- Do not elevate the entire session; only the Developer Mode registry write needs admin. +- Do not skip the PATH refresh after a winget install or upgrade. +- Do not trigger UAC without asking the user first. +- Do not silently retry failed installs or accept WinApp CLI below 0.6.0. +- Do not install .NET 10 when any SDK at or above 8.0.100 is already available. diff --git a/plugins/winui/agent-plugin/skills/winui-wpf-migration/SKILL.md b/plugins/winui/agent-plugin/skills/winui-wpf-migration/SKILL.md index 2aae60e6..0769b87c 100644 --- a/plugins/winui/agent-plugin/skills/winui-wpf-migration/SKILL.md +++ b/plugins/winui/agent-plugin/skills/winui-wpf-migration/SKILL.md @@ -15,7 +15,7 @@ List: WPF controls used, custom MVVM framework, imaging APIs, threading patterns #### Step 2: Create WinUI 3 Project and Align Namespaces ```powershell -dotnet new winui-mvvm -n +winapp new --name --template winui-mvvm --template-version latest --use-defaults ``` Immediately set `` in `.csproj` to match the WPF namespace. Update `x:Class` in `App.xaml`, `MainWindow.xaml` and their code-behind files. Build to verify before porting any code. @@ -90,6 +90,6 @@ Select-String -Path (Get-ChildItem -Recurse -Filter "*.cs" | Where-Object { $_.F # Verify packaging preserved Test-Path "Package.appxmanifest" # should be True -# Build and run +# Build and run with the bundled analyzer .\BuildAndRun.ps1 ``` diff --git a/plugins/winui/agents/winui-dev.agent.md b/plugins/winui/agents/winui-dev.agent.md index cef8c980..9ed9baf8 100644 --- a/plugins/winui/agents/winui-dev.agent.md +++ b/plugins/winui/agents/winui-dev.agent.md @@ -14,8 +14,8 @@ You build WinUI 3 desktop apps following this process: understand requirements Before continuing -1. Load the `winui-dev-workflow` skill — it has `BuildAndRun.ps1` for building and running your app -2. Load the `winui-design` skill — it has Fluent Design rules, control selection, XAML correctness, and theming guidance, **and it bundles `winui-search.exe` for grounded control lookup against the WinUI Gallery, Community Toolkit, and Reactor catalogue** +1. Load the `winui-dev-workflow` skill — it uses WinApp CLI 0.6+ for scaffolding and project-mode build/run, with `BuildAndRun.ps1` adding the bundled analyzer +2. Load the `winui-design` skill — it has Fluent Design rules, control selection, XAML correctness, theming guidance, and grounded `winapp find-ui` sample lookup ## Best Practices diff --git a/scripts/build-tools.ps1 b/scripts/build-tools.ps1 index 2c69d427..fba3a45e 100644 --- a/scripts/build-tools.ps1 +++ b/scripts/build-tools.ps1 @@ -6,14 +6,13 @@ .DESCRIPTION Builds and tests the WinUI 3 / Windows App SDK Roslyn analyzer, then - AOT-publishes winmd-cli and winui-search and refreshes the skill payload - folders that ship the resulting binaries. + AOT-publishes winmd-cli and refreshes the analyzer skill payload. This script exists to give contributors one verb to run before opening a PR. The pr-validation.yml workflow will rebuild everything in CI - anyway, but provenance checks (analyzer-provenance, analyzer-targets-sync, - winui-search-provenance) will fail fast on the PR if a committed payload - drifts from source — running this script keeps them in sync. + anyway, but provenance checks (analyzer-provenance and + analyzer-targets-sync) will fail fast on the PR if the committed payload + drifts from source — running this script keeps it in sync. .PARAMETER Configuration Build configuration. Defaults to Release. @@ -23,12 +22,12 @@ .PARAMETER SkipPayloadRefresh Don't copy the freshly built artifacts into the - plugins/winui/agent-plugin/skills/.../ payload folders. Default: payloads are - refreshed (this is what keeps CI provenance happy). + plugins/winui/agent-plugin/skills/.../ payload folder. Default: the payload + is refreshed (this is what keeps CI provenance happy). .EXAMPLE ./scripts/build-tools.ps1 - # Build + test everything in Release, AOT-publish exes, refresh payloads. + # Build + test everything in Release, AOT-publish winmd, refresh the analyzer payload. .EXAMPLE ./scripts/build-tools.ps1 -SkipTests -SkipPayloadRefresh @@ -57,7 +56,6 @@ function Warn([string]$msg) { Write-Host " [!] $msg" -ForegroundColor Yell $analyzerDir = Join-Path $repoRoot 'src/tools/winui-analyzer' $analyzerSlnx = Join-Path $analyzerDir 'Microsoft.WindowsAppSDK.Analyzers.slnx' -$analyzerProj = Join-Path $analyzerDir 'Microsoft.WindowsAppSDK.Analyzers/Microsoft.WindowsAppSDK.Analyzers.csproj' $analyzerTests = Join-Path $analyzerDir 'Microsoft.WindowsAppSDK.Analyzers.Tests/Microsoft.WindowsAppSDK.Analyzers.Tests.csproj' Step "Building analyzer ($Configuration)" @@ -94,33 +92,9 @@ dotnet publish $winmdProj -c $Configuration --nologo if ($LASTEXITCODE -ne 0) { throw "winmd-cli build failed" } Ok "winmd-cli built" -# -------------------- 3. winui-search --------------------------------------- - -$searchProj = Join-Path $repoRoot 'src/tools/winui-search/winui-search.csproj' -Step "Building winui-search ($Configuration)" -dotnet publish $searchProj -c $Configuration -r win-x64 --self-contained true /p:PublishAot=true /p:StripSymbols=true --nologo -if ($LASTEXITCODE -ne 0) { throw "winui-search build failed" } -Ok "winui-search built" - -if (-not $SkipPayloadRefresh) { - Step "Refreshing winui-search skill payload" - $searchPayloadDir = Join-Path $repoRoot 'plugins/winui/agent-plugin/skills/winui-design' - $publishedSearchExe = Join-Path $repoRoot "src/tools/winui-search/bin/$Configuration/net10.0/win-x64/publish/winui-search.exe" - if (-not (Test-Path $publishedSearchExe)) { - throw "Published winui-search.exe not found at: $publishedSearchExe" - } - Copy-Item $publishedSearchExe (Join-Path $searchPayloadDir 'winui-search.exe') -Force - Ok "payload refreshed: $searchPayloadDir/winui-search.exe" -} else { - Warn "skipping winui-search payload refresh (-SkipPayloadRefresh)" -} - # -------------------- Done -------------------------------------------------- Step "All tools built successfully" Write-Host " Analyzer payload: plugins/winui/agent-plugin/skills/winui-dev-workflow/analyzer/" -ForegroundColor DarkGray -Write-Host " AOT exes:" -ForegroundColor DarkGray -Write-Host " src/tools/winmd-cli/bin/$Configuration/net10.0//publish/winmd.exe" -ForegroundColor DarkGray -Write-Host " src/tools/winui-search/bin/$Configuration/net10.0//publish/winui-search.exe" -ForegroundColor DarkGray -Write-Host " Skill payloads:" -ForegroundColor DarkGray -Write-Host " plugins/winui/agent-plugin/skills/winui-design/winui-search.exe (refreshed)" -ForegroundColor DarkGray +Write-Host " AOT exe:" -ForegroundColor DarkGray +Write-Host " src/tools/winmd-cli/bin/$Configuration/net10.0//publish/winmd.exe" -ForegroundColor DarkGray diff --git a/src/tools/winui-analyzer/Directory.Build.props b/src/tools/winui-analyzer/Directory.Build.props index 20f98b4b..24d88ec4 100644 --- a/src/tools/winui-analyzer/Directory.Build.props +++ b/src/tools/winui-analyzer/Directory.Build.props @@ -2,7 +2,7 @@ Scoped to src/tools/winui-analyzer/ only. Sets warning-as-error and deterministic-build flags for the analyzer + tests; intentionally NOT placed at the repo root because TreatWarningsAsErrors would break - unrelated C# projects (winui-search, winmd-cli) that have their own + unrelated C# projects (such as winmd-cli) that have their own warning baselines. --> diff --git a/src/tools/winui-analyzer/README.md b/src/tools/winui-analyzer/README.md index 01950359..ef34431a 100644 --- a/src/tools/winui-analyzer/README.md +++ b/src/tools/winui-analyzer/README.md @@ -27,7 +27,7 @@ src/tools/winui-analyzer/ The `Directory.Build.props` and `global.json` are intentionally scoped to this subtree (not at repo root) so `TreatWarningsAsErrors=true` doesn't break -unrelated C# projects (`winui-search`, `winmd-cli`). +unrelated C# projects such as `winmd-cli`. ## Rule categories @@ -66,8 +66,8 @@ skill stays self-contained. For a one-shot rebuild + payload refresh, use the repo-root helper: ```powershell -# Builds analyzer + winmd-cli + winui-search and refreshes the analyzer skill -# payload in one step. Use this whenever you change analyzer source so the +# Builds the analyzer + winmd-cli and refreshes the analyzer skill payload in +# one step. Use this whenever you change analyzer source so the # pr-validation provenance check doesn't fail your PR. ./scripts/build-tools.ps1 ``` @@ -112,5 +112,4 @@ can never break someone's build by default — they have to opt into * Bump `` in the csproj only when publishing (see distribution section above). * Don't put `Directory.Build.props` at the repo root — it would force - `TreatWarningsAsErrors` onto `winui-search` / `winmd-cli` which aren't - ready for it. + `TreatWarningsAsErrors` onto `winmd-cli`, which has its own warning baseline. diff --git a/src/tools/winui-search/BM25.cs b/src/tools/winui-search/BM25.cs deleted file mode 100644 index 5e708f37..00000000 --- a/src/tools/winui-search/BM25.cs +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using System.Text.RegularExpressions; - -internal static partial class BM25 -{ - private const double K1 = 1.2; - private const double B = 0.75; - - internal sealed class Doc - { - public Dictionary Tf { get; } = new(); - public double Length { get; set; } - } - - internal sealed class Corpus - { - public Dictionary Df { get; } = new(); - public int N { get; set; } - public double AvgDl { get; set; } - } - - [GeneratedRegex(@"[^a-z0-9\s\-]")] - private static partial Regex NonAlphaRegex(); - - public static string[] Tokenize(string text) - { - return NonAlphaRegex().Replace(text.ToLowerInvariant(), " ") - .Split(' ', StringSplitOptions.RemoveEmptyEntries) - .Where(w => w.Length > 1 && !global::StopWords.Common.Contains(w)) - .ToArray(); - } - - public static Doc BuildDoc(params (string text, double weight)[] fields) - { - var doc = new Doc(); - foreach (var (text, weight) in fields) - { - foreach (var word in Tokenize(text)) - { - doc.Tf[word] = doc.Tf.GetValueOrDefault(word) + weight; - doc.Length += weight; - } - } - return doc; - } - - public static Corpus BuildCorpus(Doc[] docs) - { - var corpus = new Corpus { N = docs.Length }; - double totalLen = 0; - foreach (var doc in docs) - { - totalLen += doc.Length; - var seen = new HashSet(); - foreach (var word in doc.Tf.Keys) - { - if (seen.Add(word)) - corpus.Df[word] = corpus.Df.GetValueOrDefault(word) + 1; - } - } - corpus.AvgDl = totalLen / Math.Max(docs.Length, 1); - return corpus; - } - - public static double Score(Doc doc, string[] queryWords, Corpus corpus) - { - double score = 0; - foreach (var word in queryWords) - { - if (!doc.Tf.TryGetValue(word, out var tf) || tf == 0) continue; - var df = corpus.Df.GetValueOrDefault(word); - var idf = Math.Log((corpus.N - df + 0.5) / (df + 0.5) + 1); - var tfNorm = (tf * (K1 + 1)) / (tf + K1 * (1 - B + B * (doc.Length / corpus.AvgDl))); - score += idf * tfNorm; - } - return score; - } - - /// - /// Count how many of the given query tokens appear at least once in the doc. - /// Used by SearchEngine for the coverage gate (rejects results where most - /// query terms are OOV — e.g. "find replace text" matching only "text"). - /// - public static int CountHits(Doc doc, string[] queryTokens) - { - int hits = 0; - foreach (var word in queryTokens) - { - if (doc.Tf.TryGetValue(word, out var tf) && tf > 0) hits++; - } - return hits; - } -} diff --git a/src/tools/winui-search/BackgroundUpdater.cs b/src/tools/winui-search/BackgroundUpdater.cs deleted file mode 100644 index d1cff9d3..00000000 --- a/src/tools/winui-search/BackgroundUpdater.cs +++ /dev/null @@ -1,264 +0,0 @@ -using System.Diagnostics; - -/// -/// Stale-while-revalidate refresher for the on-disk cache under -/// %LOCALAPPDATA%\winui-search\cache\. -/// -/// Hot path commands (search/get/list/debug) call -/// after they've answered the user. If the cache hasn't been refreshed from -/// GitHub in , this spawns a detached child -/// winui-search update --background that runs the GitHub fetch and -/// updates the cache. The hot-path process returns immediately; the child -/// outlives it (Windows does not auto-kill children of an exiting parent). -/// -/// Concurrency safety: -/// - update.lock: atomic FileMode.CreateNew ensures only one -/// simultaneous spawn wins the race; others see -/// and skip silently. -/// - 10-minute TTL on the lock reaps orphans from crashed children. -/// - last-attempt.txt: rate-limits retry to 1 hour after a failed -/// attempt (otherwise a GitHub outage would re-spawn on every search). -/// -/// Disable per-process by setting WINUI_SEARCH_NO_BACKGROUND=1. -/// Enable trace logging to %LOCALAPPDATA%\winui-search\cache\background.log -/// by setting WINUI_SEARCH_DEBUG=1. -/// -internal static class BackgroundUpdater -{ - public const string BackgroundFlag = "--background"; - - private static readonly TimeSpan StaleThreshold = TimeSpan.FromDays(7); - private static readonly TimeSpan RetryAfterFailure = TimeSpan.FromHours(1); - private static readonly TimeSpan LockTtl = TimeSpan.FromMinutes(10); - - private static readonly string CacheRoot = Path.Combine( - Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), - "winui-search", "cache"); - - private static readonly string LockFile = Path.Combine(CacheRoot, "update.lock"); - private static readonly string LastSuccessFile = Path.Combine(CacheRoot, "last-github-update.txt"); - private static readonly string LastAttemptFile = Path.Combine(CacheRoot, "last-github-attempt.txt"); - - /// True if the current process was launched as a background updater child. - public static bool IsBackgroundInvocation(string[] args) => - args.Any(a => string.Equals(a, BackgroundFlag, StringComparison.Ordinal)); - - private static bool IsDisabled() => - IsTruthy(Environment.GetEnvironmentVariable("WINUI_SEARCH_NO_BACKGROUND")); - - /// - /// Treat 1, true, yes, on (case-insensitive) as enabled. - /// Anything else — including 0, false, empty, or unset — is disabled. - /// Matches the documented =1 contract and avoids the surprise of =0 - /// turning a flag on. - /// - private static bool IsTruthy(string? value) => - value is not null && - (value.Equals("1", StringComparison.Ordinal) || - value.Equals("true", StringComparison.OrdinalIgnoreCase) || - value.Equals("yes", StringComparison.OrdinalIgnoreCase) || - value.Equals("on", StringComparison.OrdinalIgnoreCase)); - - /// - /// Spawn a detached winui-search update --background if cache hasn't been - /// refreshed from GitHub in and no other update is - /// in flight or recently attempted. Returns immediately; the child runs detached. - /// Best-effort: any failure is swallowed so the hot path is never affected. - /// - public static void TryKickoffIfStale() - { - try - { - if (IsDisabled()) return; - - var lastSuccess = ReadTimestamp(LastSuccessFile); - if (lastSuccess.HasValue && DateTime.UtcNow - lastSuccess.Value < StaleThreshold) - return; // cache is fresh enough - - var lastAttempt = ReadTimestamp(LastAttemptFile); - if (lastAttempt.HasValue && DateTime.UtcNow - lastAttempt.Value < RetryAfterFailure) - return; // recent attempt — back off - - if (!TryAcquireLock()) return; - - // Lock acquired; spawn the child. The child clears the lock when done. - var exePath = Environment.ProcessPath; - if (string.IsNullOrEmpty(exePath)) - { - ReleaseLock(); - return; - } - - DebugLog($"Spawning child: {exePath} update {BackgroundFlag}"); - var psi = new ProcessStartInfo - { - FileName = exePath, - Arguments = $"update {BackgroundFlag}", - CreateNoWindow = true, - UseShellExecute = false, - WindowStyle = ProcessWindowStyle.Hidden, - // IMPORTANT: do NOT redirect stdio. With redirected pipes the parent - // implicitly waits for the child's stdout/stderr to close on exit, - // defeating the whole point of fire-and-forget. The child uses - // BackgroundFlag to stay silent on Console (writes only to its log file). - }; - - var child = Process.Start(psi); - if (child == null) - { - DebugLog("Process.Start returned null"); - ReleaseLock(); - return; - } - DebugLog($"Spawned child PID={child.Id}"); - // Dispose the Process handle immediately so the parent doesn't track the child. - child.Dispose(); - // Do NOT WaitForExit — child runs detached, parent returns now. - } - catch (Exception ex) - { - DebugLog($"TryKickoffIfStale failed: {ex.GetType().Name}: {ex.Message}"); - try { ReleaseLock(); } catch { /* ignore */ } - } - } - - /// Mark a successful GitHub refresh. Called by the background child after success. - public static void MarkSuccess() - { - try - { - Directory.CreateDirectory(CacheRoot); - var now = DateTime.UtcNow.ToString("o"); - File.WriteAllText(LastSuccessFile, now); - File.WriteAllText(LastAttemptFile, now); - DebugLog($"MarkSuccess @ {now}"); - } - catch { /* best-effort */ } - } - - /// Mark a failed GitHub refresh attempt for retry rate-limiting. - public static void MarkAttempt() - { - try - { - Directory.CreateDirectory(CacheRoot); - File.WriteAllText(LastAttemptFile, DateTime.UtcNow.ToString("o")); - DebugLog("MarkAttempt (failure)"); - } - catch { /* best-effort */ } - } - - /// Release the spawn lock. Called by the background child in finally. - public static void ReleaseLock() - { - try { if (File.Exists(LockFile)) File.Delete(LockFile); } catch { /* best-effort */ } - DebugLog("ReleaseLock"); - } - - private static readonly bool DebugEnabled = - IsTruthy(Environment.GetEnvironmentVariable("WINUI_SEARCH_DEBUG")); - - private static void DebugLog(string msg) - { - if (!DebugEnabled) return; - try - { - Directory.CreateDirectory(CacheRoot); - var line = $"[{DateTime.UtcNow:HH:mm:ss.fff}] PID={Environment.ProcessId} {msg}\n"; - File.AppendAllText(Path.Combine(CacheRoot, "background.log"), line); - } - catch { /* best-effort */ } - } - - /// Public surface for diagnostic logs from outside this class. - public static void DebugLogPublic(string msg) => DebugLog(msg); - - /// - /// Parse a round-trip ("o" format) timestamp from , returning a - /// UTC or null if the file is missing/unreadable/unparseable. - /// Uses + - /// so timezone (Z) info is preserved and parsing succeeds in every locale. - /// - public static DateTime? ReadTimestamp(string path) - { - try - { - if (!File.Exists(path)) return null; - var text = File.ReadAllText(path).Trim(); - if (DateTime.TryParse( - text, - System.Globalization.CultureInfo.InvariantCulture, - System.Globalization.DateTimeStyles.RoundtripKind, - out var dt)) - { - return dt.Kind == DateTimeKind.Utc ? dt : dt.ToUniversalTime(); - } - return null; - } - catch { return null; } - } - - /// - /// Write to via a temp file - /// + rename. The rename is atomic - /// on Windows for same-volume moves, so a crash mid-write can never leave a - /// truncated/corrupted file at — readers either see the - /// previous contents or the full new contents, never a partial write. Use this - /// for every cache file (scenarios.json, tags.json, schema-version.txt, etc.) - /// so a process crash during refresh doesn't pin users to embedded fallback. - /// - public static void AtomicWriteAllText(string path, string contents) - { - var dir = Path.GetDirectoryName(path); - if (!string.IsNullOrEmpty(dir)) Directory.CreateDirectory(dir); - var tmp = path + ".tmp"; - File.WriteAllText(tmp, contents); - File.Move(tmp, path, overwrite: true); - } - - /// - /// Try to atomically acquire the spawn lock. Returns true if this process now - /// owns the lock (caller is responsible for calling ). - /// Returns false if another process owns it (foreground caller should either - /// proceed without the lock or back off, depending on its semantics). - /// - public static bool TryAcquireLock() => TryAcquireLockInternal(); - - private static bool TryAcquireLockInternal() - { - try - { - Directory.CreateDirectory(CacheRoot); - - // Reap stale lock from a crashed previous child. - if (File.Exists(LockFile)) - { - var age = DateTime.UtcNow - File.GetLastWriteTimeUtc(LockFile); - if (age > LockTtl) - { - try { File.Delete(LockFile); } - catch { return false; } - } - else - { - return false; // Another process owns it. - } - } - - // Atomic create-or-fail. Only one process wins. - using var fs = new FileStream(LockFile, FileMode.CreateNew, - FileAccess.Write, FileShare.Read); - using var writer = new StreamWriter(fs); - writer.Write($"{Environment.ProcessId}@{DateTime.UtcNow:o}"); - return true; - } - catch (IOException) - { - return false; // Another process won the create-race. - } - catch - { - return false; - } - } -} diff --git a/src/tools/winui-search/CacheVersion.cs b/src/tools/winui-search/CacheVersion.cs deleted file mode 100644 index 9dc1460a..00000000 --- a/src/tools/winui-search/CacheVersion.cs +++ /dev/null @@ -1,50 +0,0 @@ -/// -/// Single source of truth for the on-disk cache version under -/// %LOCALAPPDATA%\winui-search\cache\. Both -/// and stamp this string into their -/// schema-version.txt on write and require an exact match on read; -/// any mismatch forces a cache miss + rebuild from embedded fallback JSON. -/// -/// Bump whenever ANY cached payload should be discarded: -/// 1. Scenario / tag JSON schema changes (new or removed fields) -/// 2. Embedded Data/*.json content changes (e.g. new tags added, -/// tag-list contents widened) — bump even if the C# schema is unchanged, -/// otherwise existing caches keep serving the older fallback contents. -/// 3. Tag extraction / cleaning logic changes that would alter the cached -/// output for the same input data. -/// -/// History: -/// "10" — Notes / Synonyms refactor -/// "11" — Added chip/token/tag entries to tokenizingtextbox in toolkit-tags.json -/// "12" — Added StopWords.TagOnly (text/input/layout/pick/basics/advanced) -/// → tag dicts cleansed; query tokens unchanged. -/// "13" — Toolkit cache now written CLEAN (CleanTagDictionary applied -/// before serialize), matching GalleryFetcher behavior. Old caches -/// contained polluted toolkit tags that were only filtered on read. -/// "14" — Plan A: separate keywords.json cache file; Plan B: HeaderText -/// is now the Sample's Header attribute alone (no " — Description" -/// suffix), Description holds the .md paragraph or XAML Description -/// attribute as a fallback. -/// "15" — Toolkit CleanCSharp now folds platform #if/#else/#endif (keeps -/// WINAPPSDK branch, drops UWP/Uno fallbacks) so emitted samples -/// compile clean against WinAppSDK without the noisy preprocessor. -/// "16" — Toolkit scenario IDs now renumbered in stable sample-path order -/// (was: alphabetical-by-slug, which reshuffled when upstream -/// rewords a Header). Old caches still resolve correctly inside a -/// single process but {controlId}-{N} differs across versions. -/// "17" — WinUI-Gallery moved + reformatted its samples: ControlInfoData.json -/// relocated to SampleSupport/Data/, pages are per-control under -/// Samples/{UniqueId}/, and ControlExample code now lives in -/// "--- header/xaml/c#" SampleDefinition .txt bundles. GalleryFetcher -/// parser rewritten and the embedded Data/gallery-*.json snapshot -/// regenerated from the new format — bump to discard old-format caches. -/// "18" — Legacy inline a11y samples with no leading comment now fall back to -/// the control Subtitle for HeaderText (was empty → "{Control}: "), -/// so the embedded gallery snapshot changed. -/// "19" — reactor provider + embedded snapshot added (new microsoft-ui-reactor -/// source; adds a reactor cache subdir with its own scenarios/tags). -/// -internal static class CacheVersion -{ - public const string Current = "19"; -} diff --git a/src/tools/winui-search/DATA_SOURCES.md b/src/tools/winui-search/DATA_SOURCES.md deleted file mode 100644 index 3d3571c1..00000000 --- a/src/tools/winui-search/DATA_SOURCES.md +++ /dev/null @@ -1,187 +0,0 @@ -# Data Sources - -`winui-search` builds its index from three upstream repositories. This doc describes -exactly **which files** are used, **what for**, and **how** they're processed. - -> Reference clones (developer convenience only — runtime always reads from GitHub): -> - `Q:\WinUI-Gallery\` — https://github.com/microsoft/WinUI-Gallery -> - `Q:\Windows\` — https://github.com/CommunityToolkit/Windows - ---- - -## 1. WinUI Gallery — `microsoft/WinUI-Gallery` - -Fetcher: **`GalleryFetcher.cs`** (cached for 7 days under -`%LOCALAPPDATA%\winui-search\cache\gallery`; fallback to embedded `Data/gallery-*.json`). - -### Files we read - -| Path on `main` | Purpose | Fields used | -|---|---|---| -| `WinUIGallery/SampleSupport/Data/ControlInfoData.json` | Master index of every control | `Groups[].Items[]`: `UniqueId`, `Title`, `Subtitle`, `Description`, `ApiNamespace`, `RelatedControls`, `Docs[]` | -| `WinUIGallery/Samples/{UniqueId}/{UniqueId}Page.xaml` | Per-control sample page | `` blocks — one per scenario. We read each block's `SampleDefinition="…"` attribute (new format). Legacy inline `` / `` (+ `HeaderText=`) is still parsed as a fallback for the few Accessibility pages that haven't migrated | -| `WinUIGallery/Samples/{UniqueId}/{SampleDefinition}` (co-located `.txt` bundle) | Per-scenario header + code | Split on `--- header` / `--- xaml` / `--- c#` markers → `HeaderText` / `Xaml` / `CSharp`. `$(…)` substitution tokens are flattened in XAML; a C# section containing `$(…)` is dropped (flattening would emit non-compileable code). The page-level copyright banner is the first XML comment on the page and lives outside every block, so it never becomes a header | - -### Fields actually consumed (not all schema fields) - -From each `ControlInfoData.json` Item we extract: -- `UniqueId` → `Scenario.ControlId` (lowercased) -- `Title` → `Scenario.ControlName` -- **`Subtitle`** → `Scenario.ControlDescription` (median 68 chars / max 129) — surfaced in `search` list as `[gallery] Name — `. Also concatenated with Title + Description for tag-source text -- `Description` (median 144 chars / max 448) — used **only** as tag-source text; was previously surfaced per-control in search but dropped during compression because it bloated tokens (Subtitle is the lighter replacement) -- **`ApiNamespace`** → `Scenario.ApiNamespace` (surfaced in `get` output for non-default namespaces only — see § Output) -- `RelatedControls[]` → `Scenario.RelatedControls` (surfaced as `**See also:**`) -- `Docs[]` → `Scenario.Docs` (kept on the Scenario but **not emitted** — agents never fetch them) - -> Note: `Groups[].Folder` was retired upstream. Special-section items (`IsSpecialSection: true`, -> e.g. Fundamentals / Design / Accessibility) now live under the same uniform -> `Samples/{UniqueId}/` path as every other control, so there is no longer a per-group URL prefix. - -Schema reference: `WinUIGallery/SampleSupport/Data/ControlInfoDataSchema.json` — -JSON-Schema description of every field. Read for documentation; **not loaded at runtime**. - -### Files NOT used - -Everything else under `WinUI-Gallery/`: -- `WinUIGallery/` app shell, MainWindow, App.xaml, Helpers, framework code -- `WinUIGallery/Samples/SamplePages/`, `Samples/SampleHelpers/` -- `WinUIGallery.SourceGenerator/` -- `tests/`, `scripts/`, `packagestore/`, `.pipelines/`, `.github/` -- `WinUIGallery/Assets/` (icons, images, sample media) - -### Output: when does Namespace show? - -- 79/115 controls map to `Microsoft.UI.Xaml.Controls` — auto-imported in default - templates, **suppressed** to keep output clean. -- 76 scenarios across 14 long-tail namespaces emit `**Namespace:** \`xxx\``: - - `Microsoft.UI.Xaml`, `Microsoft.UI.Windowing`, `Microsoft.UI.Xaml.Media.Animation`, - `Microsoft.UI.Xaml.Shapes`, `Windows.ApplicationModel.DataTransfer`, - `Microsoft.Windows.Notifications`, `Microsoft.Windows.Storage.Pickers`, - `Microsoft.UI.Composition.SystemBackdrops`, `Microsoft.UI.Xaml.Controls.Primitives`, - `Microsoft.Windows.BadgeNotifications`, `Windows.UI.StartScreen` (jumplist), - `Microsoft.UI.Xaml.Input`, `Microsoft.UI.Xaml.Media`, `Microsoft.UI.Content`. - -These are the namespaces agents most often miss when writing `using` / `xmlns` -declarations. - ---- - -## 2. CommunityToolkit Windows — `CommunityToolkit/Windows` - -Fetcher: **`ToolkitFetcher.cs`** (cached for 7 days under -`%LOCALAPPDATA%\winui-search\cache\toolkit`; fallback to embedded `Data/toolkit-*.json`). - -### Files we read - -| Path pattern | Purpose | Fields used | -|---|---|---| -| `https://api.github.com/repos/CommunityToolkit/Windows/git/trees/main?recursive=1` | File tree to discover all components/samples | All paths under `components/` | -| `components//src/.csproj` | NuGet package id (the csproj filename = package id) | filename → `Scenario.NuGetPackage` | -| `components//samples/.md` | Sample frontmatter + descriptions + tags | YAML frontmatter (`title`, `description`, `keywords`), `## ` headings → control description + per-sample text | -| `components//samples/.xaml` | XAML scenario | Whole file — extracted as `Scenario.Xaml`, with derived `xmlns:` imports → `Scenario.XmlnsImports` | -| `components//samples/.xaml.cs` | Code-behind (when present) | Whole file — `Scenario.CSharp` | - -### Skipped components (not visual controls) - -`Triggers`, `Converters`, `Behaviors`, `Extensions`, `Helpers`, `Media`, -`DeveloperTools`, `Animations`, `CameraPreview`, `LayoutTransformControl`. - -### Sample-name → controlId overrides - -`SampleOverrides` dictionary in `ToolkitFetcher.cs` — collapses multiple -sample files to one control (e.g., `SettingsCardSample` + `ClickableSettingsCardSample` -+ `SettingsPageExample` all → `settingscard`). - -### Files NOT used - -- `tests/`, `docs/`, `.github/`, repo-level configs -- `components//src/` source code (we only read csproj filename, not contents) - ---- - -## 3. microsoft-ui-reactor — `microsoft/microsoft-ui-reactor` - -Fetcher: **`ReactorFetcher.cs`** (cached for 7 days under -`%LOCALAPPDATA%\winui-search\cache\reactor`; fallback to embedded `Data/reactor-*.json`). - -Reactor scenarios are **C#-only declarative WinUI** — no XAML. The samples use -Reactor's functional API (`UseMemo`, `DataGrid(...)`, `Column(...)`). The Reactor -team owns a purpose-built search index we consume directly, so there is no scraping -or per-file cleaning. - -### File we read - -| URL on `main` | Purpose | Fields used | -|---|---|---| -| `samples/ReactorGallery/reactor-search-index.json` | Purpose-built index of every Reactor control (93) | `controls[]`: `id`, `name`, `description`, `keywords`, `relatedControls`, `apiNamespace`, `nugetPackage`, control-level `usings` (4 controls), `samples[]` (`header`, `language`, `code`) | - -Parsed with `JsonDocument` (AOT-safe, no reflection). - -### Field mapping (per control × sample) - -- `id` → `Scenario.ControlId`; scenario id = `{id}-{N}` (1-indexed; every control ships exactly one sample today, so ids are `{id}-1`) -- `name` → `Scenario.ControlName`; `description` → `Scenario.ControlDescription` -- `samples[].header` → `Scenario.HeaderText`; `samples[].code` → `Scenario.CSharp` **verbatim** (`Scenario.Xaml` stays null; `language` is always `csharp`) -- control-level `usings[]` (present only on `data-grid`, `docking`, `flex`, `property-grid`) → `using X;` lines + a blank line prepended to that control's sample code so the snippet compiles standalone -- `nugetPackage` → `Scenario.NuGetPackage` (uniform `Microsoft.UI.Reactor`, surfaced as `**Setup:** NuGet \`…\``) -- `apiNamespace` → `Scenario.ApiNamespace` (stored but **not** surfaced — all 93 share `Microsoft.UI.Reactor`, so the `**Namespace:**` line is suppressed for reactor) -- `relatedControls[]` → `Scenario.RelatedControls` (surfaced as `**See also:**`; null/absent → empty) -- `keywords[]` → the **enrichment tag field** (`ProviderData.Tags`, BM25 weight 3.0), served **verbatim — NOT stop-word cleaned** so curated multi-word intent terms like `css layout` survive (cleaning would drop the TagOnly stop word `layout` and hurt e.g. `search "flex layout"`) -- `category`, `galleryRoute` → ignored (no consumer) - -### Files NOT used - -Everything else in the repo — the tool reads only the single -`reactor-search-index.json`. - ---- - -## 4. Hand-curated data shipped with the tool - -Files under `src/tools/winui-search/Data/` — embedded resources baked into the exe: - -| File | Source | Purpose | -|---|---|---| -| `gallery-scenarios.json` | Auto-baked from § 1 by `winui-search update` | 321 scenarios across 111 controls — fallback when GitHub fetch fails or cache stale | -| `gallery-tags.json` | Auto-baked from § 1 (with manual overrides for missing controls like `jumplist-*`) | Per-control keyword arrays for BM25 | -| `toolkit-scenarios.json` | Auto-baked from § 2 | 48 scenarios across 26 controls | -| `toolkit-tags.json` | Auto-baked from § 2 | Per-control keyword arrays for BM25 | -| `reactor-scenarios.json` | Auto-baked from § 3 | 93 scenarios (1 per control) — C#-only Reactor samples | -| `reactor-tags.json` | Auto-baked from § 3 | Per-control curated keyword arrays for BM25 (verbatim, not cleaned) | -| `core-patterns.json` | **Hand-written** | 6 platform patterns Gallery doesn't cover well: jumplist, share contract, file picker, drag-drop, etc. Loaded as a separate index alongside scenarios | - ---- - -## 5. Cache & refresh - -- Cache dir: `%LOCALAPPDATA%\winui-search\cache\{gallery,toolkit,reactor}\` -- TTL: 7 days -- Schema version: see `CacheVersion.cs` (currently `"19"`). **Bump it on any - embedded-data or tag-logic change**, otherwise existing user caches keep serving - the older snapshot. Recent bumps: - - `13` Toolkit cache now written CLEAN (CleanTagDictionary applied before serialize) - - `14` Plan A keywords.json + Plan B Header attribute is the sole HeaderText source - - `15` Toolkit CleanCSharp folds platform `#if`/`#else`/`#endif` - - `16` Toolkit scenario IDs renumbered in stable sample-path order - - `17` WinUI-Gallery moved + reformatted samples (SampleSupport/Data/ + - per-control `Samples/{UniqueId}/` + `--- header/xaml/c#` SampleDefinition - bundles); GalleryFetcher rewritten and embedded gallery snapshot regenerated - - `18` Legacy inline a11y samples with no leading comment fall back to the - control Subtitle for HeaderText (was empty → `"{Control}: "`) - - `19` reactor provider + embedded snapshot added -- Manual refresh: `winui-search update` — pulls fresh data from GitHub and rewrites - `%LOCALAPPDATA%` cache. To re-bake the embedded fallback, copy - `%LOCALAPPDATA%\winui-search\cache\{source}\*.json` → - `src\tools\winui-search\Data\{source}-*.json` and rebuild. - ---- - -## 6. Quick stats (after most recent refresh) - -| Source | Scenarios | Unique controls | Notes | -|---|---:|---:|---| -| Gallery | 321 | 111 | 284 with `ApiNamespace`, 73 of which are non-default (shown as hint) | -| Toolkit | 48 | 26 | All carry `NuGetPackage` + `XmlnsImports` | -| Reactor | 93 | 93 | C#-only; uniform `Microsoft.UI.Reactor` package; 4 controls carry `usings` | -| Core patterns | 6 | n/a | jumplist, share-target, file-picker, drag-drop, etc. | -| **Total** | **468 patterns** | | | diff --git a/src/tools/winui-search/Data/core-patterns.json b/src/tools/winui-search/Data/core-patterns.json deleted file mode 100644 index 920fda04..00000000 --- a/src/tools/winui-search/Data/core-patterns.json +++ /dev/null @@ -1,167 +0,0 @@ -[ - { - "id": "jumplist-recent-files", - "scenario": "Show recently opened files/folders in the taskbar right-click menu", - "tags": [ - "jumplist", - "taskbar", - "recent", - "files", - "folders", - "pin", - "start menu" - ], - "description": "Add recently opened files or folders to the Windows taskbar JumpList so users can quickly reopen them by right-clicking the app icon.", - "prerequisites": [ - "App must be packaged (have Package.appxmanifest)" - ], - "xaml": null, - "csharp": "using Windows.UI.StartScreen;\n\npublic static class JumpListService\n{\n public static async Task AddRecentFileAsync(string filePath, string displayName)\n {\n if (!JumpList.IsSupported()) return;\n\n var jumpList = await JumpList.LoadCurrentAsync();\n jumpList.SystemGroupKind = JumpListSystemGroupKind.Recent;\n\n // Remove existing item with same path to avoid duplicates\n var existing = jumpList.Items.FirstOrDefault(i => i.Arguments == filePath);\n if (existing != null) jumpList.Items.Remove(existing);\n\n var item = JumpListItem.CreateWithArguments(filePath, displayName);\n item.GroupName = \"Recent\";\n item.Logo = new Uri(\"ms-appx:///Assets/document.png\"); // optional\n jumpList.Items.Add(item);\n\n await jumpList.SaveAsync();\n }\n\n public static async Task ClearJumpListAsync()\n {\n if (!JumpList.IsSupported()) return;\n var jumpList = await JumpList.LoadCurrentAsync();\n jumpList.Items.Clear();\n jumpList.SystemGroupKind = JumpListSystemGroupKind.None;\n await jumpList.SaveAsync();\n }\n}\n\n// Handle JumpList activation in App.xaml.cs:\nprotected override void OnLaunched(LaunchActivatedEventArgs args)\n{\n _window = new MainWindow();\n _window.Activate();\n\n // Check if launched from JumpList\n string arguments = args.Arguments;\n if (!string.IsNullOrEmpty(arguments))\n {\n // Open the file specified in the JumpList item\n _window.OpenFile(arguments);\n }\n}", - "notes": [ - "JumpList.IsSupported() returns false on non-desktop devices", - "Call AddRecentFileAsync() after opening or saving a file", - "Handle args.Arguments in OnLaunched to open files clicked in JumpList", - "JumpListItem.CreateWithArguments(args, displayName) — args is what you receive in OnLaunched" - ] - }, - { - "id": "share-contract-desktop", - "scenario": "Share files or data with other apps using the Windows Share dialog", - "tags": [ - "share", - "contract", - "datatransfer", - "files", - "send", - "share dialog" - ], - "description": "Invoke the Windows Share UI from a WinUI 3 desktop app. Desktop apps cannot use DataTransferManager.GetForCurrentView() — they must use COM interop with IDataTransferManagerInterop.", - "prerequisites": [ - "using WinRT.Interop for WindowNative.GetWindowHandle" - ], - "xaml": "", - "csharp": "using System.Runtime.InteropServices;\nusing Windows.ApplicationModel.DataTransfer;\nusing Windows.Storage;\n\npublic sealed class ShareService\n{\n // COM interface required for desktop WinUI 3 apps\n [ComImport, Guid(\"3A3DCD6C-3EAB-43DC-BCDE-45671CE800C8\")]\n [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]\n interface IDataTransferManagerInterop\n {\n IntPtr GetForWindow(IntPtr appWindow, ref Guid riid);\n void ShowShareUIForWindow(IntPtr appWindow);\n }\n\n private static readonly Guid _dtmIid =\n new(\"a5caee9b-8708-49d1-8d36-67d25a8da00c\");\n\n public static void ShowShareUI(IntPtr hwnd, IReadOnlyList filePaths)\n {\n var interop = DataTransferManager.As();\n var riid = _dtmIid;\n var dtmPtr = interop.GetForWindow(hwnd, ref riid);\n var dtm = DataTransferManager.FromAbi(dtmPtr);\n\n dtm.DataRequested += (sender, args) =>\n {\n var request = args.Request;\n request.Data.Properties.Title = \"Share Files\";\n var files = filePaths\n .Select(p => StorageFile.GetFileFromPathAsync(p).GetAwaiter().GetResult())\n .ToList();\n request.Data.SetStorageItems(files);\n };\n\n interop.ShowShareUIForWindow(hwnd);\n }\n}\n\n// Usage from code-behind:\nprivate void ShareButton_Click(object sender, RoutedEventArgs e)\n{\n var hwnd = WinRT.Interop.WindowNative.GetWindowHandle(App.Window);\n ShareService.ShowShareUI(hwnd, selectedFilePaths);\n}", - "notes": [ - "NEVER use DataTransferManager.GetForCurrentView() — it throws in desktop apps", - "NEVER use DataTransferManager.ShowShareUI() — use ShowShareUIForWindow(hwnd)", - "Get HWND via WinRT.Interop.WindowNative.GetWindowHandle(window)", - "The COM GUIDs are fixed — do not change them" - ] - }, - { - "id": "system-tray-minimize", - "scenario": "Minimize app to system tray with a tray icon and restore on click", - "tags": [ - "tray", - "system tray", - "notification area", - "minimize", - "background", - "icon", - "taskbar icon" - ], - "description": "Hide the window to the system tray (notification area) instead of closing it. Uses H.NotifyIcon.WinUI — the recommended tray icon library for WinUI 3.", - "prerequisites": [ - "dotnet add package H.NotifyIcon.WinUI" - ], - "xaml": "\n\n \n\n\n\n\n \n \n", - "csharp": "// MainWindow.xaml.cs — intercept window close to hide instead of exit\nprivate void Window_Closed(object sender, WindowEventArgs args)\n{\n // Prevent actual close — hide to tray instead\n args.Handled = true;\n this.AppWindow.Hide();\n}\n\n// Restore from tray\npublic void ShowWindow()\n{\n this.AppWindow.Show();\n this.Activate();\n}\n\n// Exit for real (from tray menu)\npublic void ExitApp()\n{\n // Dispose tray icon\n if (Application.Current.Resources.TryGetValue(\"TrayIcon\", out var icon))\n {\n (icon as IDisposable)?.Dispose();\n }\n Application.Current.Exit();\n}", - "notes": [ - "Do NOT use WinUIEx.TrayIcon — its API surface is unreliable and poorly documented", - "H.NotifyIcon.WinUI is the recommended library (dotnet add package H.NotifyIcon.WinUI)", - "Use args.Handled = true in Window_Closed to prevent the window from actually closing", - "Use AppWindow.Hide() / AppWindow.Show() for visibility control", - "The icon must be a .ico file in Assets, not a .png", - "LeftClickCommand fires when user clicks the tray icon (use to restore window)" - ] - }, - { - "id": "file-picker-desktop", - "scenario": "Open a file picker dialog to let the user select files", - "tags": [ - "file", - "picker", - "open", - "save", - "dialog", - "browse", - "select file", - "folder picker", - "storage picker", - "packaged", - "msix", - "store" - ], - "description": "Use the Windows App SDK storage pickers (Microsoft.Windows.Storage.Pickers, shipped in WinAppSDK 1.8+) in a WinUI 3 desktop app. These pickers are designed to work identically in unpackaged and packaged (MSIX/Store) apps. The legacy WinRT Windows.Storage.Pickers.* types require WinRT.Interop.InitializeWithWindow and are known to fail silently in packaged builds — do NOT use them on WinAppSDK 1.8+.", - "prerequisites": [ - "Windows App SDK 1.8 or later (PackageReference Microsoft.WindowsAppSDK 1.8.*)" - ], - "xaml": null, - "csharp": "using Microsoft.Windows.Storage.Pickers;\nusing System.IO;\n\npublic static class FilePickerHelper\n{\n // Prefer this overload from a Click handler — pulls the WindowId straight off the XAML element.\n public static Task PickOpenFileAsync(FrameworkElement element, params string[] extensions)\n => PickOpenFileAsync(element.XamlRoot.ContentIslandEnvironment.AppWindowId, extensions);\n\n // Use this overload from a view-model / command where you only have the HWND.\n public static async Task PickOpenFileAsync(Microsoft.UI.WindowId windowId, params string[] extensions)\n {\n var picker = new FileOpenPicker(windowId)\n {\n SuggestedStartLocation = PickerLocationId.DocumentsLibrary,\n };\n\n foreach (var ext in extensions)\n picker.FileTypeFilter.Add(ext);\n\n if (picker.FileTypeFilter.Count == 0)\n picker.FileTypeFilter.Add(\"*\");\n\n return await picker.PickSingleFileAsync();\n }\n\n public static async Task PickSaveFileAsync(\n Microsoft.UI.WindowId windowId, string suggestedName, string extension, string filterName)\n {\n var picker = new FileSavePicker(windowId)\n {\n SuggestedStartLocation = PickerLocationId.DocumentsLibrary,\n SuggestedFileName = suggestedName,\n };\n picker.FileTypeChoices.Add(filterName, new List { extension });\n\n return await picker.PickSaveFileAsync();\n }\n}\n\n// Usage from a Click handler (cleanest):\nprivate async void OpenFile_Click(object sender, RoutedEventArgs e)\n{\n var element = (FrameworkElement)sender;\n var result = await FilePickerHelper.PickOpenFileAsync(element, \".txt\", \".md\", \".cs\");\n if (result is not null)\n {\n string content = await File.ReadAllTextAsync(result.Path);\n // Use the content...\n }\n}\n\n// Usage from an MVVM RelayCommand (no XAML sender):\n// 1) Cache the WindowId once in App.xaml.cs:\n// public static Microsoft.UI.WindowId WindowId =>\n// Microsoft.UI.Win32Interop.GetWindowIdFromWindow(\n// WinRT.Interop.WindowNative.GetWindowHandle(Window));\n// 2) Then call:\nprivate async Task SaveAsync()\n{\n var result = await FilePickerHelper.PickSaveFileAsync(\n App.WindowId, \"document\", \".txt\", \"Text Files\");\n if (result is not null)\n await File.WriteAllTextAsync(result.Path, _editorContent);\n}\n\n// If a downstream API still requires a Windows.Storage.StorageFile\n// (e.g. RichEditBox.Document.LoadFromStream / SaveToStream, CachedFileManager.DeferUpdates):\n// var file = await Windows.Storage.StorageFile.GetFileFromPathAsync(result.Path);\n// Re-hydrate from the path — do NOT switch back to the legacy picker.", - "notes": [ - "USE Microsoft.Windows.Storage.Pickers on WinAppSDK 1.8+. It works in packaged AND unpackaged apps.", - "DO NOT use Windows.Storage.Pickers.FileSavePicker / FileOpenPicker / FolderPicker + WinRT.Interop.InitializeWithWindow — these silently fail to display a dialog in packaged (MSIX/Store) apps even when InitializeWithWindow succeeds. This is the root cause of 'save button does nothing once installed from the Store'.", - "Constructor takes a Microsoft.UI.WindowId. From a XAML element, use element.XamlRoot.ContentIslandEnvironment.AppWindowId. From an HWND, use Microsoft.UI.Win32Interop.GetWindowIdFromWindow(hwnd).", - "PickSingleFileAsync / PickSaveFileAsync return a PickFileResult (or null on cancel). Use result.Path — it's a plain filesystem path. Write with System.IO (File.WriteAllBytesAsync, File.ReadAllTextAsync, etc.).", - "FolderPicker is in the same namespace: new FolderPicker(windowId).PickSingleFolderAsync() returns a PickFolderResult.", - "FileOpenPicker.FileTypeFilter must have at least one entry — Add(\"*\") to allow all files.", - "FileSavePicker.FileTypeChoices.Add(displayName, IList extensions). Each extension must start with '.' (e.g. \".png\").", - "Canonical sample: WinUI-Gallery → WinUIGallery/Samples/ControlPages/StoragePickersPage.xaml.cs." - ] - }, - { - "id": "livecharts-realtime", - "scenario": "Display real-time scrolling line charts for monitoring data", - "tags": [ - "chart", - "graph", - "line chart", - "real-time", - "monitoring", - "performance", - "live", - "scrolling" - ], - "description": "Use LiveCharts2 to render real-time scrolling line charts in WinUI 3. The key pitfall is the Axis binding type — it must be IEnumerable, not Axis[].", - "prerequisites": [ - "dotnet add package LiveChartsCore.SkiaSharpView.WinUI" - ], - "xaml": "", - "csharp": "using LiveChartsCore;\nusing LiveChartsCore.Defaults;\nusing LiveChartsCore.Kernel.Sketches;\nusing LiveChartsCore.SkiaSharpView;\nusing LiveChartsCore.SkiaSharpView.Painting;\nusing SkiaSharp;\nusing System.Collections.ObjectModel;\n\npublic partial class MonitorViewModel : ObservableObject\n{\n private readonly ObservableCollection _cpuValues = new();\n private int _dataPointCount;\n\n // IMPORTANT: Use IEnumerable, NOT Axis[]\n public IEnumerable XAxes { get; } = new List\n {\n new Axis\n {\n Labeler = value => string.Empty, // hide X labels\n MinStep = 1,\n }\n };\n\n public IEnumerable YAxes { get; } = new List\n {\n new Axis\n {\n MinLimit = 0,\n MaxLimit = 100,\n Labeler = value => $\"{value:0}%\",\n }\n };\n\n public ISeries[] CpuSeries { get; }\n\n public MonitorViewModel()\n {\n CpuSeries = new ISeries[]\n {\n new LineSeries\n {\n Values = _cpuValues,\n Stroke = new SolidColorPaint(SKColors.DodgerBlue, 2),\n Fill = null,\n GeometrySize = 0,\n LineSmoothness = 0.5,\n }\n };\n }\n\n // Call this from a DispatcherQueueTimer (1-second interval)\n public void AddDataPoint(double cpuPercent)\n {\n _cpuValues.Add(new ObservableValue(cpuPercent));\n _dataPointCount++;\n\n // Keep 60 seconds of history\n if (_cpuValues.Count > 60)\n _cpuValues.RemoveAt(0);\n\n // Scroll X axis\n var xAxis = (Axis)((List)(IEnumerable)XAxes)[0];\n xAxis.MinLimit = _dataPointCount > 60 ? _dataPointCount - 60 : 0;\n xAxis.MaxLimit = _dataPointCount;\n }\n}", - "notes": [ - "CRITICAL: XAxes/YAxes must be IEnumerable, NOT Axis[] — Axis[] causes WMC1121 binding error", - "Use ObservableCollection for auto-updating charts", - "Set AnimationsSpeed to a short duration (100ms) for smooth real-time updates", - "Remove data points older than 60 entries to keep the chart scrolling", - "Use DispatcherQueueTimer for 1-second update intervals, NOT System.Timers.Timer" - ] - }, - { - "id": "drag-drop-files", - "scenario": "Accept files dropped from File Explorer onto the app", - "tags": [ - "drag", - "drop", - "dragover", - "allowdrop", - "files", - "import", - "datapackage", - "storageitems" - ], - "description": "Handle file drag-and-drop from Windows Explorer into a WinUI 3 app. Set AllowDrop on the target element and handle DragOver + Drop events.", - "prerequisites": [ - "using Windows.ApplicationModel.DataTransfer", - "using Windows.Storage" - ], - "xaml": "\n \n \n", - "csharp": "private void Grid_DragOver(object sender, DragEventArgs e)\n{\n e.AcceptedOperation = DataPackageOperation.Copy;\n e.DragUIOverride.Caption = \"Drop to import\";\n e.DragUIOverride.IsCaptionVisible = true;\n e.DragUIOverride.IsGlyphVisible = true;\n}\n\nprivate async void Grid_Drop(object sender, DragEventArgs e)\n{\n if (e.DataView.Contains(StandardDataFormats.StorageItems))\n {\n var items = await e.DataView.GetStorageItemsAsync();\n foreach (var item in items)\n {\n if (item is StorageFile file)\n {\n // Process each dropped file\n await ImportFileAsync(file);\n }\n else if (item is StorageFolder folder)\n {\n // Process dropped folder\n }\n }\n }\n}", - "notes": [ - "The drop target element MUST have a Background set (even Transparent) — without it, hit testing fails and drop events won't fire.", - "AllowDrop must be set to True on the target element in XAML.", - "Use e.AcceptedOperation to control the drag cursor icon (Copy, Move, Link).", - "Use e.DragUIOverride to customize the drag visual and caption.", - "StorageItems contains both StorageFile and StorageFolder — check the type." - ] - } -] \ No newline at end of file diff --git a/src/tools/winui-search/Data/gallery-scenarios.json b/src/tools/winui-search/Data/gallery-scenarios.json deleted file mode 100644 index 53630856..00000000 --- a/src/tools/winui-search/Data/gallery-scenarios.json +++ /dev/null @@ -1 +0,0 @@ -[{"id":"xamlresources-1","controlId":"xamlresources","controlName":"Resources","headerText":"XamlResources","xaml":"\u003C!-- App.xaml --\u003E\n\u003CApplication\u003E\n \u003CApplication.Resources\u003E\n \u003C!-- Define an application-wide color resource --\u003E\n \u003CColor x:Key=\u0022PrimaryColor\u0022\u003E#0078D4\u003C/Color\u003E\n \u003C/Application.Resources\u003E\n\u003C/Application\u003E\n\n\u003C!-- YourPage.xaml --\u003E\n\u003CPage\u003E\n \u003CPage.Resources\u003E\n \u003C!-- Define page-level solid color brushes --\u003E\n \u003CSolidColorBrush x:Key=\u0022HighlightBrush\u0022 Color=\u0022#A94DC1\u0022 /\u003E\n \u003CSolidColorBrush x:Key=\u0022FontColor\u0022 Color=\u0022White\u0022 /\u003E\n \u003C/Page.Resources\u003E\n\n \u003C!-- StackPanel using the application-level resource \u0027PrimaryColor\u0027 --\u003E\n \u003CStackPanel Background=\u0022{StaticResource PrimaryColor}\u0022 Padding=\u00228\u0022\u003E\n \u003CTextBlock Text=\u0022Using application-level resources\u0022 Foreground=\u0022White\u0022 FontSize=\u002224\u0022 /\u003E\n\n \u003C!-- StackPanel using the page-level resource \u0027HighlightBrush\u0027 --\u003E\n \u003CStackPanel Background=\u0022{StaticResource HighlightBrush}\u0022 Padding=\u00228\u0022 Margin=\u00228\u0022\u003E\n \u003CTextBlock Text=\u0022Using page-level resources\u0022 Foreground=\u0022{StaticResource FontColor}\u0022 FontSize=\u002218\u0022 /\u003E\n\n \u003C!-- StackPanel with control-level resources defined within its own Resources --\u003E\n \u003CStackPanel Padding=\u00228\u0022 Margin=\u00228\u0022\u003E\n \u003CStackPanel.Resources\u003E\n \u003C!-- Define control-level resources --\u003E\n \u003CColor x:Key=\u0022BackgroundColor\u0022\u003E#E2241A\u003C/Color\u003E\n \u003Cx:String x:Key=\u0022Description\u0022\u003EUsing control-level resources\u003C/x:String\u003E\n \u003C/StackPanel.Resources\u003E\n \u003CGrid Background=\u0022{StaticResource BackgroundColor}\u0022 Padding=\u00228\u0022\u003E\n \u003CTextBlock Text=\u0022{StaticResource Description}\u0022 Foreground=\u0022White\u0022/\u003E\n \u003C/Grid\u003E\n \u003C/StackPanel\u003E\n \u003C/StackPanel\u003E\n \u003C/StackPanel\u003E\n\u003C/Page\u003E","csharp":"// Retrieve application-level resource\nvar primaryColor = (Windows.UI.Color)Application.Current.Resources[\u0022PrimaryColor\u0022];\n\n// Retrieve page-level resource\nvar highlightBrush = (SolidColorBrush)this.Resources[\u0022HighlightBrush\u0022];\n\n// Retrieve control-level resources\nvar headerFontSize = (double)newGrid.Resources[\u0022HeaderFontSize\u0022];\nvar welcomeMessage = (string)newGrid.Resources[\u0022Description\u0022];","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Reusable definitions for shared values to ensure consistency and maintainability.","relatedControls":["XamlStyles","Templates","Binding"],"apiNamespace":null,"docs":[{"title":"ResourceDictionary and XAML resource references","uri":"https://learn.microsoft.com/windows/apps/design/style/xaml-resource-dictionary"},{"title":"ResourceDictionary - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.resourcedictionary"},{"title":"XAML theme resources","uri":"https://learn.microsoft.com/windows/apps/design/style/xaml-theme-resources"}]},{"id":"xamlresources-2","controlId":"xamlresources","controlName":"Resources","headerText":"StaticResource versus ThemeResource","xaml":"\u003CStackPanel\u003E\n \u003CGrid Background=\u0022{StaticResource SolidBackgroundFillColorBaseBrush}\u0022\u003E\n \u003CTextBlock\n Text=\u0022StaticResource uses the value defined when the app starts and does not update when the theme changes.\u0022\n Foreground=\u0022{StaticResource TextFillColorPrimaryBrush}\u0022\n FontSize=\u002216\u0022\n TextWrapping=\u0022Wrap\u0022/\u003E\n \u003C/Grid\u003E\n\n \u003CGrid Background=\u0022{ThemeResource SolidBackgroundFillColorBaseBrush}\u0022\u003E\n \u003CTextBlock\n Text=\u0022ThemeResource adapts automatically to the current theme. If the app switches from Light to Dark, the color defined by ThemeResource changes.\u0022\n Foreground=\u0022{ThemeResource TextFillColorPrimaryBrush}\u0022\n FontSize=\u002216\u0022\n TextWrapping=\u0022Wrap\u0022/\u003E\n \u003C/Grid\u003E\n\u003C/StackPanel\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Reusable definitions for shared values to ensure consistency and maintainability.","relatedControls":["XamlStyles","Templates","Binding"],"apiNamespace":null,"docs":[{"title":"ResourceDictionary and XAML resource references","uri":"https://learn.microsoft.com/windows/apps/design/style/xaml-resource-dictionary"},{"title":"ResourceDictionary - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.resourcedictionary"},{"title":"XAML theme resources","uri":"https://learn.microsoft.com/windows/apps/design/style/xaml-theme-resources"}]},{"id":"xamlresources-3","controlId":"xamlresources","controlName":"Resources","headerText":"Define a new theme resource","xaml":"\u003CGrid\u003E\n \u003CGrid.Resources\u003E\n \u003CResourceDictionary\u003E\n \u003CResourceDictionary.ThemeDictionaries\u003E\n \u003CResourceDictionary x:Key=\u0022Default\u0022\u003E\n \u003CSolidColorBrush x:Key=\u0022BackgroundBrush\u0022 Color=\u0022#EEE\u0022 /\u003E\n \u003CSolidColorBrush x:Key=\u0022TextBrush\u0022 Color=\u0022#333\u0022 /\u003E\n \u003Cx:String x:Key=\u0022ThemeString\u0022\u003ELight theme\u003C/x:String\u003E\n \u003CImageSource x:Key=\u0022ImageSource\u0022\u003Ems-appx:///Assets/YourImage.png\n \u003C/ResourceDictionary\u003E\n \u003CResourceDictionary x:Key=\u0022Dark\u0022\u003E\n \u003CSolidColorBrush x:Key=\u0022BackgroundBrush\u0022 Color=\u0022#333\u0022 /\u003E\n \u003CSolidColorBrush x:Key=\u0022TextBrush\u0022 Color=\u0022#EEE\u0022 /\u003E\n \u003Cx:String x:Key=\u0022ThemeString\u0022\u003EDark theme\u003C/x:String\u003E\n \u003CImageSource x:Key=\u0022ImageSource\u0022\u003Ems-appx:///Assets/YourImage.png\n \u003C/ResourceDictionary\u003E\n \u003C/ResourceDictionary.ThemeDictionaries\u003E\n \u003C/ResourceDictionary\u003E\n \u003C/Grid.Resources\u003E\n \u003CStackPanel\n Padding=\u00228\u0022\n HorizontalAlignment=\u0022Center\u0022\n VerticalAlignment=\u0022Center\u0022\n Background=\u0022{ThemeResource BackgroundBrush}\u0022\u003E\n \u003CTextBlock\n Foreground=\u0022{ThemeResource TextBrush}\u0022\n Style=\u0022{StaticResource SubtitleTextBlockStyle}\u0022\n Text=\u0022{ThemeResource ThemeString}\u0022 /\u003E\n \u003CImage Source=\u0022{ThemeResource ImageSource}\u0022 /\u003E\n \u003C/StackPanel\u003E\n\u003C/Grid\u003E\u003C/ImageSource\u003E\u003C/ResourceDictionary\u003E\u003C/ImageSource\u003E\u003C/ResourceDictionary\u003E\u003C/ResourceDictionary.ThemeDictionaries\u003E\u003C/ResourceDictionary\u003E\u003C/Grid.Resources\u003E\u003C/Grid\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Reusable definitions for shared values to ensure consistency and maintainability.","relatedControls":["XamlStyles","Templates","Binding"],"apiNamespace":null,"docs":[{"title":"ResourceDictionary and XAML resource references","uri":"https://learn.microsoft.com/windows/apps/design/style/xaml-resource-dictionary"},{"title":"ResourceDictionary - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.resourcedictionary"},{"title":"XAML theme resources","uri":"https://learn.microsoft.com/windows/apps/design/style/xaml-theme-resources"}]},{"id":"xamlstyles-1","controlId":"xamlstyles","controlName":"Style","headerText":"Creating and applying a style","xaml":"\u003CStackPanel Spacing=\u00228\u0022\u003E\n \u003CStackPanel.Resources\u003E\n \u003CStyle x:Key=\u0022CustomButtonStyle\u0022 TargetType=\u0022Button\u0022 BasedOn=\u0022{StaticResource ButtonRevealStyle}\u0022\u003E\n \u003CSetter Property=\u0022Background\u0022 Value=\u0022{ThemeResource AccentAcrylicBackgroundFillColorDefaultBrush}\u0022 /\u003E\n \u003CSetter Property=\u0022MinWidth\u0022 Value=\u0022200\u0022 /\u003E\n \u003C/Style\u003E\n \u003C/StackPanel.Resources\u003E\n \u003CButton Content=\u0022Default button\u0022 /\u003E\n \u003CButton Content=\u0022Styled button\u0022 Style=\u0022{StaticResource CustomButtonStyle}\u0022 /\u003E\n \u003CButton Content=\u0022Styled button (overridden)\u0022 Style=\u0022{StaticResource CustomButtonStyle}\u0022\n Background=\u0022{ThemeResource SystemFillColorCriticalBackgroundBrush}\u0022 /\u003E\n\u003C/StackPanel\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A XAML style is a Reusable property settings to define consistent UI design elements.","relatedControls":["XamlResources","Templates","Binding"],"apiNamespace":"Microsoft.UI.Xaml","docs":[{"title":"Style - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.style"},{"title":"XAML styles","uri":"https://learn.microsoft.com/windows/apps/design/style/xaml-styles"}]},{"id":"xamlstyles-2","controlId":"xamlstyles","controlName":"Style","headerText":"Style without a key (implicit style)","xaml":"\u003CStackPanel\u003E\n \u003CStackPanel.Resources\u003E\n \u003CStyle TargetType=\u0022TextBlock\u0022\u003E\n \u003CSetter Property=\u0022FontSize\u0022 Value=\u002216\u0022 /\u003E\n \u003CSetter Property=\u0022FontFamily\u0022 Value=\u0022Consolas\u0022 /\u003E\n \u003CSetter Property=\u0022FontWeight\u0022 Value=\u0022Bold\u0022 /\u003E\n \u003C/Style\u003E\n \u003C/StackPanel.Resources\u003E\n\n \u003CTextBlock Text=\u0022This style is applied automatically!\u0022 /\u003E\n \u003CTextBlock Text=\u0022No need to set a key.\u0022 /\u003E\n\u003C/StackPanel\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A XAML style is a Reusable property settings to define consistent UI design elements.","relatedControls":["XamlResources","Templates","Binding"],"apiNamespace":"Microsoft.UI.Xaml","docs":[{"title":"Style - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.style"},{"title":"XAML styles","uri":"https://learn.microsoft.com/windows/apps/design/style/xaml-styles"}]},{"id":"binding-1","controlId":"binding","controlName":"Binding","headerText":"Binding between controls","xaml":"\u003CGrid ColumnSpacing=\u002212\u0022\u003E\n \u003CGrid.ColumnDefinitions\u003E\n \u003CColumnDefinition Width=\u0022auto\u0022 /\u003E\n \u003CColumnDefinition Width=\u0022auto\u0022 /\u003E\n \u003CColumnDefinition Width=\u0022auto\u0022 /\u003E\n \u003C/Grid.ColumnDefinitions\u003E\n\n \u003CStackPanel Spacing=\u00228\u0022 Grid.Column=\u00220\u0022\u003E\n \u003CTextBlock Text=\u0022One-Way Binding\u0022 FontWeight=\u0022SemiBold\u0022 /\u003E\n \u003C!-- One-Way Binding: The target TextBox mirrors the text entered in the SourceTextBox, but any change in the target is not reflected back to the source --\u003E\n \u003CTextBox x:Name=\u0022SourceTextBoxOneWay\u0022 Width=\u0022200\u0022 HorizontalAlignment=\u0022Left\u0022 PlaceholderText=\u0022Enter text here\u0022 /\u003E\n \u003CTextBox x:Name=\u0022TargetTextBoxOneWay\u0022 Width=\u0022200\u0022 HorizontalAlignment=\u0022Left\u0022 PlaceholderText=\u0022Mirrors above text\u0022\n Text=\u0022{x:Bind SourceTextBoxOneWay.Text, Mode=OneWay}\u0022 /\u003E\n \u003C/StackPanel\u003E\n\n \u003CAppBarSeparator Grid.Column=\u00221\u0022 /\u003E\n\n \u003CStackPanel Spacing=\u00228\u0022 Grid.Column=\u00222\u0022\u003E\n \u003CTextBlock Text=\u0022Two-Way Binding\u0022 FontWeight=\u0022SemiBold\u0022 /\u003E\n \u003C!-- Two-Way Binding: Changes in the SourceTextBox are automatically reflected in the TargetTextBox, and vice versa --\u003E\n \u003CTextBox x:Name=\u0022SourceTextBoxTwoWay\u0022 Width=\u0022200\u0022 HorizontalAlignment=\u0022Left\u0022 PlaceholderText=\u0022Enter text here\u0022 /\u003E\n \u003CTextBox x:Name=\u0022TargetTextBoxTwoWay\u0022 Width=\u0022200\u0022 HorizontalAlignment=\u0022Left\u0022 PlaceholderText=\u0022Mirrors and edits above text\u0022\n Text=\u0022{x:Bind SourceTextBoxTwoWay.Text, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}\u0022 /\u003E\n \u003C/StackPanel\u003E\n\u003C/Grid\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Connecting UI elements to data for automatic synchronization and updates.","relatedControls":["XamlResources","XamlStyles","Templates"],"apiNamespace":null,"docs":[{"title":"Data binding","uri":"https://learn.microsoft.com/windows/apps/develop/data-binding/"},{"title":"{x:Bind} markup extension","uri":"https://learn.microsoft.com/windows/uwp/xaml-platform/x-bind-markup-extension"},{"title":"{Binding} markup extension","uri":"https://learn.microsoft.com/windows/uwp/xaml-platform/binding-markup-extension"},{"title":"Binding - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.data.binding"},{"title":"IValueConverter Interface - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.data.ivalueconverter"}]},{"id":"binding-2","controlId":"binding","controlName":"Binding","headerText":"Binding to a property in code-behind","xaml":"\u003CTextBlock\n Text=\u0022{x:Bind GreetingMessage}\u0022\n FontSize=\u002224\u0022\n HorizontalAlignment=\u0022Center\u0022\n VerticalAlignment=\u0022Center\u0022 /\u003E","csharp":"// Code-behind\npublic string GreetingMessage { get; set; } = \u0022Hello, WinUI 3!\u0022;","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Connecting UI elements to data for automatic synchronization and updates.","relatedControls":["XamlResources","XamlStyles","Templates"],"apiNamespace":null,"docs":[{"title":"Data binding","uri":"https://learn.microsoft.com/windows/apps/develop/data-binding/"},{"title":"{x:Bind} markup extension","uri":"https://learn.microsoft.com/windows/uwp/xaml-platform/x-bind-markup-extension"},{"title":"{Binding} markup extension","uri":"https://learn.microsoft.com/windows/uwp/xaml-platform/binding-markup-extension"},{"title":"Binding - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.data.binding"},{"title":"IValueConverter Interface - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.data.ivalueconverter"}]},{"id":"binding-3","controlId":"binding","controlName":"Binding","headerText":"Using a function in x:Bind","xaml":"\u003CDatePicker x:Name=\u0022DatePickerControl\u0022 Header=\u0022Select a date\u0022 /\u003E\n\u003CTextBlock Text=\u0022{x:Bind FormatDate(DatePickerControl.SelectedDate), Mode=OneWay}\u0022 /\u003E","csharp":"public string FormatDate(DateTimeOffset? date)\n{\n if (date.HasValue)\n {\n return \u0022Selected date is: \u0022 \u002B date.Value.ToString(\u0022dddd, MMMM d, yyyy\u0022);\n }\n else\n {\n return \u0022No date selected\u0022;\n }\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Connecting UI elements to data for automatic synchronization and updates.","relatedControls":["XamlResources","XamlStyles","Templates"],"apiNamespace":null,"docs":[{"title":"Data binding","uri":"https://learn.microsoft.com/windows/apps/develop/data-binding/"},{"title":"{x:Bind} markup extension","uri":"https://learn.microsoft.com/windows/uwp/xaml-platform/x-bind-markup-extension"},{"title":"{Binding} markup extension","uri":"https://learn.microsoft.com/windows/uwp/xaml-platform/binding-markup-extension"},{"title":"Binding - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.data.binding"},{"title":"IValueConverter Interface - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.data.ivalueconverter"}]},{"id":"binding-4","controlId":"binding","controlName":"Binding","headerText":"Using a converter in Binding","xaml":"\u003CPage...\n xmlns:c=\u0022using:YourNamespace\u0022\u003E\n\n \u003CPage.Resources\u003E\n \u003C!-- Declare the converter --\u003E\n \u003Cc:EmptyStringToVisibilityConverter x:Key=\u0022EmptyStringToVisibilityConverter\u0022 /\u003E\n \u003C/Page.Resources\u003E\n\n \u003CStackPanel Spacing=\u00228\u0022\u003E\n \u003C!-- Input TextBox --\u003E\n \u003CTextBox x:Name=\u0022InputTextBox\u0022 Header=\u0022Enter Text:\u0022 Width=\u0022300\u0022 /\u003E\n\n \u003C!-- TextBlock Visibility Depends on Input Text --\u003E\n \u003CTextBlock Text=\u0022The input is not empty.\u0022\n Visibility=\u0022{Binding Text, ElementName=InputTextBox, Converter={StaticResource EmptyStringToVisibilityConverter}}\u0022 /\u003E\n \u003C/StackPanel\u003E\n\u003C/Page\u003E","csharp":"using Microsoft.UI.Xaml.Data;\nusing Microsoft.UI.Xaml;\n\nnamespace YourNamespace\n{\n public class EmptyStringToVisibilityConverter : IValueConverter\n {\n // Visibility value when the input string is empty or null\n public Visibility EmptyValue { get; set; } = Visibility.Collapsed;\n\n // Visibility value when the input string is non-empty\n public Visibility NonEmptyValue { get; set; } = Visibility.Visible;\n\n public object Convert(object value, Type targetType, object parameter, string language)\n {\n // Return EmptyValue if the input is null or empty, otherwise NonEmptyValue\n return value is string stringValue \u0026\u0026 !string.IsNullOrEmpty(stringValue) \n ? NonEmptyValue \n : EmptyValue;\n }\n\n public object ConvertBack(object value, Type targetType, object parameter, string language)\n {\n // ConvertBack is not needed and not implemented in this case\n throw new NotImplementedException();\n }\n }\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Connecting UI elements to data for automatic synchronization and updates.","relatedControls":["XamlResources","XamlStyles","Templates"],"apiNamespace":null,"docs":[{"title":"Data binding","uri":"https://learn.microsoft.com/windows/apps/develop/data-binding/"},{"title":"{x:Bind} markup extension","uri":"https://learn.microsoft.com/windows/uwp/xaml-platform/x-bind-markup-extension"},{"title":"{Binding} markup extension","uri":"https://learn.microsoft.com/windows/uwp/xaml-platform/binding-markup-extension"},{"title":"Binding - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.data.binding"},{"title":"IValueConverter Interface - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.data.ivalueconverter"}]},{"id":"binding-5","controlId":"binding","controlName":"Binding","headerText":"Binding to a view model","xaml":"\u003CTextBlock Text=\u0022Title:\u0022 FontWeight=\u0022SemiBold\u0022 /\u003E\n\u003CTextBlock Text=\u0022{Binding Title}\u0022 FontSize=\u002216\u0022 /\u003E\n\n\u003CTextBlock Text=\u0022Description:\u0022 FontWeight=\u0022SemiBold\u0022 /\u003E\n\u003CTextBlock Text=\u0022{Binding Description}\u0022 FontSize=\u002216\u0022 /\u003E","csharp":"using System.ComponentModel; // For INotifyPropertyChanged interface.\nusing Microsoft.UI.Xaml.Controls; // For Page and other WinUI controls.\n\nnamespace YourNamespace\n{\n // Main page class\n public sealed partial class YourPage : Page\n {\n // Property to hold the ViewModel instance.\n public ExampleViewModel ViewModel { get; set; }\n\n public YourPage()\n {\n this.InitializeComponent();\n\n // Initialize the ViewModel with sample data.\n ViewModel = new ExampleViewModel\n {\n Title = \u0022Welcome to WinUI 3\u0022, // Set initial value for Title.\n Description = \u0022This is an example of binding to a view model.\u0022, // Set initial value for Description.\n };\n\n // Set the DataContext of the page to the ViewModel.\n // This makes the ViewModel properties available for binding in XAML.\n DataContext = ViewModel;\n }\n }\n\n // ViewModel class implementing INotifyPropertyChanged for data binding.\n public class ExampleViewModel : INotifyPropertyChanged\n {\n // Backing field for Title property.\n private string _title = string.Empty;\n\n // Backing field for Description property.\n private string _description = string.Empty;\n\n // Property for Title with change notification.\n public string Title\n {\n get =\u003E _title; // Return the current value of _title.\n set\n {\n if (_title != value) // Check if the new value is different.\n {\n _title = value; // Update the backing field.\n OnPropertyChanged(nameof(Title)); // Notify the UI of the change.\n }\n }\n }\n\n // Property for Description with change notification.\n public string Description\n {\n get =\u003E _description; // Return the current value of _description.\n set\n {\n if (_description != value) // Check if the new value is different.\n {\n _description = value; // Update the backing field.\n OnPropertyChanged(nameof(Description)); // Notify the UI of the change.\n }\n }\n }\n\n // Event to notify subscribers (UI elements) of property changes.\n public event PropertyChangedEventHandler? PropertyChanged;\n\n // Method to raise the PropertyChanged event.\n // This notifies the UI to update the bound control.\n protected void OnPropertyChanged(string propertyName)\n {\n PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));\n }\n }\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Connecting UI elements to data for automatic synchronization and updates.","relatedControls":["XamlResources","XamlStyles","Templates"],"apiNamespace":null,"docs":[{"title":"Data binding","uri":"https://learn.microsoft.com/windows/apps/develop/data-binding/"},{"title":"{x:Bind} markup extension","uri":"https://learn.microsoft.com/windows/uwp/xaml-platform/x-bind-markup-extension"},{"title":"{Binding} markup extension","uri":"https://learn.microsoft.com/windows/uwp/xaml-platform/binding-markup-extension"},{"title":"Binding - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.data.binding"},{"title":"IValueConverter Interface - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.data.ivalueconverter"}]},{"id":"binding-6","controlId":"binding","controlName":"Binding","headerText":"Binding with TargetNullValue","xaml":"\u003C!--TargetNullValue property help handle scenarios where the binding source is null--\u003E\n\u003CTextBlock Text=\u0022{Binding ViewModel.NullString, Mode=OneWay, TargetNullValue=\u0027Anonymous User\u0027}\u0022 /\u003E","csharp":"public YourPage()\n{\n this.InitializeComponent();\n\n ViewModel = new ExampleViewModel\n {\n NullString = null\n };\n \n DataContext = ViewModel;\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Connecting UI elements to data for automatic synchronization and updates.","relatedControls":["XamlResources","XamlStyles","Templates"],"apiNamespace":null,"docs":[{"title":"Data binding","uri":"https://learn.microsoft.com/windows/apps/develop/data-binding/"},{"title":"{x:Bind} markup extension","uri":"https://learn.microsoft.com/windows/uwp/xaml-platform/x-bind-markup-extension"},{"title":"{Binding} markup extension","uri":"https://learn.microsoft.com/windows/uwp/xaml-platform/binding-markup-extension"},{"title":"Binding - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.data.binding"},{"title":"IValueConverter Interface - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.data.ivalueconverter"}]},{"id":"binding-7","controlId":"binding","controlName":"Binding","headerText":"Binding a collection with data templates","xaml":"\u003CListView\n x:Name=\u0022ListDetailListView\u0022\n ItemsSource=\u0022{x:Bind Items}\u0022\n SelectionMode=\u0022Single\u0022\u003E\n \u003CListView.ItemTemplate\u003E\n \u003CDataTemplate x:DataType=\u0022local:ListDetailItem\u0022\u003E\n \u003CStackPanel Padding=\u00224\u0022 Spacing=\u00222\u0022\u003E\n \u003CTextBlock Text=\u0022{x:Bind Title}\u0022 FontWeight=\u0022SemiBold\u0022 /\u003E\n \u003CTextBlock Text=\u0022{x:Bind DateCreatedFormatted}\u0022\n Style=\u0022{ThemeResource CaptionTextBlockStyle}\u0022 /\u003E\n \u003C/StackPanel\u003E\n \u003C/DataTemplate\u003E\n \u003C/ListView.ItemTemplate\u003E\n\u003C/ListView\u003E\n\n\u003C!-- Detail panel bound to the selected item --\u003E\n\u003CStackPanel DataContext=\u0022{x:Bind ListDetailListView.SelectedItem, Mode=OneWay}\u0022\u003E\n \u003CTextBlock Text=\u0022{Binding Title}\u0022 FontSize=\u002220\u0022 FontWeight=\u0022SemiBold\u0022 /\u003E\n \u003CTextBlock Text=\u0022{Binding DateCreatedFormatted}\u0022\n Style=\u0022{ThemeResource CaptionTextBlockStyle}\u0022 /\u003E\n \u003CTextBlock Text=\u0022{Binding Text}\u0022 TextWrapping=\u0022Wrap\u0022 /\u003E\n\u003C/StackPanel\u003E","csharp":"public class ListDetailItem\n{\n public int Id { get; set; }\n public string Title { get; set; }\n public string Text { get; set; }\n public DateTime DateCreated { get; set; }\n public string DateCreatedFormatted =\u003E DateCreated.ToString(\u0022MMM d, yyyy h:mm tt\u0022);\n}\n\n// In your page class:\npublic List\u003CListDetailItem\u003E Items { get; set; }\n\npublic MyPage()\n{\n this.InitializeComponent();\n\n Items = new List\u003CListDetailItem\u003E\n {\n new ListDetailItem\n {\n Id = 0,\n Title = \u0022Item 1\u0022,\n Text = \u0022Lorem ipsum dolor sit amet...\u0022,\n DateCreated = new DateTime(2025, 6, 15, 9, 30, 0)\n },\n // Add more items...\n };\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Connecting UI elements to data for automatic synchronization and updates.","relatedControls":["XamlResources","XamlStyles","Templates"],"apiNamespace":null,"docs":[{"title":"Data binding","uri":"https://learn.microsoft.com/windows/apps/develop/data-binding/"},{"title":"{x:Bind} markup extension","uri":"https://learn.microsoft.com/windows/uwp/xaml-platform/x-bind-markup-extension"},{"title":"{Binding} markup extension","uri":"https://learn.microsoft.com/windows/uwp/xaml-platform/binding-markup-extension"},{"title":"Binding - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.data.binding"},{"title":"IValueConverter Interface - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.data.ivalueconverter"}]},{"id":"templates-1","controlId":"templates","controlName":"Templates","headerText":"Customize the look of a TextBox with a ControlTemplate","xaml":"\u003CGrid\u003E\n \u003CGrid.Resources\u003E\n \u003CControlTemplate x:Key=\u0022CustomTextBoxTemplate\u0022 TargetType=\u0022TextBox\u0022\u003E\n \u003CStackPanel Spacing=\u00228\u0022\u003E\n \u003CTextBlock Text=\u0022{TemplateBinding Header}\u0022 /\u003E\n \u003CBorder\n Background=\u0022{ThemeResource CardBackgroundFillColorDefaultBrush}\u0022\n BorderBrush=\u0022{TemplateBinding BorderBrush}\u0022\n BorderThickness=\u00222\u0022\n CornerRadius=\u00224\u0022\u003E\n \u003CStackPanel Margin=\u00224\u0022 Orientation=\u0022Horizontal\u0022 Spacing=\u00224\u0022\u003E\n \u003CSymbolIcon Symbol=\u0022Edit\u0022 /\u003E\n \u003CScrollViewer\n x:Name=\u0022ContentElement\u0022\n Padding=\u0022{TemplateBinding Padding}\u0022\n HorizontalScrollBarVisibility=\u0022{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}\u0022\n VerticalScrollBarVisibility=\u0022{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}\u0022 /\u003E\n \u003C/StackPanel\u003E\n \u003C/Border\u003E\n \u003C/StackPanel\u003E\n \u003C/ControlTemplate\u003E\n \u003C/Grid.Resources\u003E\n \u003CTextBox\n Padding=\u00228\u0022\n BorderBrush=\u0022{ThemeResource AccentFillColorDefaultBrush}\u0022\n Header=\u0022Enter text here\u0022\n Template=\u0022{StaticResource CustomTextBoxTemplate}\u0022 /\u003E\n\u003C/Grid\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Customize controls\u0027 visuals, item layouts, and data presentation in XAML.","relatedControls":["Binding","XamlStyles","CustomUserControls"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"XAML Control Templates","uri":"https://learn.microsoft.com/windows/apps/design/style/xaml-control-templates"},{"title":"ControlTemplate - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.controltemplate"},{"title":"DataTemplate - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.datatemplate"},{"title":"ItemsPanelTemplate - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.itemspaneltemplate"}]},{"id":"templates-2","controlId":"templates","controlName":"Templates","headerText":"Customize a ComboBox\u0027s ItemTemplate using a DataTemplate","xaml":"\u003CGrid\u003E\n \u003CGrid.Resources\u003E\n \u003CDataTemplate x:Key=\u0022CustomComboBoxItemTemplate\u0022\u003E\n \u003CStackPanel Orientation=\u0022Horizontal\u0022 Spacing=\u00228\u0022\u003E\n \u003CEllipse\n Fill=\u0022{ThemeResource AccentFillColorDefaultBrush}\u0022 /\u003E\n \u003CTextBlock Text=\u0022{Binding}\u0022 /\u003E\n \u003C/StackPanel\u003E\n \u003C/DataTemplate\u003E\n \u003C/Grid.Resources\u003E\n \u003CComboBox Header=\u0022Options\u0022 ItemTemplate=\u0022{StaticResource CustomComboBoxItemTemplate}\u0022 SelectedIndex=\u00220\u0022\u003E\n \u003CComboBox.Items\u003E\n \u003Cx:String\u003EOption 1\u003C/x:String\u003E\n \u003Cx:String\u003EOption 2\u003C/x:String\u003E\n \u003Cx:String\u003EOption 3\u003C/x:String\u003E\n \u003C/ComboBox.Items\u003E\n \u003C/ComboBox\u003E\n\u003C/Grid\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Customize controls\u0027 visuals, item layouts, and data presentation in XAML.","relatedControls":["Binding","XamlStyles","CustomUserControls"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"XAML Control Templates","uri":"https://learn.microsoft.com/windows/apps/design/style/xaml-control-templates"},{"title":"ControlTemplate - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.controltemplate"},{"title":"DataTemplate - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.datatemplate"},{"title":"ItemsPanelTemplate - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.itemspaneltemplate"}]},{"id":"templates-3","controlId":"templates","controlName":"Templates","headerText":"Customize an ItemsControl with an ItemsPanelTemplate","xaml":"\u003CListView\u003E\n \u003CListView.ItemsPanel\u003E\n \u003CItemsPanelTemplate\u003E\n \u003CWrapGrid Orientation=\u0022Horizontal\u0022 /\u003E\n \u003C/ItemsPanelTemplate\u003E\n \u003C/ListView.ItemsPanel\u003E\n \n \u003CListViewItem\u003EItem 01\u003C/ListViewItem\u003E\n \u003CListViewItem\u003EItem 02\u003C/ListViewItem\u003E\n \u003C!-- ... --\u003E\n \u003CListViewItem\u003EItem 20\u003C/ListViewItem\u003E\n\u003C/ListView\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Customize controls\u0027 visuals, item layouts, and data presentation in XAML.","relatedControls":["Binding","XamlStyles","CustomUserControls"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"XAML Control Templates","uri":"https://learn.microsoft.com/windows/apps/design/style/xaml-control-templates"},{"title":"ControlTemplate - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.controltemplate"},{"title":"DataTemplate - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.datatemplate"},{"title":"ItemsPanelTemplate - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.itemspaneltemplate"}]},{"id":"customusercontrols-1","controlId":"customusercontrols","controlName":"Custom \u0026 User Controls","headerText":"Counter Control with Increment/Decrement Mode","xaml":"\u003C!-- Generic.xaml --\u003E\n\u003CResourceDictionary \n xmlns=\u0022http://schemas.microsoft.com/winfx/2006/xaml/presentation\u0022\n xmlns:x=\u0022http://schemas.microsoft.com/winfx/2006/xaml\u0022\n xmlns:local=\u0022using:YourNamesapace\u0022\u003E\n\n \u003C!-- Style definition for CounterControl --\u003E\n \u003CStyle TargetType=\u0022local:CounterControl\u0022\u003E\n \u003CSetter Property=\u0022Template\u0022\u003E\n \u003CSetter.Value\u003E\n \u003C!-- ControlTemplate defines the structure of CounterControl --\u003E\n \u003CControlTemplate TargetType=\u0022local:CounterControl\u0022\u003E\n \u003CStackPanel HorizontalAlignment=\u0022Left\u0022 Spacing=\u00228\u0022\u003E\n \u003CTextBlock x:Name=\u0022CountText\u0022 FontSize=\u002220\u0022 Text=\u00220\u0022 HorizontalAlignment=\u0022Center\u0022 /\u003E\n \u003CButton x:Name=\u0022ActionButton\u0022 Content=\u0022Increase\u0022 HorizontalAlignment=\u0022Center\u0022 Width=\u0022100\u0022 /\u003E\n \u003C/StackPanel\u003E\n \u003C/ControlTemplate\u003E\n \u003C/Setter.Value\u003E\n \u003C/Setter\u003E\n \u003C/Style\u003E\n\u003C/ResourceDictionary\u003E\n\n\u003C!-- YourPage.xaml --\u003E\n\u003CPage ...\n xmlns:controls=\u0022using:YourNamesapace\u0022\u003E\n \u003CStackPanel Orientation=\u0022Horizontal\u0022 Spacing=\u00228\u0022\u003E\n \u003Ccontrols:CounterControl Mode=\u0022Increment\u0022 /\u003E\n \u003Ccontrols:CounterControl Mode=\u0022Decrement\u0022 /\u003E\n \u003C/StackPanel\u003E\n\u003C/Page\u003E","csharp":"using Microsoft.UI.Xaml;\nusing Microsoft.UI.Xaml.Controls;\n\nnamespace YourNamespace;\n\n// Enum defining the counter mode: Increment or Decrement\npublic enum CounterMode\n{\n Increment,\n Decrement\n}\n\n// Custom control class that extends Control\npublic sealed class CounterControl : Control\n{\n // DependencyProperty for storing the count value\n public static readonly DependencyProperty CountProperty =\n DependencyProperty.Register(nameof(Count), typeof(int), typeof(CounterControl), new PropertyMetadata(0));\n\n // DependencyProperty for determining the counter mode (Increment or Decrement)\n public static readonly DependencyProperty ModeProperty =\n DependencyProperty.Register(nameof(Mode), typeof(CounterMode), typeof(CounterControl), new PropertyMetadata(CounterMode.Increment));\n\n // Constructor setting the default style key\n public CounterControl()\n {\n this.DefaultStyleKey = typeof(CounterControl);\n }\n\n // Property to get and set the count value\n public int Count\n {\n get =\u003E (int)GetValue(CountProperty);\n set =\u003E SetValue(CountProperty, value);\n }\n\n // Property to get and set the counter mode\n public CounterMode Mode\n {\n get =\u003E (CounterMode)GetValue(ModeProperty);\n set =\u003E SetValue(ModeProperty, value);\n }\n\n // Fields for UI elements retrieved from the control template\n private Button? ActionButton;\n private TextBlock? CountText;\n\n // Method executed when the control\u0027s template is applied\n protected override void OnApplyTemplate()\n {\n base.OnApplyTemplate();\n\n // Retrieve template elements\n ActionButton = GetTemplateChild(nameof(ActionButton)) as Button;\n CountText = GetTemplateChild(nameof(CountText)) as TextBlock;\n\n // Attach event handler to button if it exists\n if (ActionButton is not null)\n {\n ActionButton.Click \u002B= (sender, e) =\u003E\n {\n Count = Mode == CounterMode.Increment ? Count \u002B 1 : Count - 1;\n UpdateUI();\n };\n\n UpdateButtonText();\n }\n\n UpdateUI();\n }\n\n private void UpdateUI()\n {\n if (CountText is not null)\n {\n CountText.Text = Count.ToString();\n }\n }\n\n private void UpdateButtonText()\n {\n if (ActionButton is not null)\n {\n ActionButton.Content = Mode == CounterMode.Increment ? \u0022Increase\u0022 : \u0022Decrease\u0022;\n }\n }\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Create reusable UI components with custom functionality and appearance.","relatedControls":["Templates","XamlStyles"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"Build XAML controls","uri":"https://learn.microsoft.com/windows/apps/winui/winui3/xaml-templated-controls-csharp-winui-3"},{"title":"Control - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.control"},{"title":"UserControl - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.usercontrol"}]},{"id":"customusercontrols-2","controlId":"customusercontrols","controlName":"Custom \u0026 User Controls","headerText":"Basic Custom Password Box with Validation","xaml":"\u003CResourceDictionary\n xmlns=\u0022http://schemas.microsoft.com/winfx/2006/xaml/presentation\u0022\n xmlns:x=\u0022http://schemas.microsoft.com/winfx/2006/xaml\u0022\n xmlns:local=\u0022using:YourNamespace\u0022\u003E\n \n \u003CStyle TargetType=\u0022local:ValidatedPasswordBox\u0022\u003E\n \u003CSetter Property=\u0022IsTabStop\u0022 Value=\u0022False\u0022 /\u003E\n \u003CSetter Property=\u0022Template\u0022\u003E\n \u003CSetter.Value\u003E\n \u003CControlTemplate TargetType=\u0022local:ValidatedPasswordBox\u0022\u003E\n \u003CStackPanel Spacing=\u00224\u0022\u003E\n \u003CPasswordBox x:Name=\u0022PasswordInput\u0022 /\u003E\n \u003CRichTextBlock x:Name=\u0022ValidationRichText\u0022\n AutomationProperties.LiveSetting=\u0022Polite\u0022\n TextWrapping=\u0022Wrap\u0022\n IsTextSelectionEnabled=\u0022False\u0022\n Visibility=\u0022Collapsed\u0022/\u003E\n \u003C/StackPanel\u003E\n \u003C/ControlTemplate\u003E\n \u003C/Setter.Value\u003E\n \u003C/Setter\u003E\n \u003C/Style\u003E\n\u003C/ResourceDictionary\u003E\n\n\u003C!-- YourPage.xaml --\u003E\n\u003CPage ...\n xmlns:controls=\u0022using:YourNamesapace\u0022\u003E\n \u003CStackPanel Spacing=\u00228\u0022\u003E\n \u003Ccontrols:ValidatedPasswordBox x:Name=\u0022PasswordInput\u0022 MinLength=\u00228\u0022 Width=\u0022240\u0022 HorizontalAlignment=\u0022Left\u0022\n Header=\u0022Password\u0022 PlaceholderText=\u0022Enter password...\u0022 /\u003E\n \u003CButton Content=\u0022Submit\u0022 IsEnabled=\u0022{x:Bind PasswordInput.IsValid, Mode=OneWay}\u0022\n Style=\u0022{StaticResource AccentButtonStyle}\u0022 Width=\u0022240\u0022 /\u003E\n \u003C/StackPanel\u003E\n\u003C/Page\u003E","csharp":"using Microsoft.UI.Xaml;\nusing Microsoft.UI.Xaml.Automation.Peers;\nusing Microsoft.UI.Xaml.Controls;\nusing Microsoft.UI.Xaml.Documents;\nusing Microsoft.UI.Xaml.Media;\nusing System.Linq;\nusing Windows.UI;\n\nnamespace YourNamespace;\n\n// Custom control for a validated password box\npublic sealed partial class ValidatedPasswordBox : Control\n{\n // Register a dependency property for the Password value.\n // Note: The PropertyMetadata includes a callback (OnPasswordChanged) so that the UI updates\n // whenever the password or related properties change.\n public static readonly DependencyProperty PasswordProperty =\n DependencyProperty.Register(nameof(Password), typeof(string), typeof(ValidatedPasswordBox), new PropertyMetadata(string.Empty, OnPasswordChanged));\n\n public static readonly DependencyProperty IsValidProperty =\n DependencyProperty.Register(nameof(IsValid), typeof(bool), typeof(ValidatedPasswordBox), new PropertyMetadata(false));\n\n public static readonly DependencyProperty MinLengthProperty =\n DependencyProperty.Register(nameof(MinLength), typeof(int), typeof(ValidatedPasswordBox), new PropertyMetadata(8, OnPasswordChanged));\n\n public static readonly DependencyProperty HeaderProperty =\n DependencyProperty.Register(nameof(Header), typeof(string), typeof(ValidatedPasswordBox), new PropertyMetadata(string.Empty, OnPasswordChanged));\n\n public static readonly DependencyProperty PlaceholderTextProperty =\n DependencyProperty.Register(nameof(PlaceholderText), typeof(string), typeof(ValidatedPasswordBox), new PropertyMetadata(string.Empty, OnPasswordChanged));\n\n public ValidatedPasswordBox()\n {\n this.DefaultStyleKey = typeof(ValidatedPasswordBox);\n }\n\n // CLR property wrappers\n public string Password { get =\u003E (string)GetValue(PasswordProperty); set =\u003E SetValue(PasswordProperty, value); }\n public bool IsValid { get =\u003E (bool)GetValue(IsValidProperty); set =\u003E SetValue(IsValidProperty, value); }\n public int MinLength { get =\u003E (int)GetValue(MinLengthProperty); set =\u003E SetValue(MinLengthProperty, value); }\n public string Header { get =\u003E (string)GetValue(HeaderProperty); set =\u003E SetValue(HeaderProperty, value); }\n public string PlaceholderText { get =\u003E (string)GetValue(PlaceholderTextProperty); set =\u003E SetValue(PlaceholderTextProperty, value); }\n\n // Template parts for password input and validation messages\n private PasswordBox? PasswordInput { get; set; }\n private RichTextBlock? ValidationRichText { get; set; }\n}\n// NOTE: snippet truncated \u2014 refer to full sample for additional code","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Create reusable UI components with custom functionality and appearance.","relatedControls":["Templates","XamlStyles"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"Build XAML controls","uri":"https://learn.microsoft.com/windows/apps/winui/winui3/xaml-templated-controls-csharp-winui-3"},{"title":"Control - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.control"},{"title":"UserControl - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.usercontrol"}]},{"id":"customusercontrols-3","controlId":"customusercontrols","controlName":"Custom \u0026 User Controls","headerText":"Temperature Converter UserControl example","xaml":"\u003C!-- TemperatureConverterControl.xaml --\u003E\n\u003CUserControl ...\u003E\n \u003CStackPanel Spacing=\u00228\u0022\u003E\n \u003CTextBox Header=\u0022Enter Temperature in Celsius\u0022 x:Name=\u0022InputTextBox\u0022 Width=\u0022200\u0022 PlaceholderText=\u0022Celsius\u0022 /\u003E\n \u003CButton Content=\u0022Convert to Fahrenheit\u0022 Width=\u0022200\u0022 Click=\u0022Button_Click\u0022 /\u003E\n \u003CTextBlock x:Name=\u0022ResultTextBlock\u0022 FontWeight=\u0022SemiBold\u0022 /\u003E\n \u003C/StackPanel\u003E\n\u003C/UserControl\u003E\n\n\u003C!-- Yourpage.xaml --\u003E\n\u003CPage ...\n xmlns:local=\u0022using:YourNamesapce\u0022\u003E\n \u003CGrid\u003E\n \u003Clocal:TemperatureConverterControl /\u003E\n \u003C/Grid\u003E\n\u003C/Page\u003E","csharp":"using Microsoft.UI.Xaml;\nusing Microsoft.UI.Xaml.Controls;\n\nnamespace YourNamesapace;\n\npublic sealed partial class TemperatureConverterControl : UserControl\n{\n public TemperatureConverterControl()\n {\n this.InitializeComponent();\n }\n\n private void Button_Click(object sender, RoutedEventArgs e)\n {\n string input = InputTextBox.Text;\n double celsius = 0;\n\n bool isNumber = double.TryParse(input, out celsius);\n\n if (isNumber)\n {\n double fahrenheit = (celsius * 9 / 5) \u002B 32;\n ResultTextBlock.Text = \u0022Fahrenheit: \u0022 \u002B fahrenheit.ToString(\u0022F2\u0022) \u002B \u0022\u00B0F\u0022;\n }\n else\n {\n ResultTextBlock.Text = \u0022Invalid input!\u0022;\n }\n }\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Create reusable UI components with custom functionality and appearance.","relatedControls":["Templates","XamlStyles"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"Build XAML controls","uri":"https://learn.microsoft.com/windows/apps/winui/winui3/xaml-templated-controls-csharp-winui-3"},{"title":"Control - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.control"},{"title":"UserControl - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.usercontrol"}]},{"id":"customxamlconditionals-1","controlId":"customxamlconditionals","controlName":"XAML Conditions","headerText":"Conditional elements","xaml":"\u003CPage\n xmlns=\u0022http://schemas.microsoft.com/winfx/2006/xaml/presentation\u0022\n xmlns:x=\u0022http://schemas.microsoft.com/winfx/2006/xaml\u0022\n xmlns:cond=\u0022using:WinUIGallery.ControlPages\u0022\n xmlns:newExp=\u0022http://schemas.microsoft.com/winfx/2006/xaml/presentation?cond:FeatureFlagCondition(NewExperience)\u0022\n xmlns:legacy=\u0022http://schemas.microsoft.com/winfx/2006/xaml/presentation?cond:FeatureFlagCondition(LegacyMode)\u0022\u003E\n\n \u003CStackPanel Spacing=\u00228\u0022\u003E\n \u003C!-- Included only when FeatureFlagCondition.Evaluate(\u0022NewExperience\u0022) returns true. --\u003E\n \u003CnewExp:InfoBar Title=\u0022New experience\u0022 IsOpen=\u0022True\u0022 Severity=\u0022Success\u0022\n Message=\u0022This InfoBar is included because the \u0027NewExperience\u0027 flag is true.\u0022 /\u003E\n\n \u003C!-- Included only when FeatureFlagCondition.Evaluate(\u0022LegacyMode\u0022) returns true. --\u003E\n \u003Clegacy:InfoBar Title=\u0022Legacy mode\u0022 IsOpen=\u0022True\u0022 Severity=\u0022Warning\u0022\n Message=\u0022This InfoBar is included because the \u0027LegacyMode\u0027 flag is true.\u0022 /\u003E\n \u003C/StackPanel\u003E\n\u003C/Page\u003E","csharp":"// Set the active feature flag(s) BEFORE InitializeComponent so the\n// XAML parser sees them when it evaluates the conditional elements.\n// In a real app these are typically set once at startup (e.g. from\n// App.OnLaunched) based on configuration, A/B test assignment, or\n// device capability detection. Once parsed, the result for each\n// (condition, argument) pair is cached for the lifetime of the\n// process - changing a flag later does NOT re-render markup that\n// was already parsed.\npublic sealed partial class MyPage : Page\n{\n public MyPage()\n {\n FeatureFlagCondition.FeatureFlags[\u0022NewExperience\u0022] = true;\n FeatureFlagCondition.FeatureFlags[\u0022LegacyMode\u0022] = false;\n\n this.InitializeComponent();\n }\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Define custom XAML conditions evaluated at parse time using IXamlCondition.","relatedControls":[],"apiNamespace":"Microsoft.UI.Xaml.Markup","docs":[{"title":"IXamlCondition - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.markup.ixamlcondition"}]},{"id":"customxamlconditionals-2","controlId":"customxamlconditionals","controlName":"XAML Conditions","headerText":"Conditional attributes","xaml":"\u003CPage\n xmlns=\u0022http://schemas.microsoft.com/winfx/2006/xaml/presentation\u0022\n xmlns:cond=\u0022using:WinUIGallery.ControlPages\u0022\n xmlns:newExp=\u0022http://schemas.microsoft.com/winfx/2006/xaml/presentation?cond:FeatureFlagCondition(NewExperience)\u0022\n xmlns:legacy=\u0022http://schemas.microsoft.com/winfx/2006/xaml/presentation?cond:FeatureFlagCondition(LegacyMode)\u0022\u003E\n\n \u003C!--\n At most ONE of newExp:Background and legacy:Background may evaluate to true at a time.\n If both conditions are true, the XAML parser throws at runtime.\n --\u003E\n \u003CButton Content=\u0022Background depends on the active flag\u0022\n newExp:Background=\u0022Green\u0022\n legacy:Background=\u0022Gray\u0022\n Foreground=\u0022White\u0022 /\u003E\n\u003C/Page\u003E","csharp":"// Conditional attributes use the same setup. Make sure that, for any\n// given attribute, no more than one condition can evaluate to true at\n// the same time - if multiple are true the XAML parser will throw at\n// runtime.\npublic sealed partial class MyPage : Page\n{\n public MyPage()\n {\n FeatureFlagCondition.FeatureFlags[\u0022NewExperience\u0022] = true;\n FeatureFlagCondition.FeatureFlags[\u0022LegacyMode\u0022] = false;\n\n this.InitializeComponent();\n }\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Define custom XAML conditions evaluated at parse time using IXamlCondition.","relatedControls":[],"apiNamespace":"Microsoft.UI.Xaml.Markup","docs":[{"title":"IXamlCondition - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.markup.ixamlcondition"}]},{"id":"customxamlconditionals-3","controlId":"customxamlconditionals","controlName":"XAML Conditions","headerText":"Conditional Setters in a Style","xaml":"\u003CPage\n xmlns=\u0022http://schemas.microsoft.com/winfx/2006/xaml/presentation\u0022\n xmlns:cond=\u0022using:WinUIGallery.ControlPages\u0022\n xmlns:newExp=\u0022http://schemas.microsoft.com/winfx/2006/xaml/presentation?cond:FeatureFlagCondition(NewExperience)\u0022\n xmlns:legacy=\u0022http://schemas.microsoft.com/winfx/2006/xaml/presentation?cond:FeatureFlagCondition(LegacyMode)\u0022\u003E\n\n \u003CPage.Resources\u003E\n \u003CStyle x:Key=\u0022ConditionalHeadingStyle\u0022 TargetType=\u0022TextBlock\u0022\u003E\n \u003C!-- Setters can also be qualified with a conditional namespace. --\u003E\n \u003CnewExp:Setter Property=\u0022FontWeight\u0022 Value=\u0022SemiBold\u0022 /\u003E\n \u003CnewExp:Setter Property=\u0022FontSize\u0022 Value=\u002228\u0022 /\u003E\n \u003Clegacy:Setter Property=\u0022FontWeight\u0022 Value=\u0022Normal\u0022 /\u003E\n \u003Clegacy:Setter Property=\u0022FontSize\u0022 Value=\u002218\u0022 /\u003E\n \u003C/Style\u003E\n \u003C/Page.Resources\u003E\n\n \u003CTextBlock Text=\u0022Heading styled with conditional Setters\u0022\n Style=\u0022{StaticResource ConditionalHeadingStyle}\u0022 /\u003E\n\u003C/Page\u003E","csharp":"// Conditional Setters inside a Style are evaluated when the Style\n// resource is first parsed. Set the flags before InitializeComponent\n// (or before the resource dictionary that contains the Style is\n// loaded) so the parser produces the Style you expect.\npublic sealed partial class MyPage : Page\n{\n public MyPage()\n {\n FeatureFlagCondition.FeatureFlags[\u0022NewExperience\u0022] = true;\n FeatureFlagCondition.FeatureFlags[\u0022LegacyMode\u0022] = false;\n\n this.InitializeComponent();\n }\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Define custom XAML conditions evaluated at parse time using IXamlCondition.","relatedControls":[],"apiNamespace":"Microsoft.UI.Xaml.Markup","docs":[{"title":"IXamlCondition - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.markup.ixamlcondition"}]},{"id":"geometry-1","controlId":"geometry","controlName":"Geometry","headerText":"Geometry","xaml":"\u003CGrid CornerRadius=\u0022{StaticResource OverlayCornerRadius}\u0022/\u003E\n\u003CGrid CornerRadius=\u0022{StaticResource ControlCornerRadius}\u0022/\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Clear geometric design ensures visual coherence and structure.","relatedControls":[],"apiNamespace":null,"docs":[{"title":"Geometry in Windows 11","uri":"https://learn.microsoft.com/windows/apps/design/signature-experiences/geometry"},{"title":"WinUI Theme Resources (GitHub)","uri":"https://github.com/microsoft/microsoft-ui-xaml/blob/main/controls/dev/CommonStyles/Common_themeresources_any.xaml"}]},{"id":"typography-1","controlId":"typography","controlName":"Typography","headerText":"Type ramp","xaml":"\u003CTextBlock Text=\u0022Caption\u0022 Style=\u0022{StaticResource CaptionTextBlockStyle}\u0022/\u003E\n\u003CTextBlock Text=\u0022Body\u0022 Style=\u0022{StaticResource BodyTextBlockStyle}\u0022/\u003E\n\u003CTextBlock Text=\u0022Body Strong\u0022 Style=\u0022{StaticResource BodyStrongTextBlockStyle}\u0022/\u003E\n\u003CTextBlock Text=\u0022Body Large\u0022 Style=\u0022{StaticResource BodyLargeTextBlockStyle}\u0022/\u003E\n\u003CTextBlock Text=\u0022Body Strong Strong\u0022 Style=\u0022{StaticResource BodyLargeStrongTextBlockStyle}\u0022/\u003E\n\u003CTextBlock Text=\u0022Subtitle\u0022 Style=\u0022{StaticResource SubtitleTextBlockStyle}\u0022/\u003E\n\u003CTextBlock Text=\u0022Title\u0022 Style=\u0022{StaticResource TitleTextBlockStyle}\u0022/\u003E\n\u003CTextBlock Text=\u0022Title Large\u0022 Style=\u0022{StaticResource TitleLargeTextBlockStyle}\u0022/\u003E\n\u003CTextBlock Text=\u0022Display\u0022 Style=\u0022{StaticResource DisplayTextBlockStyle}\u0022/\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Typography design guides attention with intuitive fonts and hierarchy.","relatedControls":[],"apiNamespace":null,"docs":[{"title":"Typography in Windows Apps","uri":"https://learn.microsoft.com/windows/apps/design/style/typography"},{"title":"XAML theme resources","uri":"https://learn.microsoft.com/windows/apps/design/style/xaml-theme-resources#the-xaml-type-ramp"},{"title":"Typography in Windows 11","uri":"https://learn.microsoft.com/windows/apps/design/signature-experiences/typography"}]},{"id":"accessibilitykeyboard-1","controlId":"accessibilitykeyboard","controlName":"Keyboard Navigation","headerText":"Non-interactive controls should not be in the tab order","xaml":"\u003CStackPanel Spacing=\u00224\u0022\u003E\n \u003CButton Content=\u0022First\u0022 /\u003E\n \u003C!-- Non-interactive controls should not be in the tab order --\u003E\n \u003CTextBlock Text=\u0022(not present)\u0022 /\u003E\n \u003CButton Content=\u0022Second\u0022 /\u003E\n \u003C!-- Disabled controls should not be in the tab order --\u003E\n \u003CButton Content=\u0022(not present)\u0022 IsEnabled=\u0022False\u0022 /\u003E\n \u003CButton Content=\u0022Third\u0022 /\u003E\n\u003C/StackPanel\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Keyboard-friendly design enables seamless interactions.","relatedControls":[],"apiNamespace":null,"docs":[{"title":"Accessibility","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/accessibility"},{"title":"Accessibility overview","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/accessibility-overview"},{"title":"Keyboard accessibility","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/keyboard-accessibility"},{"title":"Keyboard interactions","uri":"https://learn.microsoft.com/windows/apps/design/input/keyboard-interactions"},{"title":"Access keys","uri":"https://learn.microsoft.com/windows/apps/design/input/access-keys"},{"title":"Keyboard accelerators","uri":"https://learn.microsoft.com/windows/apps/design/input/keyboard-accelerators"},{"title":"Focus navigation for keyboard, gamepad, remote control, and accessibility tools","uri":"https://learn.microsoft.com/windows/apps/design/input/focus-navigation"},{"title":"Automation Properties - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.automation.automationproperties"}]},{"id":"accessibilitykeyboard-2","controlId":"accessibilitykeyboard","controlName":"Keyboard Navigation","headerText":"This example is a bit contrived, since you could fix the tab order by reordering the elements in the XAML, but sometimes\u2026","xaml":"\u003CGrid RowSpacing=\u00228\u0022 ColumnSpacing=\u00228\u0022\u003E\n \u003CGrid.RowDefinitions\u003E\n\t \u003CRowDefinition Height=\u0022Auto\u0022/\u003E\n\t \u003CRowDefinition Height=\u0022Auto\u0022/\u003E\n\t \u003CRowDefinition Height=\u0022Auto\u0022/\u003E\n \u003C/Grid.RowDefinitions\u003E\n \u003CGrid.ColumnDefinitions\u003E\n\t \u003CColumnDefinition Width=\u0022Auto\u0022/\u003E\n\t \u003CColumnDefinition Width=\u0022Auto\u0022/\u003E\n\t \u003CColumnDefinition Width=\u0022Auto\u0022/\u003E\n \u003C/Grid.ColumnDefinitions\u003E\n\n \u003CTextBlock Grid.Column=\u00221\u0022 HorizontalAlignment=\u0022Center\u0022 Text=\u0022Column 1\u0022/\u003E\n \u003CTextBlock Grid.Column=\u00222\u0022 HorizontalAlignment=\u0022Center\u0022 Text=\u0022Column 2\u0022/\u003E\n\n \u003C!--\n This example is a bit contrived, since you could fix the\n tab order by reordering the elements in the XAML, but\n sometimes that is not easy to do.\n --\u003E\n \u003CTextBlock Grid.Row=\u00221\u0022 VerticalAlignment=\u0022Center\u0022 Text=\u0022Row 1\u0022/\u003E\n \u003CButton Grid.Column=\u00221\u0022 Grid.Row=\u00221\u0022 Content=\u0022First stop\u0022 TabIndex=\u00221\u0022 HorizontalAlignment=\u0022Stretch\u0022/\u003E\n \u003CButton Grid.Column=\u00222\u0022 Grid.Row=\u00221\u0022 Content=\u0022Third stop\u0022 TabIndex=\u00223\u0022 HorizontalAlignment=\u0022Stretch\u0022/\u003E\n\n \u003CTextBlock Grid.Row=\u00222\u0022 VerticalAlignment=\u0022Center\u0022 Text=\u0022Row 2\u0022/\u003E\n \u003CButton Grid.Column=\u00221\u0022 Grid.Row=\u00222\u0022 Content=\u0022Second stop\u0022 TabIndex=\u00222\u0022 HorizontalAlignment=\u0022Stretch\u0022/\u003E\n \u003CButton Grid.Column=\u00222\u0022 Grid.Row=\u00222\u0022 Content=\u0022Not a stop\u0022 IsTabStop=\u0022False\u0022 HorizontalAlignment=\u0022Stretch\u0022/\u003E\n\u003C/Grid\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Keyboard-friendly design enables seamless interactions.","relatedControls":[],"apiNamespace":null,"docs":[{"title":"Accessibility","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/accessibility"},{"title":"Accessibility overview","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/accessibility-overview"},{"title":"Keyboard accessibility","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/keyboard-accessibility"},{"title":"Keyboard interactions","uri":"https://learn.microsoft.com/windows/apps/design/input/keyboard-interactions"},{"title":"Access keys","uri":"https://learn.microsoft.com/windows/apps/design/input/access-keys"},{"title":"Keyboard accelerators","uri":"https://learn.microsoft.com/windows/apps/design/input/keyboard-accelerators"},{"title":"Focus navigation for keyboard, gamepad, remote control, and accessibility tools","uri":"https://learn.microsoft.com/windows/apps/design/input/focus-navigation"},{"title":"Automation Properties - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.automation.automationproperties"}]},{"id":"accessibilitykeyboard-3","controlId":"accessibilitykeyboard","controlName":"Keyboard Navigation","headerText":"ListViews fully support arrow keys, for example","xaml":"\u003C!-- ListViews fully support arrow keys, for example --\u003E\n\u003CListView\n AutomationProperties.Name=\u0022Colors\u0022\u003E\n \u003CListViewItem\u003ERed\u003C/ListViewItem\u003E\n \u003CListViewItem\u003EBlue\u003C/ListViewItem\u003E\n \u003CListViewItem\u003EGreen\u003C/ListViewItem\u003E\n \u003CListViewItem\u003EYellow\u003C/ListViewItem\u003E\n\u003C/ListView\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Keyboard-friendly design enables seamless interactions.","relatedControls":[],"apiNamespace":null,"docs":[{"title":"Accessibility","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/accessibility"},{"title":"Accessibility overview","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/accessibility-overview"},{"title":"Keyboard accessibility","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/keyboard-accessibility"},{"title":"Keyboard interactions","uri":"https://learn.microsoft.com/windows/apps/design/input/keyboard-interactions"},{"title":"Access keys","uri":"https://learn.microsoft.com/windows/apps/design/input/access-keys"},{"title":"Keyboard accelerators","uri":"https://learn.microsoft.com/windows/apps/design/input/keyboard-accelerators"},{"title":"Focus navigation for keyboard, gamepad, remote control, and accessibility tools","uri":"https://learn.microsoft.com/windows/apps/design/input/focus-navigation"},{"title":"Automation Properties - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.automation.automationproperties"}]},{"id":"accessibilitykeyboard-4","controlId":"accessibilitykeyboard","controlName":"Keyboard Navigation","headerText":"XYFocusKeyboardNavigation enables arrow keys between the buttons","xaml":"\u003CStackPanel\n Background=\u0022{ThemeResource CardBackgroundFillColorSecondaryBrush}\u0022\n BorderBrush=\u0022{ThemeResource SurfaceStrokeColorDefaultBrush}\u0022\n AutomationProperties.Name=\u0022Potatoes?\u0022\n BorderThickness=\u00221\u0022\n Spacing=\u00228\u0022\n Padding=\u00228\u0022\n CornerRadius=\u00224\u0022\u003E\n \u003CTextBlock\n Style=\u0022{ThemeResource BodyStrongTextBlockStyle}\u0022\n Text=\u0022Potatoes?\u0022 /\u003E\n \u003C!--\n XYFocusKeyboardNavigation enables arrow keys between the buttons.\n\n Note that:\n\n - The buttons are still tabbable by default\n - Home/End and PgUp/PgDn do not work\n - Screen readers do not read PositionInSet/SizeOfSet (\u00221 of 3\u0022)\n\n All of that would require custom work.\n --\u003E\n \u003CStackPanel\n Spacing=\u00224\u0022\n Orientation=\u0022Horizontal\u0022\n XYFocusKeyboardNavigation=\u0022Enabled\u0022\u003E\n \u003CButton Content=\u0022Boil \u0027em\u0022 /\u003E\n \u003CButton Content=\u0022Mash \u0027em\u0022 /\u003E\n \u003CButton Content=\u0022Stick \u0027em in a stew\u0022 /\u003E\n \u003C/StackPanel\u003E\n\u003C/StackPanel\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Keyboard-friendly design enables seamless interactions.","relatedControls":[],"apiNamespace":null,"docs":[{"title":"Accessibility","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/accessibility"},{"title":"Accessibility overview","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/accessibility-overview"},{"title":"Keyboard accessibility","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/keyboard-accessibility"},{"title":"Keyboard interactions","uri":"https://learn.microsoft.com/windows/apps/design/input/keyboard-interactions"},{"title":"Access keys","uri":"https://learn.microsoft.com/windows/apps/design/input/access-keys"},{"title":"Keyboard accelerators","uri":"https://learn.microsoft.com/windows/apps/design/input/keyboard-accelerators"},{"title":"Focus navigation for keyboard, gamepad, remote control, and accessibility tools","uri":"https://learn.microsoft.com/windows/apps/design/input/focus-navigation"},{"title":"Automation Properties - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.automation.automationproperties"}]},{"id":"accessibilitykeyboard-5","controlId":"accessibilitykeyboard","controlName":"Keyboard Navigation","headerText":"Chartreuse is an uncommon color, so we explain it in the tooltip","xaml":"\u003CGrid ColumnSpacing=\u00228\u0022 RowSpacing=\u00228\u0022\u003E\n\u003CGrid.RowDefinitions\u003E\n\t\u003CRowDefinition Height=\u0022Auto\u0022 /\u003E\n\t\u003CRowDefinition Height=\u0022Auto\u0022 /\u003E\n\u003C/Grid.RowDefinitions\u003E\n\n\u003CGrid.ColumnDefinitions\u003E\n\t\u003CColumnDefinition Width=\u0022Auto\u0022/\u003E\n\t\u003CColumnDefinition Width=\u0022Auto\u0022/\u003E\n\t\u003CColumnDefinition Width=\u0022Auto\u0022/\u003E\n\u003C/Grid.ColumnDefinitions\u003E\n\n\u003CRectangle x:Name=\u0022ColorRectangle\u0022 Fill=\u0022Red\u0022\n\tGrid.ColumnSpan=\u00223\u0022/\u003E\n\n\u003CButton Click=\u0022MakeRedButton_Click\u0022 Content=\u0022Red\u0022 Grid.Row=\u00221\u0022\n\tToolTipService.ToolTip=\u0022Shortcut: Ctrl\u002BR\u0022\u003E\n\t\u003CButton.KeyboardAccelerators\u003E\n\t\t\u003CKeyboardAccelerator Modifiers=\u0022Control\u0022 Key=\u0022R\u0022 /\u003E\n\t\u003C/Button.KeyboardAccelerators\u003E\n\u003C/Button\u003E\n\t\n\u003CButton Click=\u0022MakeBlueButton_Click\u0022 Content=\u0022Blue\u0022\n\tGrid.Row=\u00221\u0022 Grid.Column=\u00221\u0022\n\tToolTipService.ToolTip=\u0022Shortcut: Ctrl\u002BB\u0022\u003E\n\t\u003CButton.KeyboardAccelerators\u003E\n\t\t\u003CKeyboardAccelerator Modifiers=\u0022Control\u0022 Key=\u0022B\u0022 /\u003E\n\t\u003C/Button.KeyboardAccelerators\u003E\n\u003C/Button\u003E\n\n\u003C!--\n Chartreuse is an uncommon color, so we explain it in the tooltip.\n This replaces the auto-generated tooltip, so we manually mention\n the hotkey in the custom tooltip.\n--\u003E\n\u003CButton Click=\u0022MakeChartreuseButton_Click\u0022 Content=\u0022Chartreuse\u0022\n\tGrid.Row=\u00221\u0022 Grid.Column=\u00221\u0022\n\tToolTipService.ToolTip=\u0022A greenish yellow (Ctrl\u002BG)\u0022\u003E\n\t\u003CButton.KeyboardAccelerators\u003E\n\t\t\u003CKeyboardAccelerator Modifiers=\u0022Control\u0022 Key=\u0022G\u0022 /\u003E\n\t\u003C/Button.KeyboardAccelerators\u003E\n\u003C/Button\u003E\n\u003C/Grid\u003E","csharp":"private void MakeRedButton_Click(object sender, RoutedEventArgs e)\n{\n ColorRectangle.Fill = new SolidColorBrush(Colors.Red);\n}\nprivate void MakeBlueButton_Click(object sender, RoutedEventArgs e)\n{\n ColorRectangle.Fill = new SolidColorBrush(Colors.Blue);\n}\nprivate void MakeChartreuseButton_Click(object sender, RoutedEventArgs e)\n{\n ColorRectangle.Fill = new SolidColorBrush(Colors.Chartreuse);\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Keyboard-friendly design enables seamless interactions.","relatedControls":[],"apiNamespace":null,"docs":[{"title":"Accessibility","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/accessibility"},{"title":"Accessibility overview","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/accessibility-overview"},{"title":"Keyboard accessibility","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/keyboard-accessibility"},{"title":"Keyboard interactions","uri":"https://learn.microsoft.com/windows/apps/design/input/keyboard-interactions"},{"title":"Access keys","uri":"https://learn.microsoft.com/windows/apps/design/input/access-keys"},{"title":"Keyboard accelerators","uri":"https://learn.microsoft.com/windows/apps/design/input/keyboard-accelerators"},{"title":"Focus navigation for keyboard, gamepad, remote control, and accessibility tools","uri":"https://learn.microsoft.com/windows/apps/design/input/focus-navigation"},{"title":"Automation Properties - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.automation.automationproperties"}]},{"id":"accessibilitykeyboard-6","controlId":"accessibilitykeyboard","controlName":"Keyboard Navigation","headerText":"Keyboard-friendly design enables seamless interactions.","xaml":"\u003CMenuBar\u003E\n \u003CMenuBarItem Title=\u0022File\u0022 AccessKey=\u0022F\u0022\u003E\n \u003CMenuFlyoutItem Text=\u0022New\u0022 AccessKey=\u0022N\u0022 /\u003E\n \u003CMenuFlyoutItem Text=\u0022Open...\u0022 AccessKey=\u0022O\u0022 /\u003E\n \u003CMenuFlyoutItem Text=\u0022Save\u0022 AccessKey=\u0022S\u0022 /\u003E\n \u003CMenuFlyoutItem Text=\u0022Exit\u0022 AccessKey=\u0022E\u0022 /\u003E\n \u003C/MenuBarItem\u003E\n\n \u003CMenuBarItem Title=\u0022Edit\u0022 AccessKey=\u0022E\u0022\u003E\n \u003CMenuFlyoutItem Text=\u0022Undo\u0022 AccessKey=\u0022U\u0022 /\u003E\n \u003CMenuFlyoutItem Text=\u0022Cut\u0022 AccessKey=\u0022X\u0022 /\u003E\n \u003CMenuFlyoutItem Text=\u0022Copy\u0022 AccessKey=\u0022C\u0022 /\u003E\n \u003CMenuFlyoutItem Text=\u0022Paste\u0022 AccessKey=\u0022V\u0022 /\u003E\n \u003C/MenuBarItem\u003E\n\n \u003CMenuBarItem Title=\u0022Help\u0022 AccessKey=\u0022H\u0022\u003E\n \u003CMenuFlyoutItem Text=\u0022About\u0022 AccessKey=\u0022A\u0022 /\u003E\n \u003C/MenuBarItem\u003E\n\u003C/MenuBar\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Keyboard-friendly design enables seamless interactions.","relatedControls":[],"apiNamespace":null,"docs":[{"title":"Accessibility","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/accessibility"},{"title":"Accessibility overview","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/accessibility-overview"},{"title":"Keyboard accessibility","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/keyboard-accessibility"},{"title":"Keyboard interactions","uri":"https://learn.microsoft.com/windows/apps/design/input/keyboard-interactions"},{"title":"Access keys","uri":"https://learn.microsoft.com/windows/apps/design/input/access-keys"},{"title":"Keyboard accelerators","uri":"https://learn.microsoft.com/windows/apps/design/input/keyboard-accelerators"},{"title":"Focus navigation for keyboard, gamepad, remote control, and accessibility tools","uri":"https://learn.microsoft.com/windows/apps/design/input/focus-navigation"},{"title":"Automation Properties - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.automation.automationproperties"}]},{"id":"accessibilityscreenreader-1","controlId":"accessibilityscreenreader","controlName":"Screen Reader","headerText":"Most controls automatically get names from their content","xaml":"\u003C!-- Most controls automatically get names from their content --\u003E\n\u003CButton Content=\u0022Download survey\u0022 /\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Inclusive design ensures meaningful content for assistive technologies.","relatedControls":[],"apiNamespace":null,"docs":[{"title":"Accessibility","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/accessibility"},{"title":"Accessibility overview","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/accessibility-overview"},{"title":"Expose basic accessibility information","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/basic-accessibility-information"},{"title":"Landmarks and Headings","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/landmarks-and-headings"},{"title":"Accessible text requirements","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/accessible-text-requirements"},{"title":"Complete guide to Narrator","uri":"https://support.microsoft.com/windows/complete-guide-to-narrator-e4397a0d-ef4f-b386-d8ae-c172f109bdb1"}]},{"id":"accessibilityscreenreader-2","controlId":"accessibilityscreenreader","controlName":"Screen Reader","headerText":"Headers are promoted to name","xaml":"\u003C!-- Headers are promoted to name --\u003E\n\u003CTextBox Header=\u0022Name\u0022 /\u003E\n\n\u003C!-- As are placeholders --\u003E\n\u003CTextBox PlaceholderText=\u0022Nickname\u0022 /\u003E\n\n\u003C!-- If both are provided, headers are name and placeholders are moved to description --\u003E\n\u003CTextBox Header=\u0022Email\u0022 PlaceholderText=\u0022test@example.com\u0022 MinWidth=\u0022200\u0022 /\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Inclusive design ensures meaningful content for assistive technologies.","relatedControls":[],"apiNamespace":null,"docs":[{"title":"Accessibility","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/accessibility"},{"title":"Accessibility overview","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/accessibility-overview"},{"title":"Expose basic accessibility information","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/basic-accessibility-information"},{"title":"Landmarks and Headings","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/landmarks-and-headings"},{"title":"Accessible text requirements","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/accessible-text-requirements"},{"title":"Complete guide to Narrator","uri":"https://support.microsoft.com/windows/complete-guide-to-narrator-e4397a0d-ef4f-b386-d8ae-c172f109bdb1"}]},{"id":"accessibilityscreenreader-3","controlId":"accessibilityscreenreader","controlName":"Screen Reader","headerText":"Add a name to this ListView to be heard when screen reader users enter it","xaml":"\u003C!-- Add a name to this ListView to be heard when screen reader users enter it --\u003E\n\u003CListView Width=\u0022300\u0022\nAutomationProperties.Name=\u0022Contacts\u0022\u003E\n\u003CListViewItem\u003ENathan Quinn\u003C/ListViewItem\u003E\n\u003CListViewItem\u003EJessica Lamber\u003C/ListViewItem\u003E\n\u003CListViewItem\u003ECarl Bond\u003C/ListViewItem\u003E\n\u003CListViewItem\u003EJessica Russel\u003C/ListViewItem\u003E\n\u003C/ListView\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Inclusive design ensures meaningful content for assistive technologies.","relatedControls":[],"apiNamespace":null,"docs":[{"title":"Accessibility","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/accessibility"},{"title":"Accessibility overview","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/accessibility-overview"},{"title":"Expose basic accessibility information","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/basic-accessibility-information"},{"title":"Landmarks and Headings","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/landmarks-and-headings"},{"title":"Accessible text requirements","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/accessible-text-requirements"},{"title":"Complete guide to Narrator","uri":"https://support.microsoft.com/windows/complete-guide-to-narrator-e4397a0d-ef4f-b386-d8ae-c172f109bdb1"}]},{"id":"accessibilityscreenreader-4","controlId":"accessibilityscreenreader","controlName":"Screen Reader","headerText":"Add \u0022alt text\u0022 to this image so screen reader users can understand it","xaml":"\u003C!-- Add \u0022alt text\u0022 to this image so screen reader users can understand it --\u003E\n\u003CImage AutomationProperties.Name=\u0022Grapes\u0022 Source=\u0022ms-appx:///Assets/YourImage.png\u0022/\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Inclusive design ensures meaningful content for assistive technologies.","relatedControls":[],"apiNamespace":null,"docs":[{"title":"Accessibility","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/accessibility"},{"title":"Accessibility overview","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/accessibility-overview"},{"title":"Expose basic accessibility information","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/basic-accessibility-information"},{"title":"Landmarks and Headings","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/landmarks-and-headings"},{"title":"Accessible text requirements","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/accessible-text-requirements"},{"title":"Complete guide to Narrator","uri":"https://support.microsoft.com/windows/complete-guide-to-narrator-e4397a0d-ef4f-b386-d8ae-c172f109bdb1"}]},{"id":"accessibilityscreenreader-5","controlId":"accessibilityscreenreader","controlName":"Screen Reader","headerText":"Inclusive design ensures meaningful content for assistive technologies.","xaml":"\u003CTextBlock x:Name=\u0022InputLabel\u0022 AutomationProperties.AccessibilityView=\u0022Raw\u0022 Text=\u0022Searching Photos:\u0022/\u003E\n\u003CTextBox AutomationProperties.LabeledBy=\u0022{x:Bind InputLabel}\u0022/\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Inclusive design ensures meaningful content for assistive technologies.","relatedControls":[],"apiNamespace":null,"docs":[{"title":"Accessibility","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/accessibility"},{"title":"Accessibility overview","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/accessibility-overview"},{"title":"Expose basic accessibility information","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/basic-accessibility-information"},{"title":"Landmarks and Headings","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/landmarks-and-headings"},{"title":"Accessible text requirements","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/accessible-text-requirements"},{"title":"Complete guide to Narrator","uri":"https://support.microsoft.com/windows/complete-guide-to-narrator-e4397a0d-ef4f-b386-d8ae-c172f109bdb1"}]},{"id":"accessibilityscreenreader-6","controlId":"accessibilityscreenreader","controlName":"Screen Reader","headerText":"Description and help text: add descriptions and help text to controls","xaml":"\u003CStackPanel Spacing=\u00228\u0022\u003E\n \u003C!-- Use FullDescription to connect visible descriptions to their controls --\u003E\n \u003CStackPanel Spacing=\u00228\u0022\u003E\n \u003CCheckBox Content=\u0022Clear cache on exit\u0022\n AutomationProperties.FullDescription=\u0022{x:Bind ClearCacheDescription.Text}\u0022 /\u003E\n \u003CTextBlock x:Name=\u0022ClearCacheDescription\u0022\n Text=\u0022Deletes all cached items when closing the browser. This includes cookies, images, and browsing history.\u0022\n AutomationProperties.AccessibilityView=\u0022Raw\u0022\n Foreground=\u0022{ThemeResource TextFillColorSecondaryBrush}\u0022 /\u003E\n \u003C/StackPanel\u003E\n\n \u003C!-- Use HelpText and/or tooltips to explain nuances of controls --\u003E\n \u003CButton Content=\u0022Cancel RSS subscriptions\u0022\n ToolTipService.ToolTip=\u0022Launch the cancellation wizard\u0022\n AutomationProperties.HelpText=\u0022Launch the cancellation wizard\u0022 /\u003E\n\u003C/StackPanel\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Inclusive design ensures meaningful content for assistive technologies.","relatedControls":[],"apiNamespace":null,"docs":[{"title":"Accessibility","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/accessibility"},{"title":"Accessibility overview","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/accessibility-overview"},{"title":"Expose basic accessibility information","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/basic-accessibility-information"},{"title":"Landmarks and Headings","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/landmarks-and-headings"},{"title":"Accessible text requirements","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/accessible-text-requirements"},{"title":"Complete guide to Narrator","uri":"https://support.microsoft.com/windows/complete-guide-to-narrator-e4397a0d-ef4f-b386-d8ae-c172f109bdb1"}]},{"id":"accessibilityscreenreader-7","controlId":"accessibilityscreenreader","controlName":"Screen Reader","headerText":"Position in set: indicate the position of an element within a set","xaml":"\u003CStackPanel\u003E\n \u003C!-- Many controls automatically indicate position in set --\u003E\n \u003CTextBlock Text=\u0022Students\u0022\n Style=\u0022{ThemeResource BodyStrongTextBlockStyle}\u0022\n x:Name=\u0022StudentsLabel\u0022\n AutomationProperties.AccessibilityView=\u0022Raw\u0022 /\u003E\n \u003CListView AutomationProperties.LabeledBy=\u0022{x:Bind StudentsLabel}\u0022\u003E\n \u003CListView.ItemTemplate\u003E\n \u003CDataTemplate x:DataType=\u0022x:String\u0022\u003E\n \u003CTextBlock Text=\u0022{x:Bind}\u0022 /\u003E\n \u003C/DataTemplate\u003E\n \u003C/ListView.ItemTemplate\u003E\n \u003Cx:String\u003ENathan Quinn\u003C/x:String\u003E\n \u003Cx:String\u003EJessica Lamber\u003C/x:String\u003E\n \u003Cx:String\u003ECarl Bond\u003C/x:String\u003E\n \u003Cx:String\u003EJessica Russel\u003C/x:String\u003E\n \u003C/ListView\u003E\n\n \u003C!-- Custom layouts may need to specify PositionInSet and SizeOfSet manually. --\u003E\n \u003CStackPanel Orientation=\u0022Horizontal\u0022\n Spacing=\u00228\u0022\u003E\n \u003CButton AutomationProperties.PositionInSet=\u00221\u0022\n AutomationProperties.SizeOfSet=\u00223\u0022\n Content=\u0022View\u0022 /\u003E\n \u003CButton AutomationProperties.PositionInSet=\u00222\u0022\n AutomationProperties.SizeOfSet=\u00223\u0022\n Content=\u0022Rename\u0022 /\u003E\n \u003CButton AutomationProperties.PositionInSet=\u00223\u0022\n AutomationProperties.SizeOfSet=\u00223\u0022\n Content=\u0022Delete\u0022 /\u003E\n \u003C/StackPanel\u003E\n\u003C/StackPanel\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Inclusive design ensures meaningful content for assistive technologies.","relatedControls":[],"apiNamespace":null,"docs":[{"title":"Accessibility","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/accessibility"},{"title":"Accessibility overview","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/accessibility-overview"},{"title":"Expose basic accessibility information","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/basic-accessibility-information"},{"title":"Landmarks and Headings","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/landmarks-and-headings"},{"title":"Accessible text requirements","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/accessible-text-requirements"},{"title":"Complete guide to Narrator","uri":"https://support.microsoft.com/windows/complete-guide-to-narrator-e4397a0d-ef4f-b386-d8ae-c172f109bdb1"}]},{"id":"accessibilityscreenreader-8","controlId":"accessibilityscreenreader","controlName":"Screen Reader","headerText":"Remove a control from the content visual tree","xaml":"\u003CStackPanel Orientation=\u0022Horizontal\u0022\u003E\n\u003C!-- The image is not necessary for screen readers as it does not contain any information.\n Thus we remove it from the content visual tree with AccessibilityView=\u0022Raw\u0022 --\u003E\n\u003CImage Source=\u0022/Assets/SampleMedia/treetops.jpg\u0022 AutomationProperties.AccessibilityView=\u0022Raw\u0022 Height=\u002240\u0022 VerticalAlignment=\u0022Top\u0022/\u003E\n\u003CTextBlock TextWrapping=\u0022WrapWholeWords\u0022 MaxWidth=\u0022400\u0022 Margin=\u00228,0,0,0\u0022\u003EThis is some demo text.\n The image on the left is just for decoration and serves no informational purpose.\n To prevent Narrator or other screen readers from reading out the image, we set the accessibility view to \u0022Raw\u0022 which removes it from the content visual tree.\u003C/TextBlock\u003E\n\u003C/StackPanel\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Inclusive design ensures meaningful content for assistive technologies.","relatedControls":[],"apiNamespace":null,"docs":[{"title":"Accessibility","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/accessibility"},{"title":"Accessibility overview","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/accessibility-overview"},{"title":"Expose basic accessibility information","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/basic-accessibility-information"},{"title":"Landmarks and Headings","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/landmarks-and-headings"},{"title":"Accessible text requirements","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/accessible-text-requirements"},{"title":"Complete guide to Narrator","uri":"https://support.microsoft.com/windows/complete-guide-to-narrator-e4397a0d-ef4f-b386-d8ae-c172f109bdb1"}]},{"id":"accessibilityscreenreader-9","controlId":"accessibilityscreenreader","controlName":"Screen Reader","headerText":"The navigation pane for our app","xaml":"\u003CGrid\u003E\n \u003CGrid.ColumnDefinitions\u003E\n \u003CColumnDefinition Width=\u0022200\u0022 /\u003E\n \u003CColumnDefinition Width=\u0022*\u0022 /\u003E\n \u003CColumnDefinition Width=\u0022200\u0022 /\u003E\n \u003C/Grid.ColumnDefinitions\u003E\n\n \u003C!-- The navigation pane for our app --\u003E\n \u003CStackPanel\n Grid.Column=\u00220\u0022\n Spacing=\u00228\u0022\n Padding=\u00226\u0022\n Background=\u0022{ThemeResource CardStrokeColorDefaultBrush}\u0022\n CornerRadius=\u0022{StaticResource ControlCornerRadius}\u0022\n AutomationProperties.LandmarkType=\u0022Navigation\u0022\u003E\n \u003CAutoSuggestBox\n PlaceholderText=\u0022Search\u0022\n AutomationProperties.LandmarkType=\u0022Search\u0022/\u003E\n \u003CButton Content=\u0022Open settings\u0022 /\u003E\n \u003C/StackPanel\u003E\n\n \u003C!-- The main content of our app --\u003E\n \u003CStackPanel\n Grid.Column=\u00221\u0022\n Padding=\u00226\u0022\n AutomationProperties.LandmarkType=\u0022Main\u0022\u003E\n \u003CTextBlock TextWrapping=\u0022WrapWholeWords\u0022\u003E\n Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\n Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\n Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.\n Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum\n \u003C/TextBlock\u003E\n \u003C/StackPanel\u003E\n\n \u003C!-- A custom sidebar with a custom landmark name --\u003E\n \u003CStackPanel\n Grid.Column=\u00222\u0022\n Padding=\u00226\u0022\n Background=\u0022{ThemeResource CardStrokeColorDefaultBrush}\u0022\n CornerRadius=\u0022{StaticResource ControlCornerRadius}\u0022\n Spacing=\u00228\u0022\n AutomationProperties.LandmarkType=\u0022Custom\u0022\n AutomationProperties.LocalizedLandmarkType=\u0022Current viewers\u0022\u003E\n \u003CTextBlock\n Text=\u0022Current viewers\u0022\n Style=\u0022{ThemeResource BodyStrongTextBlockStyle}\u0022\n AutomationProperties.HeadingLevel=\u0022Level1\u0022 /\u003E\u003C/StackPanel\u003E\u003C/Grid\u003E\n\u003C!-- ...truncated --\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Inclusive design ensures meaningful content for assistive technologies.","relatedControls":[],"apiNamespace":null,"docs":[{"title":"Accessibility","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/accessibility"},{"title":"Accessibility overview","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/accessibility-overview"},{"title":"Expose basic accessibility information","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/basic-accessibility-information"},{"title":"Landmarks and Headings","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/landmarks-and-headings"},{"title":"Accessible text requirements","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/accessible-text-requirements"},{"title":"Complete guide to Narrator","uri":"https://support.microsoft.com/windows/complete-guide-to-narrator-e4397a0d-ef4f-b386-d8ae-c172f109bdb1"}]},{"id":"accessibilityscreenreader-10","controlId":"accessibilityscreenreader","controlName":"Screen Reader","headerText":"Here is the main header for the whole text","xaml":"\u003CStackPanel MaxWidth=\u0022500\u0022\u003E\n\u003C!-- Here is the main header for the whole text. It gets HeadingLevel 1 --\u003E\n\u003CTextBlock AutomationProperties.HeadingLevel=\u0022Level1\u0022 FontSize=\u002226\u0022\u003ELorem ipsums\u003C/TextBlock\u003E\n\u003C!-- The following TextBlock is the header for the standard lorem ipsum text, thus it is only HeadingLevel 2--\u003E\n\u003CTextBlock AutomationProperties.HeadingLevel=\u0022Level2\u0022 FontSize=\u002222\u0022\u003ELorem ipsum\u003C/TextBlock\u003E\n\u003CTextBlock TextWrapping=\u0022WrapWholeWords\u0022\u003ELorem ipsum dolor sit amet, consectetur adipiscing elit. \n Pellentesque feugiat velit pulvinar, vehicula nisi at, molestie risus. \n Duis consequat auctor libero vitae consectetur. Nullam efficitur euismod lacinia.\u003C/TextBlock\u003E\n \n\u003CTextBlock AutomationProperties.HeadingLevel=\u0022Level2\u0022 FontSize=\u002222\u0022\u003ECat ipsum\u003C/TextBlock\u003E\n\u003C!-- This is the header for the standard cat ipsum section, which is hierarchically below the cat ipsum header, resulting in HeadingLevel 3 --\u003E\n\u003CTextBlock AutomationProperties.HeadingLevel=\u00223\u0022 FontSize=\u002218\u0022\u003EStandard\u003C/TextBlock\u003E\n\u003CTextBlock TextWrapping=\u0022WrapWholeWords\u0022\u003EMice litter kitter kitty litty little kitten big roar roar feed me \n but i will ruin the couch with my claws and hunt by meowing loudly at 5am next to human.\u003C/TextBlock\u003E\n\u003CTextBlock AutomationProperties.HeadingLevel=\u00223\u0022 FontSize=\u002218\u0022\u003ECat breeds\u003C/TextBlock\u003E\n\u003CTextBlock TextWrapping=\u0022WrapWholeWords\u0022\u003ETabby abyssinian for jaguar. Thai russian blue and ragdoll, ocicat. \n Mouser puma so american bobtail for donskoy balinese . Scottish fold manx so siamese.\u003C/TextBlock\u003E\n \n\u003CTextBlock AutomationProperties.HeadingLevel=\u00222\u0022 FontSize=\u002222\u0022\u003EBacon ipsum\u003C/TextBlock\u003E\n\u003CTextBlock TextWrapping=\u0022WrapWholeWords\u0022\u003EBacon ipsum dolor amet meatball nulla labore, \n tempor sirloin chicken frankfurter tail drumstick ex cupim ground round.\u003C/TextBlock\u003E\n\u003C/StackPanel\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Inclusive design ensures meaningful content for assistive technologies.","relatedControls":[],"apiNamespace":null,"docs":[{"title":"Accessibility","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/accessibility"},{"title":"Accessibility overview","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/accessibility-overview"},{"title":"Expose basic accessibility information","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/basic-accessibility-information"},{"title":"Landmarks and Headings","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/landmarks-and-headings"},{"title":"Accessible text requirements","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/accessible-text-requirements"},{"title":"Complete guide to Narrator","uri":"https://support.microsoft.com/windows/complete-guide-to-narrator-e4397a0d-ef4f-b386-d8ae-c172f109bdb1"}]},{"id":"accessibilityscreenreader-11","controlId":"accessibilityscreenreader","controlName":"Screen Reader","headerText":"These TextBlocks could reasonably be headings, too","xaml":"\u003CStackPanel AutomationProperties.Name=\u0022Album browser\u0022\u003E\n \u003CStackPanel AutomationProperties.Name=\u0022My albums\u0022\u003E\n \u003C!-- These TextBlocks could reasonably be headings, too. --\u003E\n \u003CTextBlock\n Text=\u0022My albums\u0022\n Style=\u0022{ThemeResource BodyStrongTextBlockStyle}\u0022 /\u003E\n \u003CListView\u003E\n \u003Cx:String\u003ETrip to Redmond\u003C/x:String\u003E\n \u003Cx:String\u003EVisiting Ben\u003C/x:String\u003E\n \u003C/ListView\u003E\n \u003C/StackPanel\u003E\n \u003CStackPanel AutomationProperties.Name=\u0022Shared with me\u0022\u003E\n \u003CTextBlock\n Text=\u0022Shared with me\u0022\n Style=\u0022{ThemeResource BodyStrongTextBlockStyle}\u0022 /\u003E\n \u003CListView\u003E\n \u003Cx:String\u003EPaul\u0027s winter vacation\u003C/x:String\u003E\n \u003Cx:String\u003ECool street photography\u003C/x:String\u003E\n \u003Cx:String\u003EValeria\u0027s cat\u003C/x:String\u003E\n \u003C/ListView\u003E\n \u003C/StackPanel\u003E\n\u003C/StackPanel\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Inclusive design ensures meaningful content for assistive technologies.","relatedControls":[],"apiNamespace":null,"docs":[{"title":"Accessibility","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/accessibility"},{"title":"Accessibility overview","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/accessibility-overview"},{"title":"Expose basic accessibility information","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/basic-accessibility-information"},{"title":"Landmarks and Headings","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/landmarks-and-headings"},{"title":"Accessible text requirements","uri":"https://learn.microsoft.com/windows/apps/design/accessibility/accessible-text-requirements"},{"title":"Complete guide to Narrator","uri":"https://support.microsoft.com/windows/complete-guide-to-narrator-e4397a0d-ef4f-b386-d8ae-c172f109bdb1"}]},{"id":"appbarbutton-1","controlId":"appbarbutton","controlName":"AppBarButton","headerText":"An AppBarButton with a symbol icon.","xaml":"\u003CAppBarButton Icon=\u0022Like\u0022 Label=\u0022SymbolIcon\u0022 Click=\u0022AppBarButton_Click\u0022/\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A button that\u0027s styled for use in a CommandBar.","relatedControls":["AppBarToggleButton","AppBarSeparator","CommandBar"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"AppBarButton - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.appbarbutton"},{"title":"SymbolIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.symbolicon"},{"title":"FontIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.fonticon"},{"title":"BitmapIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.bitmapicon"},{"title":"PathIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.pathicon"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/command-bar"}]},{"id":"appbarbutton-2","controlId":"appbarbutton","controlName":"AppBarButton","headerText":"An AppBarButton with a bitmap icon.","xaml":"\u003CAppBarButton Label=\u0022BitmapIcon\u0022 Click=\u0022AppBarButton_Click\u0022\u003E\n \u003CAppBarButton.Icon\u003E\n \u003CBitmapIcon UriSource=\u0022ms-appx:///Assets/YourImage.png\u0022/\u003E\n \u003C/AppBarButton.Icon\u003E\n\u003C/AppBarButton\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A button that\u0027s styled for use in a CommandBar.","relatedControls":["AppBarToggleButton","AppBarSeparator","CommandBar"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"AppBarButton - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.appbarbutton"},{"title":"SymbolIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.symbolicon"},{"title":"FontIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.fonticon"},{"title":"BitmapIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.bitmapicon"},{"title":"PathIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.pathicon"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/command-bar"}]},{"id":"appbarbutton-3","controlId":"appbarbutton","controlName":"AppBarButton","headerText":"An AppBarButton with a font icon.","xaml":"\u003CAppBarButton Label=\u0022FontIcon\u0022 Click=\u0022AppBarButton_Click\u0022\u003E\n \u003CAppBarButton.Icon\u003E\n \u003CFontIcon FontFamily=\u0022Candara\u0022 Glyph=\u0022\u0026#x03A3;\u0022/\u003E\n \u003C/AppBarButton.Icon\u003E\n\u003C/AppBarButton\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A button that\u0027s styled for use in a CommandBar.","relatedControls":["AppBarToggleButton","AppBarSeparator","CommandBar"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"AppBarButton - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.appbarbutton"},{"title":"SymbolIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.symbolicon"},{"title":"FontIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.fonticon"},{"title":"BitmapIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.bitmapicon"},{"title":"PathIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.pathicon"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/command-bar"}]},{"id":"appbarbutton-4","controlId":"appbarbutton","controlName":"AppBarButton","headerText":"An AppBarButton with a path icon.","xaml":"\u003CAppBarButton Label=\u0022PathIcon\u0022 Click=\u0022AppBarButton_Click\u0022\u003E\n \u003CAppBarButton.Content\u003E\n \u003CViewbox Stretch=\u0022Uniform\u0022\u003E\n \u003CPathIcon Data=\u0022F1 M 20,20L 24,10L 24,24L 5,24\u0022/\u003E\n \u003C/Viewbox\u003E\n \u003C/AppBarButton.Content\u003E\n\u003C/AppBarButton\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A button that\u0027s styled for use in a CommandBar.","relatedControls":["AppBarToggleButton","AppBarSeparator","CommandBar"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"AppBarButton - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.appbarbutton"},{"title":"SymbolIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.symbolicon"},{"title":"FontIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.fonticon"},{"title":"BitmapIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.bitmapicon"},{"title":"PathIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.pathicon"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/command-bar"}]},{"id":"appbarbutton-5","controlId":"appbarbutton","controlName":"AppBarButton","headerText":"An AppBarButton with a KeyboardAccelerator","xaml":"\u003CAppBarButton Icon=\u0022Save\u0022 Label=\u0022Save\u0022 Click=\u0022AppBarButton_Click\u0022\u003E\n \u003CAppBarButton.KeyboardAccelerators\u003E\n \u003CKeyboardAccelerator Modifiers=\u0022Control\u0022 Key=\u0022S\u0022/\u003E\n \u003CAppBarButton.KeyboardAccelerators/\u003E\n\u003C/AppBarButton\u003E\u003C/AppBarButton.KeyboardAccelerators\u003E\u003C/AppBarButton\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A button that\u0027s styled for use in a CommandBar.","relatedControls":["AppBarToggleButton","AppBarSeparator","CommandBar"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"AppBarButton - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.appbarbutton"},{"title":"SymbolIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.symbolicon"},{"title":"FontIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.fonticon"},{"title":"BitmapIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.bitmapicon"},{"title":"PathIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.pathicon"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/command-bar"}]},{"id":"appbarbutton-6","controlId":"appbarbutton","controlName":"AppBarButton","headerText":"An AppBarButton that opens a Flyout containing an input control.","xaml":"\u003CAppBarButton\n AllowFocusOnInteraction=\u0022True\u0022\n Icon=\u0022Edit\u0022\n Label=\u0022Edit\u0022\u003E\n \u003CAppBarButton.Flyout\u003E\n \u003CFlyout\u003E\n \u003CTextBox MinWidth=\u0022240\u0022 PlaceholderText=\u0022Input text here\u0022 /\u003E\n \u003C/Flyout\u003E\n \u003C/AppBarButton.Flyout\u003E\n\u003C/AppBarButton\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A button that\u0027s styled for use in a CommandBar.","relatedControls":["AppBarToggleButton","AppBarSeparator","CommandBar"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"AppBarButton - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.appbarbutton"},{"title":"SymbolIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.symbolicon"},{"title":"FontIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.fonticon"},{"title":"BitmapIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.bitmapicon"},{"title":"PathIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.pathicon"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/command-bar"}]},{"id":"appbarseparator-1","controlId":"appbarseparator","controlName":"AppBarSeparator","headerText":"AppBarButtons separated by AppBarSeparators.","xaml":"\u003CCommandBar\u003E\n \u003CCommandBar.PrimaryCommands\u003E\n \u003CAppBarButton Icon=\u0022AttachCamera\u0022 Label=\u0022Attach Camera\u0022/\u003E\n \u003CAppBarSeparator /\u003E\n \u003CAppBarButton Icon=\u0022Like\u0022 Label=\u0022Like\u0022/\u003E\n \u003CAppBarButton Icon=\u0022Dislike\u0022 Label=\u0022Dislike\u0022/\u003E\n \u003CAppBarSeparator /\u003E\n \u003CAppBarButton Icon=\u0022Orientation\u0022 Label=\u0022Orientation\u0022/\u003E\n \u003C/CommandBar.PrimaryCommands\u003E\n\u003C/CommandBar\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A vertical line that\u0027s used to visually separate groups of commands in an app bar.","relatedControls":["AppBarButton","AppBarToggleButton","CommandBar"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"AppBarSeparator - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.appbarseparator"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/command-bar"}]},{"id":"appbartogglebutton-1","controlId":"appbartogglebutton","controlName":"AppBarToggleButton","headerText":"An AppBarToggleButton with a symbol icon.","xaml":"\u003CAppBarToggleButton Icon=\u0022Shuffle\u0022 Label=\u0022SymbolIcon\u0022 Click=\u0022AppBarButton_Click\u0022/\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A button that can be on, off, or indeterminate like a CheckBox, and is styled for use in an app bar or other specialized UI.","relatedControls":["AppBarButton","AppBarSeparator","CommandBar"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"AppBarToggleButton - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.appbartogglebutton"},{"title":"SymbolIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.symbolicon"},{"title":"FontIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.fonticon"},{"title":"BitmapIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.bitmapicon"},{"title":"PathIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.pathicon"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/command-bar"}]},{"id":"appbartogglebutton-2","controlId":"appbartogglebutton","controlName":"AppBarToggleButton","headerText":"An AppBarToggleButton with a bitmap icon.","xaml":"\u003CAppBarToggleButton Label=\u0022BitmapIcon\u0022 Click=\u0022AppBarButton_Click\u0022\u003E\n \u003CAppBarToggleButton.Icon\u003E\n \u003CBitmapIcon UriSource=\u0022ms-appx:///Assets/YourImage.png\u0022/\u003E\n \u003C/AppBarToggleButton.Icon\u003E\n\u003C/AppBarToggleButton\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A button that can be on, off, or indeterminate like a CheckBox, and is styled for use in an app bar or other specialized UI.","relatedControls":["AppBarButton","AppBarSeparator","CommandBar"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"AppBarToggleButton - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.appbartogglebutton"},{"title":"SymbolIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.symbolicon"},{"title":"FontIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.fonticon"},{"title":"BitmapIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.bitmapicon"},{"title":"PathIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.pathicon"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/command-bar"}]},{"id":"appbartogglebutton-3","controlId":"appbartogglebutton","controlName":"AppBarToggleButton","headerText":"An AppBarToggleButton with a font icon.","xaml":"\u003CAppBarToggleButton Label=\u0022FontIcon\u0022 Click=\u0022AppBarButton_Click\u0022\u003E\n \u003CAppBarToggleButton.Icon\u003E\n \u003CFontIcon FontFamily=\u0022Candara\u0022 Glyph=\u0022\u0026#x03A3;\u0022/\u003E\n \u003C/AppBarToggleButton.Icon\u003E\n\u003C/AppBarToggleButton\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A button that can be on, off, or indeterminate like a CheckBox, and is styled for use in an app bar or other specialized UI.","relatedControls":["AppBarButton","AppBarSeparator","CommandBar"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"AppBarToggleButton - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.appbartogglebutton"},{"title":"SymbolIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.symbolicon"},{"title":"FontIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.fonticon"},{"title":"BitmapIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.bitmapicon"},{"title":"PathIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.pathicon"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/command-bar"}]},{"id":"appbartogglebutton-4","controlId":"appbartogglebutton","controlName":"AppBarToggleButton","headerText":"A three-state AppBarToggleButton with a path icon.","xaml":"\u003CAppBarToggleButton Label=\u0022PathIcon\u0022 Click=\u0022AppBarButton_Click\u0022 IsThreeState=\u0022True\u0022\u003E\n \u003CAppBarToggleButton.Icon\u003E\n \u003CPathIcon Data=\u0022F1 M 20,20L 24,10L 24,24L 5,24\u0022/\u003E\n \u003C/AppBarToggleButton.Icon\u003E\n\u003C/AppBarToggleButton\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A button that can be on, off, or indeterminate like a CheckBox, and is styled for use in an app bar or other specialized UI.","relatedControls":["AppBarButton","AppBarSeparator","CommandBar"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"AppBarToggleButton - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.appbartogglebutton"},{"title":"SymbolIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.symbolicon"},{"title":"FontIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.fonticon"},{"title":"BitmapIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.bitmapicon"},{"title":"PathIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.pathicon"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/command-bar"}]},{"id":"commandbar-1","controlId":"commandbar","controlName":"CommandBar","headerText":"A command bar with labels on the side free floating in a page","xaml":"\u003CCommandBar Background=\u0022Transparent\u0022 IsOpen=\u0022True\u0022 DefaultLabelPosition=\u0022Right\u0022...\u003E\n \u003CAppBarButton Icon=\u0022Add\u0022 Label=\u0022Add\u0022/\u003E\n \u003CAppBarButton Icon=\u0022Edit\u0022 Label=\u0022Edit\u0022/\u003E\n \u003CAppBarButton Icon=\u0022Share\u0022 Label=\u0022Share\u0022/\u003E\n \u003CCommandBar.SecondaryCommands\u003E\n \u003CAppBarButton Icon=\u0022Setting\u0022 Label=\u0022Settings\u0022\u003E\n \u003CAppBarButton.KeyboardAccelerators\u003E\n \u003CKeyboardAccelerator Modifiers=\u0022Control\u0022 Key=\u0022I\u0022 /\u003E\n \u003C/AppBarButton.KeyboardAccelerators\u003E\n \u003C/AppBarButton\u003E...\n \u003C/CommandBar.SecondaryCommands\u003E\n\u003C/CommandBar\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A toolbar for displaying application-specific commands that handles layout and resizing of its contents.","relatedControls":["AppBarButton","AppBarToggleButton","AppBarSeparator"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"CommandBar - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.commandbar"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/command-bar"}]},{"id":"commandbarflyout-1","controlId":"commandbarflyout","controlName":"CommandBarFlyout","headerText":"CommandBarFlyout for commands on an in-app object","xaml":"\u003CPage.Resources\u003E\n \u003CCommandBarFlyout Placement=\u0022Right\u0022 x:Name=\u0022CommandBarFlyout1\u0022\u003E\n \u003CAppBarButton Label=\u0022Share\u0022 Icon=\u0022Share\u0022 ToolTipService.ToolTip=\u0022Share\u0022 Click=\u0022OnElementClicked\u0022 /\u003E\n \u003CAppBarButton Label=\u0022Save\u0022 Icon=\u0022Save\u0022 ToolTipService.ToolTip=\u0022Save\u0022 Click=\u0022OnElementClicked\u0022 /\u003E\n \u003CAppBarButton Label=\u0022Delete\u0022 Icon=\u0022Delete\u0022 ToolTipService.ToolTip=\u0022Delete\u0022 Click=\u0022OnElementClicked\u0022 /\u003E\n \u003CCommandBarFlyout.SecondaryCommands\u003E\n \u003CAppBarButton x:Name=\u0022ResizeButton1\u0022 Label=\u0022Resize\u0022 Click=\u0022OnElementClicked\u0022 /\u003E\n \u003CAppBarButton x:Name=\u0022MoveButton1\u0022 Label=\u0022Move\u0022 Click=\u0022OnElementClicked\u0022 /\u003E\n \u003C/CommandBarFlyout.SecondaryCommands\u003E\n \u003C/CommandBarFlyout\u003E\n\u003C/Page.Resources\u003E\n\n\u003CButton x:Name=\u0022myImageButton\u0022 AutomationProperties.Name=\u0022mountain\u0022 Padding=\u00220\u0022\n Click=\u0022MyImageButton_Click\u0022 ContextRequested=\u0022MyImageButton_ContextRequested\u0022 \u003E\n \u003CImage x:Name=\u0022Image1\u0022 Height=\u0022300\u0022 Source=\u0022/Assets/SampleMedia/rainier.jpg\u0022/\u003E\n\u003C/Button\u003E","csharp":"private void ShowMenu(bool isTransient)\n{\n FlyoutShowOptions myOption = new FlyoutShowOptions();\n myOption.ShowMode = isTransient ? FlyoutShowMode.Transient : FlyoutShowMode.Standard;\n CommandBarFlyout1.ShowAt(Image1, myOption);\n}\n\nprivate void MyImageButton_ContextRequested(Microsoft.UI.Xaml.UIElement sender, ContextRequestedEventArgs args)\n{\n // Show a context menu in standard mode\n // Focus will move to the menu\n ShowMenu(false);\n}\n\nprivate void MyImageButton_Click(object sender, Microsoft.UI.Xaml.RoutedEventArgs e)\n{\n // Show a context menu in transient mode\n // Focus will not move to the menu\n ShowMenu(true);\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A mini-toolbar displaying proactive commands, and an optional menu of commands.","relatedControls":["CommandBar","MenuFlyout","RichEditBox","TextBox","StandardUICommand","XamlUICommand"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"CommandBarFlyout - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.commandbarflyout"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/command-bar-flyout"}]},{"id":"menubar-1","controlId":"menubar","controlName":"MenuBar","headerText":"A simple MenuBar","xaml":"\u003CMenuBar\u003E\n \u003CMenuBarItem Title=\u0022File\u0022\u003E\n \u003CMenuFlyoutItem Text=\u0022New\u0022/\u003E\n \u003CMenuFlyoutItem Text=\u0022Open...\u0022/\u003E\n \u003CMenuFlyoutItem Text=\u0022Save\u0022/\u003E\n \u003CMenuFlyoutItem Text=\u0022Exit\u0022/\u003E\n \u003C/MenuBarItem\u003E\n\n \u003CMenuBarItem Title=\u0022Edit\u0022\u003E\n \u003CMenuFlyoutItem Text=\u0022Undo\u0022/\u003E\n \u003CMenuFlyoutItem Text=\u0022Cut\u0022/\u003E\n \u003CMenuFlyoutItem Text=\u0022Copy\u0022/\u003E\n \u003CMenuFlyoutItem Text=\u0022Paste\u0022/\u003E\n \u003C/MenuBarItem\u003E\n\n \u003CMenuBarItem Title=\u0022Help\u0022\u003E\n \u003CMenuFlyoutItem Text=\u0022About\u0022/\u003E\n \u003C/MenuBarItem\u003E\n\u003C/MenuBar\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A classic menu, allowing the display of MenuItems containing MenuFlyoutItems.","relatedControls":["CommandBar","MenuFlyout","StandardUICommand","XamlUICommand"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"MenuBar - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Controls.MenuBar"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/menus"}]},{"id":"menubar-2","controlId":"menubar","controlName":"MenuBar","headerText":"MenuBar with keyboard accelerators","xaml":"\u003CMenuBar\u003E\n \u003CMenuBarItem Title=\u0022File\u0022\u003E\n \u003CMenuFlyoutItem Text=\u0022New\u0022\u003E\n \u003CMenuFlyoutItem.KeyboardAccelerators\u003E\n \u003CKeyboardAccelerator Modifiers=\u0022Control\u0022 Key=\u0022N\u0022/\u003E\n \u003C/MenuFlyoutItem.KeyboardAccelerators\u003E\n \u003C/MenuFlyoutItem\u003E\n \u003CMenuFlyoutItem Text=\u0022Open...\u0022\u003E\n \u003CMenuFlyoutItem.KeyboardAccelerators\u003E\n \u003CKeyboardAccelerator Modifiers=\u0022Control\u0022 Key=\u0022O\u0022/\u003E\n \u003C/MenuFlyoutItem.KeyboardAccelerators\u003E\n \u003C/MenuFlyoutItem\u003E\n \u003CMenuFlyoutItem Text=\u0022Save\u0022\u003E\n \u003CMenuFlyoutItem.KeyboardAccelerators\u003E\n \u003CKeyboardAccelerator Modifiers=\u0022Control\u0022 Key=\u0022S\u0022/\u003E\n \u003C/MenuFlyoutItem.KeyboardAccelerators\u003E\n \u003C/MenuFlyoutItem\u003E\n \u003CMenuFlyoutItem Text=\u0022Exit\u0022\u003E\n \u003CMenuFlyoutItem.KeyboardAccelerators\u003E\n \u003CKeyboardAccelerator Modifiers=\u0022Control\u0022 Key=\u0022E\u0022/\u003E\n \u003C/MenuFlyoutItem.KeyboardAccelerators\u003E\n \u003C/MenuFlyoutItem\u003E\n \u003C/MenuBarItem\u003E\n\n \u003CMenuBarItem Title=\u0022Edit\u0022\u003E\n \u003CMenuFlyoutItem Text=\u0022Undo\u0022\u003E\n \u003CMenuFlyoutItem.KeyboardAccelerators\u003E\n \u003CKeyboardAccelerator Modifiers=\u0022Control\u0022 Key=\u0022Z\u0022/\u003E\n \u003C/MenuFlyoutItem.KeyboardAccelerators\u003E\n \u003C/MenuFlyoutItem\u003E\n \u003CMenuFlyoutItem Text=\u0022Cut\u0022\u003E\n \u003CMenuFlyoutItem.KeyboardAccelerators\u003E\n \u003CKeyboardAccelerator Modifiers=\u0022Control\u0022 Key=\u0022X\u0022/\u003E\n \u003C/MenuFlyoutItem.KeyboardAccelerators\u003E\n \u003C/MenuFlyoutItem\u003E\n \u003CMenuFlyoutItem Text=\u0022Copy\u0022\u003E\n \u003CMenuFlyoutItem.KeyboardAccelerators\u003E\n \u003CKeyboardAccelerator Modifiers=\u0022Control\u0022 Key=\u0022C\u0022/\u003E\n \u003C/MenuFlyoutItem.KeyboardAccelerators\u003E\n \u003C/MenuFlyoutItem\u003E\n \u003CMenuFlyoutItem Text=\u0022Paste\u0022\u003E\n \u003CMenuFlyoutItem.KeyboardAccelerators\u003E\n \u003CKeyboardAccelerator Modifiers=\u0022Control\u0022 Key=\u0022V\u0022/\u003E\n \u003C/MenuFlyoutItem.KeyboardAccelerators\u003E\n \u003C/MenuFlyoutItem\u003E\n \u003C/MenuBarItem\u003E\n\n \u003CMenuBarItem Title=\u0022Help\u0022\u003E\n \u003CMenuFlyoutItem Text=\u0022About\u0022\u003E\n \u003CMenuFlyoutItem.KeyboardAccelerators\u003E\n \u003CKeyboardAccelerator Modifiers=\u0022Control\u0022 Key=\u0022I\u0022/\u003E\n \u003C/MenuFlyoutItem.KeyboardAccelerators\u003E\n \u003C/MenuFlyoutItem\u003E\n \u003C/MenuBarItem\u003E\n\u003C/MenuBar\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A classic menu, allowing the display of MenuItems containing MenuFlyoutItems.","relatedControls":["CommandBar","MenuFlyout","StandardUICommand","XamlUICommand"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"MenuBar - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Controls.MenuBar"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/menus"}]},{"id":"menubar-3","controlId":"menubar","controlName":"MenuBar","headerText":"MenuBar with submenus, separators, and radio items","xaml":"\u003CMenuBar\u003E\n \u003CMenuBarItem Title=\u0022File\u0022\u003E\n \u003CMenuFlyoutSubItem Text=\u0022New\u0022\u003E\n \u003CMenuFlyoutItem Text=\u0022Plain Text Document\u0022/\u003E\n \u003CMenuFlyoutItem Text=\u0022Rich Text Document\u0022/\u003E\n \u003CMenuFlyoutItem Text=\u0022Other Formats...\u0022/\u003E\n \u003C/MenuFlyoutSubItem\u003E\n \u003CMenuFlyoutItem Text=\u0022Open...\u0022/\u003E\n \u003CMenuFlyoutItem Text=\u0022Save\u0022/\u003E\n \u003CMenuFlyoutSeparator /\u003E\n \u003CMenuFlyoutItem Text=\u0022Exit\u0022/\u003E\n \u003C/MenuBarItem\u003E\n\n \u003CMenuBarItem Title=\u0022Edit\u0022\u003E\n \u003CMenuFlyoutItem Text=\u0022Undo\u0022/\u003E\n \u003CMenuFlyoutItem Text=\u0022Cut\u0022/\u003E\n \u003CMenuFlyoutItem Text=\u0022Copy\u0022/\u003E\n \u003CMenuFlyoutItem Text=\u0022Paste\u0022/\u003E\n \u003C/MenuBarItem\u003E\n\n \u003CMenuBarItem Title=\u0022View\u0022\u003E\n \u003CMenuFlyoutItem Text=\u0022Output\u0022/\u003E\n \u003CMenuFlyoutSeparator/\u003E\n \u003CRadioMenuFlyoutItem Text=\u0022Landscape\u0022 GroupName=\u0022OrientationGroup\u0022/\u003E\n \u003CRadioMenuFlyoutItem Text=\u0022Portrait\u0022 GroupName=\u0022OrientationGroup\u0022 IsChecked=\u0022True\u0022/\u003E\n \u003CMenuFlyoutSeparator/\u003E\n \u003CRadioMenuFlyoutItem Text=\u0022Small icons\u0022 GroupName=\u0022SizeGroup\u0022/\u003E\n \u003CRadioMenuFlyoutItem Text=\u0022Medium icons\u0022 IsChecked=\u0022True\u0022 GroupName=\u0022SizeGroup\u0022/\u003E\n \u003CRadioMenuFlyoutItem Text=\u0022Large icons\u0022 GroupName=\u0022SizeGroup\u0022/\u003E\n \u003C/MenuBarItem\u003E\n \n \u003CMenuBarItem Title=\u0022Help\u0022\u003E\n \u003CMenuFlyoutItem Text=\u0022About\u0022/\u003E\n \u003C/MenuBarItem\u003E\n\u003C/MenuBar\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A classic menu, allowing the display of MenuItems containing MenuFlyoutItems.","relatedControls":["CommandBar","MenuFlyout","StandardUICommand","XamlUICommand"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"MenuBar - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Controls.MenuBar"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/menus"}]},{"id":"menuflyout-1","controlId":"menuflyout","controlName":"MenuFlyout","headerText":"An AppBarButton with a MenuFlyout.","xaml":"\u003CAppBarButton Icon=\u0022Sort\u0022 IsCompact=\u0022True\u0022 ToolTipService.ToolTip=\u0022Sort\u0022 AutomationProperties.Name=\u0022Sort\u0022\u003E\n \u003CAppBarButton.Flyout\u003E\n \u003CMenuFlyout\u003E\n \u003CMenuFlyoutItem Text=\u0022By rating\u0022 Click=\u0022MenuFlyoutItem_Click\u0022 Tag=\u0022rating\u0022/\u003E\n \u003CMenuFlyoutItem Text=\u0022By match\u0022 Click=\u0022MenuFlyoutItem_Click\u0022 Tag=\u0022match\u0022/\u003E\n \u003CMenuFlyoutItem Text=\u0022By distance\u0022 Click=\u0022MenuFlyoutItem_Click\u0022 Tag=\u0022distance\u0022/\u003E\n \u003C/MenuFlyout\u003E\n \u003C/AppBarButton.Flyout\u003E\n\u003C/AppBarButton\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Shows a contextual list of simple commands or options.","relatedControls":["Flyout","ContentDialog","Button","AppBarButton"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"MenuFlyout - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.menuflyout"},{"title":"MenuFlyoutItem - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.menuflyoutitem"},{"title":"MenuFlyoutSubItem - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.menuflyoutsubitem"},{"title":"MenuFlyoutSeparator - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.menuflyoutseparator"},{"title":"ToggleMenuFlyoutItem - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.togglemenuflyoutitem"},{"title":"RadioMenuFlyoutItem - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.radiomenuflyoutitem"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/menus"}]},{"id":"menuflyout-2","controlId":"menuflyout","controlName":"MenuFlyout","headerText":"A MenuFlyout with ToggleMenuFlyoutItems and MenuFlyoutSeparator.","xaml":"\u003CButton Content=\u0022Options\u0022\u003E\n \u003CButton.Flyout\u003E\n \u003CMenuFlyout\u003E\n \u003CMenuFlyoutItem Text=\u0022Reset\u0022/\u003E\n \u003CMenuFlyoutSeparator/\u003E\n \u003CToggleMenuFlyoutItem Text=\u0022Repeat\u0022 IsChecked=\u0022...\u0022/\u003E\n \u003CToggleMenuFlyoutItem Text=\u0022Shuffle\u0022 IsChecked=\u0022...\u0022/\u003E\n \u003C/MenuFlyout\u003E\n \u003C/Button.Flyout\u003E\n\u003C/Button\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Shows a contextual list of simple commands or options.","relatedControls":["Flyout","ContentDialog","Button","AppBarButton"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"MenuFlyout - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.menuflyout"},{"title":"MenuFlyoutItem - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.menuflyoutitem"},{"title":"MenuFlyoutSubItem - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.menuflyoutsubitem"},{"title":"MenuFlyoutSeparator - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.menuflyoutseparator"},{"title":"ToggleMenuFlyoutItem - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.togglemenuflyoutitem"},{"title":"RadioMenuFlyoutItem - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.radiomenuflyoutitem"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/menus"}]},{"id":"menuflyout-3","controlId":"menuflyout","controlName":"MenuFlyout","headerText":"A MenuFlyout with cascading menus.","xaml":"\u003CButton Content=\u0022File Options\u0022\u003E\n \u003CButton.Flyout\u003E\n \u003CMenuFlyout\u003E\n \u003CMenuFlyoutItem Text=\u0022Open\u0022/\u003E\n \u003CMenuFlyoutSubItem Text=\u0022Send to\u0022\u003E\n \u003CMenuFlyoutItem Text=\u0022Bluetooth\u0022 /\u003E\n \u003CMenuFlyoutItem Text=\u0022Desktop (shortcut)\u0022 /\u003E\n \u003CMenuFlyoutSubItem Text=\u0022Compressed file\u0022\u003E\n \u003CMenuFlyoutItem Text=\u0022Compress and email\u0022 /\u003E\n \u003CMenuFlyoutItem Text=\u0022Compress to .7z\u0022 /\u003E\n \u003CMenuFlyoutItem Text=\u0022Compress to .zip\u0022 /\u003E\n \u003C/MenuFlyoutSubItem\u003E\n \u003C/MenuFlyoutSubItem\u003E\n \u003C/MenuFlyout\u003E\n \u003C/Button.Flyout\u003E\n\u003C/Button\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Shows a contextual list of simple commands or options.","relatedControls":["Flyout","ContentDialog","Button","AppBarButton"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"MenuFlyout - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.menuflyout"},{"title":"MenuFlyoutItem - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.menuflyoutitem"},{"title":"MenuFlyoutSubItem - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.menuflyoutsubitem"},{"title":"MenuFlyoutSeparator - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.menuflyoutseparator"},{"title":"ToggleMenuFlyoutItem - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.togglemenuflyoutitem"},{"title":"RadioMenuFlyoutItem - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.radiomenuflyoutitem"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/menus"}]},{"id":"menuflyout-4","controlId":"menuflyout","controlName":"MenuFlyout","headerText":"A MenuFlyout with SplitMenuFlyoutItems.","xaml":"\u003CButton Content=\u0022File Options\u0022\u003E\n \u003CButton.Flyout\u003E\n \u003CMenuFlyout\u003E\n \u003CSplitMenuFlyoutItem Text=\u0022Save\u0022 Click=\u0022SplitMenuFlyoutItem_Click\u0022\u003E\n \u003CSplitMenuFlyoutItem.Icon\u003E\n \u003CFontIcon Glyph=\u0022\u0026#xE74E;\u0022/\u003E\n \u003C/SplitMenuFlyoutItem.Icon\u003E\n \u003CMenuFlyoutItem Text=\u0022Save as .docx\u0022 Click=\u0022SplitMenuFlyoutItem_Click\u0022/\u003E\n \u003CMenuFlyoutItem Text=\u0022Save as .pdf\u0022 Click=\u0022SplitMenuFlyoutItem_Click\u0022/\u003E\n \u003CMenuFlyoutItem Text=\u0022Save as .txt\u0022 Click=\u0022SplitMenuFlyoutItem_Click\u0022/\u003E\n \u003C/SplitMenuFlyoutItem\u003E\n \u003CSplitMenuFlyoutItem Text=\u0022Share\u0022 Icon=\u0022Share\u0022 Click=\u0022SplitMenuFlyoutItem_Click\u0022\u003E\n \u003CMenuFlyoutItem Text=\u0022Share via email\u0022 Click=\u0022SplitMenuFlyoutItem_Click\u0022/\u003E\n \u003CMenuFlyoutItem Text=\u0022Share via link\u0022 Click=\u0022SplitMenuFlyoutItem_Click\u0022/\u003E\n \u003C/SplitMenuFlyoutItem\u003E\n \u003C/MenuFlyout\u003E\n \u003C/Button.Flyout\u003E\n\u003C/Button\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Shows a contextual list of simple commands or options.","relatedControls":["Flyout","ContentDialog","Button","AppBarButton"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"MenuFlyout - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.menuflyout"},{"title":"MenuFlyoutItem - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.menuflyoutitem"},{"title":"MenuFlyoutSubItem - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.menuflyoutsubitem"},{"title":"MenuFlyoutSeparator - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.menuflyoutseparator"},{"title":"ToggleMenuFlyoutItem - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.togglemenuflyoutitem"},{"title":"RadioMenuFlyoutItem - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.radiomenuflyoutitem"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/menus"}]},{"id":"menuflyout-5","controlId":"menuflyout","controlName":"MenuFlyout","headerText":"A MenuFlyout with icons.","xaml":"\u003CButton Content=\u0022Edit Options\u0022\u003E\n \u003CButton.Flyout\u003E\n \u003CMenuFlyout\u003E\n \u003CMenuFlyoutItem Text=\u0022Share\u0022\u003E\n \u003CMenuFlyoutItem.Icon\u003E\n \u003CFontIcon Glyph=\u0022\u0026#xE72D;\u0022/\u003E\n \u003C/MenuFlyoutItem.Icon\u003E\n \u003C/MenuFlyoutItem\u003E\n \u003CMenuFlyoutItem Text=\u0022Copy\u0022 Icon=\u0022Copy\u0022/\u003E\n \u003CMenuFlyoutItem Text=\u0022Delete\u0022 Icon=\u0022Delete\u0022/\u003E\n \u003CMenuFlyoutSeparator/\u003E\n \u003CMenuFlyoutItem Text=\u0022Rename\u0022/\u003E\n \u003CMenuFlyoutItem Text=\u0022Select\u0022/\u003E\n \u003C/MenuFlyout\u003E\n \u003C/Button.Flyout\u003E\n\u003C/Button\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Shows a contextual list of simple commands or options.","relatedControls":["Flyout","ContentDialog","Button","AppBarButton"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"MenuFlyout - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.menuflyout"},{"title":"MenuFlyoutItem - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.menuflyoutitem"},{"title":"MenuFlyoutSubItem - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.menuflyoutsubitem"},{"title":"MenuFlyoutSeparator - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.menuflyoutseparator"},{"title":"ToggleMenuFlyoutItem - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.togglemenuflyoutitem"},{"title":"RadioMenuFlyoutItem - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.radiomenuflyoutitem"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/menus"}]},{"id":"menuflyout-6","controlId":"menuflyout","controlName":"MenuFlyout","headerText":"A MenuFlyout with icons and Keyboard Accelerators.","xaml":"\u003CButton Content=\u0022Edit Options\u0022\u003E\n \u003CButton.Flyout\u003E\n \u003CMenuFlyout\u003E\n \u003CMenuFlyoutItem Text=\u0022Share\u0022\u003E\n \u003CMenuFlyoutItem.Icon\u003E\n \u003CFontIcon Glyph=\u0022\u0026#xE72D;\u0022/\u003E\n \u003C/MenuFlyoutItem.Icon\u003E\n \u003CMenuFlyoutItem.KeyboardAccelerators\u003E\n \u003CKeyboardAccelerator Key=\u0022S\u0022 Modifiers=\u0022Control\u0022/\u003E\n \u003C/MenuFlyoutItem.KeyboardAccelerators\u003E\n \u003C/MenuFlyoutItem\u003E\n \u003CMenuFlyoutItem Text=\u0022Copy\u0022 Icon=\u0022Copy\u0022\u003E\n \u003CMenuFlyoutItem.KeyboardAccelerators\u003E\n \u003CKeyboardAccelerator Key=\u0022C\u0022 Modifiers=\u0022Control\u0022/\u003E\n \u003C/MenuFlyoutItem.KeyboardAccelerators\u003E\n \u003C/MenuFlyoutItem\u003E\n \u003CMenuFlyoutItem Text=\u0022Delete\u0022 Icon=\u0022Delete\u0022\u003E\n \u003CMenuFlyoutItem.KeyboardAccelerators\u003E\n \u003CKeyboardAccelerator Key=\u0022Delete\u0022 /\u003E\n \u003C/MenuFlyoutItem.KeyboardAccelerators\u003E\n \u003C/MenuFlyoutItem\u003E\n \u003CMenuFlyoutSeparator/\u003E\n \u003CMenuFlyoutItem Text=\u0022Rename\u0022/\u003E\n \u003CMenuFlyoutItem Text=\u0022Select\u0022/\u003E\n \u003C/MenuFlyout\u003E\n \u003C/Button.Flyout\u003E\n\u003C/Button\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Shows a contextual list of simple commands or options.","relatedControls":["Flyout","ContentDialog","Button","AppBarButton"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"MenuFlyout - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.menuflyout"},{"title":"MenuFlyoutItem - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.menuflyoutitem"},{"title":"MenuFlyoutSubItem - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.menuflyoutsubitem"},{"title":"MenuFlyoutSeparator - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.menuflyoutseparator"},{"title":"ToggleMenuFlyoutItem - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.togglemenuflyoutitem"},{"title":"RadioMenuFlyoutItem - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.radiomenuflyoutitem"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/menus"}]},{"id":"menuflyout-7","controlId":"menuflyout","controlName":"MenuFlyout","headerText":"A MenuFlyout with RadioMenuFlyoutItems","xaml":"\u003CButton Content=\u0022Options\u0022\u003E\n \u003CButton.Flyout\u003E\n \u003CMenuFlyout\u003E\n \u003CRadioMenuFlyoutItem Text=\u0022Landscape\u0022 GroupName=\u0022OrientationGroup\u0022/\u003E\n \u003CRadioMenuFlyoutItem Text=\u0022Portrait\u0022 GroupName=\u0022OrientationGroup\u0022 IsChecked=\u0022True\u0022/\u003E\n \u003CMenuFlyoutSeparator/\u003E\n \u003CRadioMenuFlyoutItem Text=\u0022Small icons\u0022 GroupName=\u0022SizeGroup\u0022/\u003E\n \u003CRadioMenuFlyoutItem Text=\u0022Medium icons\u0022 IsChecked=\u0022True\u0022 GroupName=\u0022SizeGroup\u0022/\u003E\n \u003CRadioMenuFlyoutItem Text=\u0022Large icons\u0022 GroupName=\u0022SizeGroup\u0022/\u003E\n \u003C/MenuFlyout\u003E\n \u003C/Button.Flyout\u003E\n\u003C/Button\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Shows a contextual list of simple commands or options.","relatedControls":["Flyout","ContentDialog","Button","AppBarButton"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"MenuFlyout - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.menuflyout"},{"title":"MenuFlyoutItem - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.menuflyoutitem"},{"title":"MenuFlyoutSubItem - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.menuflyoutsubitem"},{"title":"MenuFlyoutSeparator - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.menuflyoutseparator"},{"title":"ToggleMenuFlyoutItem - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.togglemenuflyoutitem"},{"title":"RadioMenuFlyoutItem - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.radiomenuflyoutitem"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/menus"}]},{"id":"swipecontrol-1","controlId":"swipecontrol","controlName":"SwipeControl","headerText":"Swipe right to reveal actions","xaml":"\u003CBorder\u003E\n \u003CBorder.Resources\u003E\n \u003CFontIconSource x:Key=\u0022AcceptIcon\u0022 Glyph=\u0022\u0026#xE8FB;\u0022/\u003E\n \u003CFontIconSource x:Key=\u0022FlagIcon\u0022 Glyph=\u0022\u0026#xE7C1;\u0022/\u003E\n\n \u003CSwipeItems x:Key=\u0022left\u0022 Mode=\u0022Reveal\u0022\u003E\n \u003CSwipeItem Text=\u0022Accept\u0022 IconSource=\u0022{StaticResource AcceptIcon}\u0022 Invoked=\u0022Accept_ItemInvoked\u0022/\u003E\n \u003CSwipeItem Text=\u0022Flag\u0022 IconSource=\u0022{StaticResource FlagIcon}\u0022 Invoked=\u0022Flag_ItemInvoked\u0022/\u003E\n \u003C/SwipeItems\u003E\n \u003C/Border.Resources\u003E\n \u003CSwipeControl BorderThickness=\u00221\u0022\n LeftItems=\u0022{StaticResource left}\u0022 BorderBrush=\u0022{ThemeResource ButtonBackground}\u0022\n Width=\u0022300\u0022 Margin=\u002212\u0022 Height=\u002268\u0022\u003E\n \u003CTextBlock Text=\u0022Swipe Right\u0022 Margin=\u002212\u0022\n HorizontalAlignment=\u0022Center\u0022 VerticalAlignment=\u0022Center\u0022/\u003E\n \u003C/SwipeControl\u003E\n\u003C/Border\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Touch gesture for quick menu actions on items.","relatedControls":["GridView","ListView"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"SwipeControl - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.swipecontrol"},{"title":"SwipeItems - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.swipeitems"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/swipe"},{"title":"Gesture Actions","uri":"https://learn.microsoft.com/windows/apps/design/controls/collection-commanding"}]},{"id":"swipecontrol-2","controlId":"swipecontrol","controlName":"SwipeControl","headerText":"Swipe left to invoke an execute","xaml":"\u003CBorder\u003E\n \u003CBorder.Resources\u003E\n \u003CFontIconSource x:Key=\u0022DeleteIcon\u0022 Glyph=\u0022\u0026#xE74D;\u0022/\u003E\n \u003CSwipeItems x:Key=\u0022right\u0022 Mode=\u0022Execute\u0022\u003E\n \u003CSwipeItem Text=\u0022Archive\u0022 IconSource=\u0022{StaticResource ArchiveIcon}\u0022\n BehaviorOnInvoked=\u0022Close\u0022 Invoked=\u0022DeleteOne_ItemInvoked\u0022/\u003E\n \u003C/SwipeItems\u003E\n \u003C/Border.Resources\u003E\n \u003CSwipeControl BorderThickness=\u00221\u0022 BorderBrush=\u0022{ThemeResource ButtonBackground}\u0022\n RightItems=\u0022{StaticResource right}\u0022\n Width=\u0022300\u0022 Margin=\u002212\u0022 Height=\u002268\u0022\u003E\n \u003CTextBlock Text=\u0022Swipe Left\u0022 Margin=\u002212\u0022\n HorizontalAlignment=\u0022Center\u0022 VerticalAlignment=\u0022Center\u0022/\u003E\n \u003C/SwipeControl\u003E\n\u003C/Border\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Touch gesture for quick menu actions on items.","relatedControls":["GridView","ListView"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"SwipeControl - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.swipecontrol"},{"title":"SwipeItems - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.swipeitems"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/swipe"},{"title":"Gesture Actions","uri":"https://learn.microsoft.com/windows/apps/design/controls/collection-commanding"}]},{"id":"swipecontrol-3","controlId":"swipecontrol","controlName":"SwipeControl","headerText":"Custom Swipe in a ListView","xaml":"\u003CListView x:Name=\u0022lv\u0022 Width=\u0022400\u0022 Height=\u0022300\u0022 Margin=\u002212\u0022\u003E\n \u003CListView.Resources\u003E\n \u003CFontIconSource x:Key=\u0022ReplyAllIcon\u0022 Glyph=\u0022\u0026#xE8C2;\u0022/\u003E\n \u003CFontIconSource x:Key=\u0022ReadIcon\u0022 Glyph=\u0022\u0026#xE8C3;\u0022/\u003E\n \u003CFontIconSource x:Key=\u0022DeleteIcon\u0022 Glyph=\u0022\u0026#xE74D;\u0022/\u003E\n\n \u003CSwipeItems x:Key=\u0022left\u0022 Mode=\u0022Reveal\u0022\u003E\n \u003CSwipeItem Text=\u0022Reply All\u0022 IconSource=\u0022{StaticResource ReplyAllIcon}\u0022\n Background=\u0022#FF3e6fa7\u0022 Foreground=\u0022White\u0022/\u003E\n \u003CSwipeItem Text=\u0022Open\u0022 IconSource=\u0022{StaticResource ReadIcon}\u0022\n Background=\u0022#FFff9501\u0022 Foreground=\u0022White\u0022/\u003E\n \u003C/SwipeItems\u003E\n \u003CSwipeItems x:Key=\u0022right\u0022 Mode=\u0022Execute\u0022\u003E\n \u003CSwipeItem Text=\u0022Delete\u0022 IconSource=\u0022{StaticResource DeleteIcon}\u0022\n Background=\u0022#FFF4B183\u0022 Invoked=\u0022DeleteItem_ItemInvoked\u0022/\u003E\n \u003C/SwipeItems\u003E\n \u003C/ListView.Resources\u003E\n\n \u003CListView.ItemTemplate\u003E\n \u003CDataTemplate\u003E\n \u003CSwipeControl BorderThickness=\u00220,1,0,0\u0022 BorderBrush=\u0022{ThemeResource ButtonBackground}\u0022 Height=\u002268\u0022\n RightItems=\u0022{StaticResource right}\u0022\u003E\n \u003CTextBlock Text=\u0022{Binding}\u0022 FontSize=\u002224\u0022 Margin=\u002212\u0022\n HorizontalAlignment=\u0022Stretch\u0022 VerticalAlignment=\u0022Center\u0022/\u003E\n \u003C/SwipeControl\u003E\n \u003C/DataTemplate\u003E\n \u003C/ListView.ItemTemplate\u003E\n\u003C/ListView\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Touch gesture for quick menu actions on items.","relatedControls":["GridView","ListView"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"SwipeControl - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.swipecontrol"},{"title":"SwipeItems - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.swipeitems"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/swipe"},{"title":"Gesture Actions","uri":"https://learn.microsoft.com/windows/apps/design/controls/collection-commanding"}]},{"id":"swipecontrol-4","controlId":"swipecontrol","controlName":"SwipeControl","headerText":"Gradient Background","xaml":"\u003CBorder\u003E\n \u003CBorder.Resources\u003E\n \u003CFontIconSource x:Key=\u0022LockIcon\u0022 Glyph=\u0022\u0026#xE72E;\u0022/\u003E\n \u003CLinearGradientBrush x:Key=\u0022PurpleGradient\u0022 StartPoint=\u00220,0.5\u0022 EndPoint=\u00221,0.5\u0022\u003E\n \u003CGradientStop Color=\u0022#ff8990f9\u0022 Offset=\u00220.0\u0022/\u003E\n \u003CGradientStop Color=\u0022#ff5b66fb\u0022 Offset=\u00220.5\u0022/\u003E\n \u003CGradientStop Color=\u0022#ff5c1df4\u0022 Offset=\u00221.0\u0022/\u003E\n \u003CLinearGradientBrush/\u003E\n \u003CSwipeItems x:Key=\u0022right\u0022 Mode=\u0022Execute\u0022\u003E\n \u003CSwipeItem Text=\u0022Lock\u0022 Background=\u0022{StaticResource PurpleGradient}\u0022 \n BehaviorOnInvoked=\u0022Close\u0022 IconSource=\u0022{StaticResource LockIcon}\u0022/\u003E\n \u003C/SwipeItems\u003E\n \u003C/Border.Resources\u003E\n \u003CSwipeControl BorderThickness=\u00221\u0022 BorderBrush=\u0022{ThemeResource ButtonBackground}\u0022\n RightItems=\u0022{StaticResource right}\u0022\n Width=\u0022500\u0022 Margin=\u002212\u0022 Height=\u002268\u0022\u003E\n \u003CTextBlock Text=\u0022Swipe Left\u0022 Margin=\u002212\u0022\n HorizontalAlignment=\u0022Center\u0022 VerticalAlignment=\u0022Center\u0022/\u003E\n \u003C/SwipeControl\u003E\n\u003C/Border\u003E\u003C/LinearGradientBrush\u003E\u003C/Border.Resources\u003E\u003C/Border\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Touch gesture for quick menu actions on items.","relatedControls":["GridView","ListView"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"SwipeControl - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.swipecontrol"},{"title":"SwipeItems - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.swipeitems"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/swipe"},{"title":"Gesture Actions","uri":"https://learn.microsoft.com/windows/apps/design/controls/collection-commanding"}]},{"id":"swipecontrol-5","controlId":"swipecontrol","controlName":"SwipeControl","headerText":"Custom icons","xaml":"\u003CBorder\u003E\n \u003CBorder.Resources\u003E\n \u003CSwipeItems x:Key=\u0022left\u0022 Mode=\u0022Reveal\u0022\u003E\n \u003CSwipeItem Text=\u0022Coffee\u0022\u003E\n \u003CSwipeItem.IconSource\u003E\n \u003CBitmapIconSource UriSource=\u0022ms-appx:///Assets/YourImage.png\u0022/\u003E\n \u003CSwipeItem.IconSource/\u003E\n \u003CSwipeItem/\u003E\n \u003C/SwipeItems\u003E\n \u003C/Border.Resources\u003E\n \u003CSwipeControl BorderThickness=\u00221\u0022\n LeftItems=\u0022{StaticResource left}\u0022 BorderBrush=\u0022{ThemeResource ButtonBackground}\u0022\n Width=\u0022300\u0022 Margin=\u002212\u0022 Height=\u002268\u0022\u003E\n \u003CTextBlock Text=\u0022Swipe Right\u0022 Margin=\u002212\u0022\n HorizontalAlignment=\u0022Center\u0022 VerticalAlignment=\u0022Center\u0022/\u003E\n \u003C/SwipeControl\u003E\n\u003C/Border\u003E\u003C/SwipeItem.IconSource\u003E\u003C/SwipeItem\u003E\u003C/SwipeItems\u003E\u003C/Border.Resources\u003E\u003C/Border\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Touch gesture for quick menu actions on items.","relatedControls":["GridView","ListView"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"SwipeControl - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.swipecontrol"},{"title":"SwipeItems - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.swipeitems"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/swipe"},{"title":"Gesture Actions","uri":"https://learn.microsoft.com/windows/apps/design/controls/collection-commanding"}]},{"id":"standarduicommand-1","controlId":"standarduicommand","controlName":"StandardUICommand","headerText":"Exposing a command in multiple controls using StandardUICommand","xaml":"\u003CSwipeItem x:Name=\u0022DeleteSwipeItem\u0022 Background=\u0022Red\u0022 Command=\u0022{x:Bind Command}\u0022 CommandParameter=\u0022{x:Bind Text}\u0022 /\u003E\n\n\u003CAppBarButton x:Name=\u0022HoverButton\u0022 IsTabStop=\u0022False\u0022 HorizontalAlignment=\u0022Right\u0022 Visibility=\u0022Collapsed\u0022 \n Command=\u0022{x:Bind Command}\u0022 CommandParameter=\u0022{x:Bind Text}\u0022 /\u003E","csharp":"private void ControlExample_Loaded(object sender, RoutedEventArgs e)\n{\n var deleteCommand = new StandardUICommand(StandardUICommandKind.Delete);\n deleteCommand.ExecuteRequested \u002B= DeleteCommand_ExecuteRequested;\n\n DeleteFlyoutItem.Command = deleteCommand;\n\n for (var i = 0; i \u003C 15; i\u002B\u002B)\n {\n collection.Add(new ListItemData { Text = \u0022List item \u0022 \u002B i.ToString(), Command = deleteCommand });\n }\n}\n\nprivate void ListViewRight_ContainerContentChanging(ListViewBase sender, ContainerContentChangingEventArgs args)\n{\n MenuFlyout flyout = new MenuFlyout();\n ListItemData data = (ListItemData)args.Item;\n MenuFlyoutItem item = new MenuFlyoutItem() { Command = data.Command};\n flyout.Items.Add(item);\n args.ItemContainer.ContextFlyout = flyout;\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A StandardUICommand is a built-in \u0027XamlUICommand\u0027 which represents a commonly used command, e.g. \u0027Save\u0027.","relatedControls":["XamlUICommand","AppBarButton","AppBarToggleButton","CommandBar"],"apiNamespace":"Microsoft.UI.Xaml.Input","docs":[{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/commanding#command-experiences-using-the-standarduicommand-class"},{"title":"StandardUICommand - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.input.standarduicommand"}]},{"id":"xamluicommand-1","controlId":"xamluicommand","controlName":"XamlUICommand","headerText":"Creating a reusable command with XamlUICommand","xaml":"\u003CPage.Resources\u003E\n \u003CXamlUICommand x:Name=\u0022CustomXamlUICommand\u0022 ExecuteRequested=\u0022CustomXamlUICommand_ExecuteRequested\u0022 \n\tDescription=\u0022This is a custom command\u0022 Label=\u0022Custom Command\u0022\u003E\n \u003CXamlUICommand.IconSource\u003E\n \u003CSymbolIconSource Symbol=\u0022Favorite\u0022 /\u003E\n \u003C/XamlUICommand.IconSource\u003E\n \u003CXamlUICommand.KeyboardAccelerators\u003E\n \u003CKeyboardAccelerator Key=\u0022D\u0022 Modifiers=\u0022Control\u0022/\u003E\n \u003C/XamlUICommand.KeyboardAccelerators\u003E\n \u003C/XamlUICommand\u003E\n\u003C/Page.Resources\u003E\n\n\u003CRelativePanel Grid.Row=\u00221\u0022\u003E\n \u003CAppBarButton x:Name=\u0022CustomButton\u0022 Command=\u0022{StaticResource CustomXamlUICommand}\u0022/\u003E\n \u003CTextBlock x:Name=\u0022XamlUICommandOutput\u0022 Margin=\u00228,0,0,0\u0022 FontFamily=\u0022Global User Interface\u0022 \n RelativePanel.RightOf=\u0022CustomButton\u0022 RelativePanel.AlignVerticalCenterWith=\u0022CustomButton\u0022 /\u003E\n\u003C/RelativePanel\u003E","csharp":"private void CustomXamlUICommand_ExecuteRequested(XamlUICommand sender, ExecuteRequestedEventArgs args)\n{\n XamlUICommandOutput.Text = \u0022You fired the custom command\u0022;\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"An object which is used to define the look and feel of a given command.","relatedControls":["StandardUICommand","AppBarButton","AppBarToggleButton","CommandBar"],"apiNamespace":"Microsoft.UI.Xaml.Input","docs":[{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/commanding#command-experiences-using-the-xamluicommand-class"},{"title":"XamlUICommand - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.input.xamluicommand"}]},{"id":"flipview-1","controlId":"flipview","controlName":"FlipView","headerText":"A simple FlipView with items declared inline.","xaml":"\u003CFlipView MaxWidth=\u0022400\u0022 Height=\u0022270\u0022\n AutomationProperties.AutomationControlType=\u0022List\u0022\n AutomationProperties.LocalizedControlType=\u0022list\u0022\u003E\n \u003CImage Source=\u0022ms-appx:///Assets/YourImage.png\u0022 AutomationProperties.Name=\u0022Cliff\u0022/\u003E\n \u003CImage Source=\u0022ms-appx:///Assets/YourImage.png\u0022 AutomationProperties.Name=\u0022Grapes\u0022/\u003E\n \u003CImage Source=\u0022ms-appx:///Assets/YourImage.png\u0022 AutomationProperties.Name=\u0022Rainier\u0022/\u003E\n \u003CImage Source=\u0022ms-appx:///Assets/YourImage.png\u0022 AutomationProperties.Name=\u0022Sunset\u0022/\u003E\n \u003CImage Source=\u0022ms-appx:///Assets/YourImage.png\u0022 AutomationProperties.Name=\u0022Valley\u0022/\u003E\n\u003C/FlipView\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Presents a collection of items that the user can flip through, one item at a time.","relatedControls":["GridView","ListView","SemanticZoom"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"FlipView - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.flipview"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/flipview"}]},{"id":"flipview-2","controlId":"flipview","controlName":"FlipView","headerText":"A FlipView showing bound data with a data template.","xaml":"\u003CFlipView MaxWidth=\u0022400\u0022 Height=\u0022180\u0022 BorderBrush=\u0022Black\u0022 BorderThickness=\u00221\u0022\n AutomationProperties.AutomationControlType=\u0022List\u0022\n AutomationProperties.LocalizedControlType=\u0022list\u0022\n ItemsSource=\u0022{x:Bind Items, Mode=OneWay}\u0022\u003E\n \u003CFlipView.ItemTemplate\u003E\n \u003CDataTemplate x:DataType=\u0022data:ControlInfoDataItem\u0022\u003E\n \u003CGrid\u003E\n \u003CImage Height=\u0022120\u0022 Source=\u0022{x:Bind ImagePath}\u0022 Stretch=\u0022Uniform\u0022 VerticalAlignment=\u0022Top\u0022/\u003E\n \u003CBorder Background=\u0022#A5FFFFFF\u0022 Height=\u002260\u0022 VerticalAlignment=\u0022Bottom\u0022\u003E\n \u003CTextBlock Text=\u0022{x:Bind Title}\u0022 Foreground=\u0022#CCFFFFFF\u0022 Padding=\u002212,12\u0022 Style=\u0022{StaticResource TitleTextBlockStyle}\u0022 HorizontalAlignment=\u0022Center\u0022/\u003E\n \u003C/Border\u003E\n \u003C/Grid\u003E\n \u003C/DataTemplate\u003E\n \u003C/FlipView.ItemTemplate\u003E\n\u003C/FlipView\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Presents a collection of items that the user can flip through, one item at a time.","relatedControls":["GridView","ListView","SemanticZoom"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"FlipView - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.flipview"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/flipview"}]},{"id":"flipview-3","controlId":"flipview","controlName":"FlipView","headerText":"Vertical FlipView","xaml":"\u003CFlipView MaxWidth=\u0022400\u0022 Height=\u0022270\u0022\n AutomationProperties.AutomationControlType=\u0022List\u0022\n AutomationProperties.LocalizedControlType=\u0022list\u0022\u003E\n \u003CImage Source=\u0022ms-appx:///Assets/YourImage.png\u0022 AutomationProperties.Name=\u0022Cliff\u0022/\u003E\n \u003CImage Source=\u0022ms-appx:///Assets/YourImage.png\u0022 AutomationProperties.Name=\u0022Grapes\u0022/\u003E\n \u003CImage Source=\u0022ms-appx:///Assets/YourImage.png\u0022 AutomationProperties.Name=\u0022Rainier\u0022/\u003E\n \u003CImage Source=\u0022ms-appx:///Assets/YourImage.png\u0022 AutomationProperties.Name=\u0022Sunset\u0022/\u003E\n \u003CImage Source=\u0022ms-appx:///Assets/YourImage.png\u0022 AutomationProperties.Name=\u0022Valley\u0022/\u003E\n \u003CFlipView.ItemsPanel \u003E\n \u003CItemsPanelTemplate\u003E\n \u003CVirtualizingStackPanel Orientation=\u0022Vertical\u0022/\u003E\n \u003C/ItemsPanelTemplate\u003E\n \u003C/FlipView.ItemsPanel\u003E\n\u003CFlipView\u003E\u003C/FlipView\u003E\u003C/FlipView\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Presents a collection of items that the user can flip through, one item at a time.","relatedControls":["GridView","ListView","SemanticZoom"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"FlipView - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.flipview"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/flipview"}]},{"id":"gridview-1","controlId":"gridview","controlName":"GridView","headerText":"Basic GridView with Simple DataTemplate","xaml":"\u003C!-- XAML Code --\u003E\n\n\u003CGridView\n x:Name=\u0022BasicGridView\u0022\n ItemTemplate=\u0022{StaticResource ImageTemplate}\u0022\n IsItemClickEnabled=\u0022True\u0022\n ItemClick=\u0022BasicGridView_ItemClick\u0022\n SelectionMode=\u0022Single\u0022/\u003E\n \n\u003CDataTemplate x:Key=\u0022ImageTemplate\u0022 x:DataType=\u0022local:CustomDataObject\u0022\u003E\n \u003CImage Stretch=\u0022UniformToFill\u0022 Source=\u0022{x:Bind ImageLocation}\u0022 Width=\u0022190\u0022 Height=\u0022130\u0022/\u003E\n\u003C/DataTemplate\u003E\n \n\u003C!-- In this example, the GridView\u0027s ItemTemplate property is bound to a data template (shown above)\ncalled ImageTemplate, defined in the Page.Resources section of the XAML file. \n \nThe data template is defined to display an object of type CustomDataObject, which is created from a class\nthat\u0027s defined in the code-behind (see code below).\n \nThe ItemsSource for the GridView is an ObservableCollection\u003CCustomDataObject\u003E called Items and\nis defined in the C# code-behind. It is bound to the GridView\u0027s ItemsSource property in the code-behind.\n \nThe IsItemClickEnabled property allows items to be clicked, and a function called BasicGridView_ItemClick \nis called when an item is clicked. This function is defined in the C# code-behind and simply outputs \nthe title of the selected item into a TextBlock below the GridView. --\u003E","csharp":"// CustomDataObject class definition: \npublic class CustomDataObject\n{\n public string Title { get; set; } = string.Empty;\n public string ImageLocation { get; set; } = string.Empty;\n public string Views { get; set; } = string.Empty;\n public string Likes { get; set; } = string.Empty;\n public string Description { get; set; } = string.Empty;\n\n public CustomDataObject()\n {\n }\n\n // ... Methods ...\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A control that presents a collection of items in rows and columns.","relatedControls":["ItemsView","ListView","FlipView","SemanticZoom"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"GridView - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.gridview"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/lists"}]},{"id":"gridview-2","controlId":"gridview","controlName":"GridView","headerText":"GridView with Layout Customization","xaml":"\u003C!-- The GridView used for this example is shown below. Setter properties are used to customize \nsome parts of the GridViewItems (i.e. the margins). --\u003E\n\u003CGridView\n x:Name=\u0022StyledGrid\u0022\n ItemTemplate=\u0022{StaticResource ImageOverlayTemplate}\u0022\u003E\n\n \u003CGridView.ItemContainerStyle\u003E\n \u003CStyle TargetType=\u0022GridViewItem\u0022 BasedOn=\u0022{StaticResource DefaultGridViewItemStyle}\u0022\u003E\n \u003CSetter Property=\u0022Margin\u0022 Value=\u0022..., ..., ..., ...\u0022/\u003E\n \u003C/Style\u003E\n \u003C/GridView.ItemContainerStyle\u003E\n \n \u003C!-- An extra property also needs to be added to the GridView\u0027s ItemsWrapGrid. \n The following sets the maximum # of items to show before wrapping.--\u003E\n \u003CGridView.ItemsPanel\u003E\n \u003CItemsPanelTemplate\u003E\n \u003CItemsWrapGrid x:Name=\u0022MaxItemsWrapGrid\u0022 \n MaximumRowsOrColumns=\u0022...\u0022 \n Orientation=\u0022Horizontal\u0022/\u003E\n \u003C/ItemsPanelTemplate\u003E\n \u003C/GridView.ItemsPanel\u003E \n\u003C/GridView\u003E \n \n\u003C!-- In this example, the GridView\u0027s ItemTemplate property is bound to a data template (shown below)\ncalled ImageOverlayTemplate, defined in the Page.Resources section of the XAML file. \n \nThe data template is defined to display a CustomDataObject object (same type as in above sample). --\u003E\n \n\u003CDataTemplate x:Name=\u0022ImageOverlayTemplate\u0022 x:DataType=\u0022local:CustomDataObject\u0022\u003E\n \u003CGrid Width=\u0022100\u0022\u003E\n \u003CImage Source=\u0022{x:Bind ImageLocation}\u0022 Stretch=\u0022UniformToFill\u0022/\u003E\n \u003CStackPanel Orientation=\u0022Vertical\u0022 Height=\u002240\u0022 VerticalAlignment=\u0022Bottom\u0022 Padding=\u00225,1,5,1\u0022 \n Background=\u0022LightGray\u0022 Opacity=\u0022.75\u0022\u003E\n \u003CTextBlock Text=\u0022{x:Bind Title}\u0022/\u003E\n \u003CStackPanel Orientation=\u0022Horizontal\u0022\u003E\n \u003CTextBlock Text=\u0022{x:Bind Likes}\u0022 Style=\u0022{ThemeResource CaptionTextBlockStyle}\u0022 \n Foreground=\u0022{ThemeResource SystemControlPageTextBaseMediumBrush}\u0022/\u003E\u003C/StackPanel\u003E\u003C/StackPanel\u003E\u003C/Grid\u003E\u003C/DataTemplate\u003E\n\u003C!-- ...truncated --\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A control that presents a collection of items in rows and columns.","relatedControls":["ItemsView","ListView","FlipView","SemanticZoom"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"GridView - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.gridview"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/lists"}]},{"id":"gridview-3","controlId":"gridview","controlName":"GridView","headerText":"Content inside of a GridView.","xaml":"\u003C!-- The GridView used for this sample is shown below, with all of the necessary added properties. --\u003E\n\u003CGridView \n x:Name=\u0022ContentGridView\u0022\n ItemsSource=\u0022{x:Bind Items}\u0022\n ItemTemplate=\u0022{StaticResource ...}\u0022\n IsItemClickEnabled=\u0022...\u0022\n CanDragItems=\u0022...\u0022\n AllowDrop=\u0022...\u0022\n CanReorderItems=\u0022...\u0022\n SelectionMode=\u0022...\u0022\n SelectionChanged=\u0022ContentGridView_SelectionChanged\u0022\n ItemClick=\u0022ContentGridView_ItemClick\u0022 \n FlowDirection=\u0022...\u0022/\u003E\n\n\u003C!-- ContentGridView_SelectionChanged and ContentGridView_ItemClick are functions defined in the code-behind\nto handle the events of when a selection changes on the GridView and when an item is clicked. --\u003E\n \n\u003C!-- The data template bound to this GridView\u0027s ItemTemplate property is based on which one you\nselect from the options on the right. The currently selected DataTemplate is: --\u003E\n\n...","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A control that presents a collection of items in rows and columns.","relatedControls":["ItemsView","ListView","FlipView","SemanticZoom"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"GridView - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.gridview"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/lists"}]},{"id":"itemsrepeater-1","controlId":"itemsrepeater","controlName":"ItemsRepeater","headerText":"Basic, non-interactive items laid out by ItemsRepeater","xaml":"\u003C!-- The ItemsRepeater and ScrollViewer used: --\u003E\n\u003CScrollViewer HorizontalScrollBarVisibility=\u0022Auto\u0022 \n HorizontalScrollMode=\u0022Auto\u0022 \n IsVerticalScrollChainingEnabled=\u0022False\u0022\n MaxHeight=\u0022500\u0022\u003E\n \u003CItemsRepeater\n ItemsSource=\u0022{x:Bind BarItems}\u0022\n Layout=\u0022{StaticResource ...}\u0022\n ItemTemplate=\u0022{StaticResource ...}\u0022 /\u003E\n\u003C/ScrollViewer\u003E\n \n\u003C!-- The Layout specifications used: --\u003E\n \n... \n \n\u003C!-- The DataTemplate used: ...--\u003E\n \n...","csharp":"// The ItemsSource used is a list of custom-class Bar objects called BarItems\n\npublic class Bar\n{\n public Bar(double length, int max)\n {\n Length = length;\n MaxLength = max;\n\n Height = length / 4;\n MaxHeight = max / 4;\n\n Diameter = length / 6;\n MaxDiameter = max / 6;\n }\n public double Length { get; set; }\n public int MaxLength { get; set; }\n\n public double Height { get; set; }\n public double MaxHeight { get; set; }\n\n public double Diameter { get; set; }\n public double MaxDiameter { get; set; }\n}\n\npublic ObservableCollection\u003CBar\u003E BarItems;\nprivate int MaxLength = 425;\n\nprivate void InitializeData()\n{\n if (BarItems == null)\n {\n BarItems = new ObservableCollection\u003CBar\u003E();\n }\n BarItems.Add(new Bar(300, this.MaxLength));\n BarItems.Add(new Bar(25, this.MaxLength));\n BarItems.Add(new Bar(175, this.MaxLength));\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A flexible, primitive control for data-driven layouts.","relatedControls":["ItemsView","ScrollView","ScrollViewer","ListView","GridView"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"ItemsRepeater - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.itemsrepeater"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/items-repeater"},{"title":"StackLayout - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.stacklayout"},{"title":"UniformGridLayout - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.uniformgridlayout"}]},{"id":"itemsrepeater-2","controlId":"itemsrepeater","controlName":"ItemsRepeater","headerText":"Virtualizing, scrollable list of items laid out by ItemsRepeater","xaml":"\u003C!-- XAML Code --\u003E\n\n\u003C!-- The ItemsRepeater and ScrollViewer used: --\u003E\n\u003CScrollViewer x:Name=\u0022scrollViewer\u0022\n IsVerticalScrollChainingEnabled=\u0022False\u0022\n Padding=\u00220,0,16,0\u0022\u003E\n \u003CItemsRepeater\n ItemsSource=\u0022{x:Bind NumberedItems}\u0022\n Layout=\u0022{StaticResource ...}\u0022\n ItemTemplate=\u0022{StaticResource ...}\u0022 /\u003E\n\u003CScrollViewer/\u003E \n \n\u003C!-- The Layout specifications used: --\u003E\n \n... \n \n\u003C!-- The ItemTemplate is bound to a DataTemplateSelector called MyDataTemplateSelector. \nMyDataTemplateSelector is defined in the code-behind to return the Accent DataTemplate \nfor odd-numbered-items, and returns the Normal DataTemplate for even-numbered-items \n(shown in C# code-behind section below). The two data templates and the XAML declaration\nof MyDataTemplateSelector are below: --\u003E\n\n\u003CMyDataTemplateSelector x:Key=\u0022MyDataTemplateSelector\u0022\n Normal=\u0022{StaticResource NormalItemTemplate}\u0022\n Accent=\u0022{StaticResource AccentItemTemplate}\u0022/\u003E \n \n\u003CDataTemplate x:Key=\u0022NormalItemTemplate\u0022 x:DataType=\u0022x:Int32\u0022\u003E\n \u003CButton HorizontalAlignment=\u0022Stretch\u0022 VerticalAlignment=\u0022Stretch\u0022 \n\t Background=\u0022{ThemeResource SystemChromeLowColor}\u0022\u003E\n \u003CTextBlock Text=\u0022{x:Bind}\u0022 /\u003E\n \u003C/Button\u003E\n\u003C/DataTemplate\u003E\n\n\u003CDataTemplate x:Key=\u0022AccentItemTemplate\u0022 x:DataType=\u0022x:Int32\u0022\u003E\n \u003CButton HorizontalAlignment=\u0022Stretch\u0022 VerticalAlignment=\u0022Stretch\u0022 \n\t Background=\u0022{ThemeResource SystemAccentColor}\u0022\u003E\n \u003CTextBlock Text=\u0022{x:Bind}\u0022 /\u003E\n \u003C/Button\u003E\n\u003C/DataTemplate\u003E\n \n\u003C!-- The ItemsSource for this ItemsRepeater is a list of integers called NumberedItems.--\u003E\n \n\u003C!-- ActivityFeedLayout is a custom designed virtualizing layout that loads images only as you come \naccross them, defined in the code-behind. View the WinUI Gallery source code to see more\ndetails about this custom layout. --\u003E\u003C/ScrollViewer\u003E","csharp":"public class MyDataTemplateSelector : DataTemplateSelector\n{\n public DataTemplate? Normal { get; set; }\n public DataTemplate? Accent { get; set; }\n\n protected override DataTemplate? SelectTemplateCore(object item)\n {\n if ((int)item % 2 == 0)\n {\n return Normal;\n }\n else\n {\n return Accent;\n }\n }\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A flexible, primitive control for data-driven layouts.","relatedControls":["ItemsView","ScrollView","ScrollViewer","ListView","GridView"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"ItemsRepeater - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.itemsrepeater"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/items-repeater"},{"title":"StackLayout - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.stacklayout"},{"title":"UniformGridLayout - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.uniformgridlayout"}]},{"id":"itemsrepeater-3","controlId":"itemsrepeater","controlName":"ItemsRepeater","headerText":"ItemsRepeater with mixed-type collection","xaml":"\u003C!-- XAML Code --\u003E\n\n\u003C!-- This is the ItemsRepeater used in this example: --\u003E\n\u003CItemsRepeater x:Name=\u0022MixedTypeRepeater\u0022 \n Margin=\u00220,0,12,0\u0022\n HorizontalAlignment=\u0022Stretch\u0022\n ItemTemplate=\u0022{StaticResource StringOrIntTemplateSelector}\u0022\u003E\n\n \u003CItemsRepeater.Layout\u003E\n \u003CUniformGridLayout MinItemWidth=\u0022200\u0022 MinItemHeight=\u0022200\u0022/\u003E\n \u003C/ItemsRepeater.Layout\u003E\n\u003C/ItemsRepeater\u003E\n\n\u003C!-- The ItemsSource is bound in the C# code-behind to an ObservableCollection called \nStringsAndInts. StringsAndInts has both string objects and integer objects. The ItemTemplate\nis a DataTemplateSelector called StringOrIntTemplateSelector, and is defined in the \ncode-behind and shown in the C# code-behind section below. The layout is a simple \nUniformGridLayout where each item is a 200x200 square. --\u003E\n \n\u003C!-- StringOrIntTemplateSelector assesses the type of an item, and returns StringDataTemplate if \nthe item is a string, and IntDataTemplate if the item is an integer. \nThe XAML code directly below binds the DataTemplateSelector to those two data templates, and \ndefines each of them: --\u003E\n \n\u003CStringOrIntTemplateSelector x:Key=\u0022StringOrIntTemplateSelector\u0022\n StringTemplate=\u0022{StaticResource StringDataTemplate}\u0022\n IntTemplate=\u0022{StaticResource IntDataTemplate}\u0022/\u003E \n \n\u003CDataTemplate x:Key=\u0022StringDataTemplate\u0022 x:DataType=\u0022x:String\u0022\u003E\n \u003CGrid Background=\u0022{ThemeResource SystemControlBackgroundAccentBrush}\u0022 Margin=\u002210\u0022\u003E\n \u003CTextBlock Padding=\u002210\u0022 Text=\u0022{x:Bind}\u0022 \n Foreground=\u0022{ThemeResource SystemControlForegroundChromeWhiteBrush}\u0022\n HorizontalAlignment=\u0022Center\u0022 TextWrapping=\u0022Wrap\u0022 \n VerticalAlignment=\u0022Center\u0022/\u003E\n \u003C/Grid\u003E\n\u003C/DataTemplate\u003E\n\n\u003CDataTemplate x:Key=\u0022IntDataTemplate\u0022 x:DataType=\u0022x:Int32\u0022\u003E\u003C/DataTemplate\u003E\n\u003C!-- ...truncated --\u003E","csharp":"public class StringOrIntTemplateSelector : DataTemplateSelector\n{\n // Define the (currently empty) data templates to return\n // These will be \u0022filled-in\u0022 in the XAML code.\n public DataTemplate? StringTemplate { get; set; }\n\n public DataTemplate? IntTemplate { get; set; }\n\n protected override DataTemplate? SelectTemplateCore(object item)\n {\n // Return the correct data template based on the item\u0027s type.\n if (item.GetType() == typeof(String))\n {\n return StringTemplate;\n }\n else if (item.GetType() == typeof(int))\n {\n return IntTemplate;\n }\n else\n {\n return null;\n }\n }\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A flexible, primitive control for data-driven layouts.","relatedControls":["ItemsView","ScrollView","ScrollViewer","ListView","GridView"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"ItemsRepeater - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.itemsrepeater"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/items-repeater"},{"title":"StackLayout - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.stacklayout"},{"title":"UniformGridLayout - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.uniformgridlayout"}]},{"id":"itemsrepeater-4","controlId":"itemsrepeater","controlName":"ItemsRepeater","headerText":"Laying out nested ItemsRepeaters","xaml":"\u003C!-- The nested ItemsRepeater experience is achieved by creating one ItemsRepeater (outerRepeater below) \nand creating another ItemsRepeater (innerRepeater below) inside the outer one\u0027s DataTemplate. Below is \nthe outer ItemsRepeater definition and the DataTemplate it uses. --\u003E\n \n\u003CScrollViewer HorizontalScrollMode=\u0022Auto\u0022 HorizontalScrollBarVisibility=\u0022Auto\u0022\u003E\n \u003CItemsRepeater \n x:Name=\u0022outerRepeater\u0022\n VerticalAlignment=\u0022Top\u0022\n ItemTemplate =\u0022{StaticResource CategoryTemplate}\u0022\u003E\n \u003CItemsRepeater.Layout\u003E\n \u003CStackLayout Orientation=\u0022Vertical\u0022 /\u003E\n \u003C/ItemsRepeater.Layout\u003E\n \u003C/ItemsRepeater\u003E\n\u003C/ScrollViewer\u003E\n \n\u003CDataTemplate x:Key=\u0022CategoryTemplate\u0022 x:DataType=\u0022l:NestedCategory\u0022\u003E\n \u003CStackPanel\u003E\n \u003CTextBlock Text=\u0022{x:Bind CategoryName}\u0022 Padding=\u00228\u0022 Style=\u0022{StaticResource TitleTextBlockStyle}\u0022/\u003E\n \u003CItemsRepeater x:Name=\u0022innerRepeater\u0022\n ItemsSource=\u0022{x:Bind CategoryItems}\u0022\n ItemTemplate=\u0022{StaticResource StringDataTemplateColor}\u0022\u003E\n \u003CItemsRepeater.Layout\u003E\n \u003CStackLayout Orientation=\u0022Horizontal\u0022 /\u003E\n \u003C/ItemsRepeater.Layout\u003E\n \u003C/ItemsRepeater\u003E\n \u003C/StackPanel\u003E\n\u003C/DataTemplate\u003E\n \n\u003C!-- The DataTemplate shown above is bound to a custom-class type called NestedCategory, \nwhich is defined in the code-behind. NestedCategory objects have the following two attributes: \na CategoryName (string), and a collection of strings called CategoryItems. --\u003E\n \n\u003C!-- The inner ItemsRepeater is bound to its own, separate DataTemplate called StringDataTemplateColor: --\u003E\n \n\u003CDataTemplate x:Key=\u0022StringDataTemplateColor\u0022 x:DataType=\u0022x:String\u0022\u003E\n \u003CGrid Background=\u0022{StaticResource SystemControlBackgroundAccentBrush}\u0022 Margin=\u002210, 0, 10 10\u0022\u003E\u003C/Grid\u003E\u003C/DataTemplate\u003E\n\u003C!-- ...truncated --\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A flexible, primitive control for data-driven layouts.","relatedControls":["ItemsView","ScrollView","ScrollViewer","ListView","GridView"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"ItemsRepeater - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.itemsrepeater"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/items-repeater"},{"title":"StackLayout - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.stacklayout"},{"title":"UniformGridLayout - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.uniformgridlayout"}]},{"id":"itemsrepeater-5","controlId":"itemsrepeater","controlName":"ItemsRepeater","headerText":"Animated Scrolling and Content Display","xaml":"\u003C!-- XAML Code --\u003E\n\n\u003C!-- The below code shows the XAML for the ItemsRepeater as well as the\ncolor-changing rectangle besides it. --\u003E\n\n\u003CGrid\u003E\n \u003CGrid.ColumnDefinitions\u003E\n \u003CColumnDefinition Width=\u00221*\u0022/\u003E\n \u003CColumnDefinition Width=\u00221*\u0022/\u003E\n \u003C/Grid.ColumnDefinitions\u003E\n\n \u003CScrollViewer x:Name=\u0022Animated_ScrollViewer\u0022 \n Grid.Column=\u00220\u0022\n ViewChanging=\u0022Animated_ScrollViewer_ViewChanging\u0022\u003E\n \u003CItemsRepeater x:Name=\u0022animatedScrollRepeater\u0022 \u003E\n \u003CItemsRepeater.ItemTemplate\u003E\n \u003CDataTemplate x:DataType=\u0022x:String\u0022\u003E\n \u003CButton Content=\u0022{x:Bind}\u0022\n Background=\u0022{x:Bind}\u0022\n Click=\u0022Animated_GotItem\u0022 \n GotFocus=\u0022Animated_GotItem\u0022 \n HorizontalAlignment=\u0022Stretch\u0022\n Foreground=\u0022{ThemeResource ButtonForeground}\u0022/\u003E\n \u003C/DataTemplate\u003E\n \u003C/ItemsRepeater.ItemTemplate\u003E\n \u003C/ItemsRepeater\u003E\n \u003C/ScrollViewer\u003E\n\n \u003CRectangle x:Name=\u0022colorRectangle\u0022\n Grid.Column=\u00221\u0022\n Stroke=\u0022Black\u0022\n Margin=\u002210,0,0,0\u0022/\u003E\n\u003C/Grid\u003E","csharp":"// Initialization code\n\nprivate double AnimatedBtnHeight;\nprivate Microsoft.UI.Xaml.Thickness AnimatedBtnMargin;\n\nprivate void InitializeData()\n{\n\n IList\u003Cstring\u003E colors = new List\u003CString\u003E()\n {\n \u0022Blue\u0022,\n \u0022BlueViolet\u0022,\n \u0022Crimson\u0022,\n \u0022DarkCyan\u0022,\n \u0022DarkGoldenrod\u0022,\n \u0022DarkMagenta\u0022,\n \u0022DarkOliveGreen\u0022,\n \u0022DarkRed\u0022,\n \u0022DarkSlateBlue\u0022,\n \u0022DeepPink\u0022,\n \u0022IndianRed\u0022,\n \u0022MediumSlateBlue\u0022,\n \u0022Maroon\u0022,\n \u0022MidnightBlue\u0022,\n \u0022Peru\u0022,\n \u0022SaddleBrown\u0022,\n \u0022SteelBlue\u0022,\n \u0022OrangeRed\u0022,\n \u0022Firebrick\u0022,\n \u0022DarkKhaki\u0022\n };\n\n animatedScrollRepeater.ItemsSource = colors;\n animatedScrollRepeater.ElementPrepared \u002B= OnElementPrepared;\n}\n\n// Animation code\n\nprivate void Animated_GotItem(object sender, RoutedEventArgs e)\n{\n if (sender is not Button senderBtn)\n {\n return;\n }\n\n // When the clicked item has been recieved, bring it to the middle of the viewport.\n senderBtn.StartBringIntoView(new BringIntoViewOptions()\n {\n VerticalAlignmentRatio = 0.5,\n AnimationDesired = true,\n });\n\n // Update corresponding rectangle with selected color\n colorRectangle.Fill = senderBtn.Background;\n}\n// NOTE: snippet truncated \u2014 refer to full sample for additional code","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A flexible, primitive control for data-driven layouts.","relatedControls":["ItemsView","ScrollView","ScrollViewer","ListView","GridView"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"ItemsRepeater - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.itemsrepeater"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/items-repeater"},{"title":"StackLayout - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.stacklayout"},{"title":"UniformGridLayout - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.uniformgridlayout"}]},{"id":"itemsrepeater-6","controlId":"itemsrepeater","controlName":"ItemsRepeater","headerText":"Virtualized, Content-Heavy Layout with Filtering and Sorting","xaml":"\u003C!-- XAML Code: --\u003E\n\u003CItemsRepeaterScrollHost\u003E\n \u003CScrollViewer\u003E\n \u003CItemsRepeater x:Name=\u0022VariedImageSizeRepeater\u0022 \n\t\t\t ItemTemplate=\u0022{StaticResource RecipeTemplate}\u0022\u003E\n\t \n \u003C!-- IMPORTANT: This ItemsRepeater uses a custom-created layout \n\t\tcalled VariedImageSize Layout (referenced below).You can find \n \t\tthe full source code for this layout in the file \n\t\tVariedImageSizeLayout.cs in the WinUI Gallery repo. --\u003E\n\n \u003CItemsRepeater.Layout\u003E\n \u003Ccommon:VariedImageSizeLayout Width=\u0022200\u0022 /\u003E\n \u003C/ItemsRepeater.Layout\u003E\n \u003C/ItemsRepeater\u003E\n \u003C/ScrollViewer\u003E\n\u003C/ItemsRepeaterScrollHost\u003E\n\n\u003C!-- DataTemplate used: --\u003E\n\u003C!-- This repeater holds Recipe objects, which is a custom class defined in \n the code-behind, and shown below. --\u003E\n\u003CDataTemplate x:DataType=\u0022l:Recipe\u0022 x:Key=\u0022RecipeTemplate\u0022\u003E\n \u003CStackPanel BorderThickness=\u00221\u0022 Background=\u0022LightGray\u0022 Margin=\u00225\u0022\u003E\n \u003CStackPanel Background=\u0022{x:Bind Color}\u0022 Margin=\u00228\u0022 Height=\u002275\u0022 Opacity=\u0022.8\u0022\u003E\n \u003CTextBlock Text=\u0022{x:Bind Num.ToString()}\u0022 FontSize=\u002235\u0022 TextAlignment=\u0022Center\u0022 \n Padding=\u002212\u0022 Foreground=\u0022{ThemeResource SystemControlForegroundAltHighBrush}\u0022/\u003E\n \u003C/StackPanel\u003E\n \u003CTextBlock \n x:Name=\u0022recipeName\u0022 \n Text=\u0022{x:Bind Name}\u0022\n TextWrapping=\u0022Wrap\u0022\n Margin=\u002215,0,10,0\u0022 \n Style=\u0022{StaticResource TitleTextBlockStyle}\u0022/\u003E\n \u003CTextBlock Text=\u0022{x:Bind Ingredients}\u0022 Style=\u0022{StaticResource BodyTextBlockStyle}\u0022 Margin=\u002215,0,15,15\u0022/\u003E\n \u003C/StackPanel\u003E\n\u003C/DataTemplate\u003E","csharp":"// ========================== Recipe class used for items ========================== \npublic class Recipe\n{\n public int Num { get; set; }\n public string Ingredients { get; set; } = string.Empty;\n public List\u003Cstring\u003E IngList { get; set; } = [];\n public string Name { get; set; } = string.Empty;\n public string Color { get; set; } = string.Empty;\n public int numIngredients\n {\n get\n {\n return IngList.Count();\n }\n }\n\n public void RandomizeIngredients()\n {\n // To give the items different heights for visual variety, give recipes \n // random numbers of random \u0022extra\u0022 ingredients\n Random rndNum = new Random();\n Random rndIng = new Random();\n\n ObservableCollection\u003Cstring\u003E extras = new ObservableCollection\u003Cstring\u003E{\n \u0022Garlic\u0022,\n \u0022Lemon\u0022,\n \u0022Butter\u0022,\n \u0022Lime\u0022,\n \u0022Feta Cheese\u0022,\n \u0022Parmesan Cheese\u0022,\n \u0022Breadcrumbs\u0022};\n for (int i =0; i \u003C rndNum.Next(0,4); i\u002B\u002B)\n {\n string newIng = extras[rndIng.Next(0, 6)];\n // If the ingredient is not already present in the recipe, add it\n if (!IngList.Contains(newIng))\n {\n Ingredients \u002B= \u0022\\n\u0022 \u002B newIng;\n IngList.Add(newIng);\n }\n }\n\n }\n}\n// NOTE: snippet truncated \u2014 refer to full sample for additional code","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A flexible, primitive control for data-driven layouts.","relatedControls":["ItemsView","ScrollView","ScrollViewer","ListView","GridView"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"ItemsRepeater - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.itemsrepeater"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/items-repeater"},{"title":"StackLayout - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.stacklayout"},{"title":"UniformGridLayout - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.uniformgridlayout"}]},{"id":"itemsview-1","controlId":"itemsview","controlName":"ItemsView","headerText":"Basic ItemsView","xaml":"\u003CDataTemplate x:Key=\u0022ImageTemplate\u0022 x:DataType=\u0022local:CustomDataObject\u0022\u003E\n \u003CItemContainer HorizontalAlignment=\u0022Left\u0022 Width=\u0022200\u0022 Height=\u0022140\u0022 AutomationProperties.Name=\u0022{x:Bind Title}\u0022\u003E\n \u003CImage Stretch=\u0022UniformToFill\u0022 HorizontalAlignment=\u0022Center\u0022 VerticalAlignment=\u0022Center\u0022 Source=\u0022{x:Bind ImageLocation}\u0022 Margin=\u00224\u0022 AutomationProperties.AccessibilityView=\u0022Raw\u0022/\u003E\n \u003C/ItemContainer\u003E\n\u003C/DataTemplate\u003E\n\n\u003CItemsView Width=\u0022220\u0022 Height=\u0022400\u0022 HorizontalAlignment=\u0022Left\u0022\n ItemTemplate=\u0022{StaticResource ImageTemplate}\u0022 IsItemInvokedEnabled=\u0022True\u0022 ItemInvoked=\u0022BasicItemsView_ItemInvoked\u0022/\u003E","csharp":"private void BasicItemsView_ItemInvoked(ItemsView sender, ItemsViewItemInvokedEventArgs e)\n{\n tblBasicInvokeOutput.Text = \u0022You invoked \u0022 \u002B (e.InvokedItem as CustomDataObject).Title \u002B \u0022.\u0022;\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A control that presents a collection of items using various layouts.","relatedControls":["AnnotatedScrollBar","ItemsRepeater","ListView","GridView","ScrollView"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"ItemsView - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.itemsview"},{"title":"CollectionViewSource - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Data.CollectionViewSource"}]},{"id":"itemsview-2","controlId":"itemsview","controlName":"ItemsView","headerText":"ItemsView with swappable layouts","xaml":"\u003CDataTemplate x:Key=\u0022LinedFlowLayoutItemTemplate\u0022 x:DataType=\u0022local:CustomDataObject\u0022\u003E\n \u003CItemContainer AutomationProperties.Name=\u0022{x:Bind Title}\u0022\u003E\n \u003CGrid\u003E\n \u003CImage Source=\u0022{x:Bind ImageLocation}\u0022 Stretch=\u0022UniformToFill\u0022 HorizontalAlignment=\u0022Center\u0022 VerticalAlignment=\u0022Center\u0022 MinWidth=\u002270\u0022/\u003E\n \u003CStackPanel Orientation=\u0022Vertical\u0022 Height=\u002240\u0022 VerticalAlignment=\u0022Bottom\u0022 Padding=\u00225,1,5,1\u0022 Background=\u0022{ThemeResource SystemControlBackgroundBaseMediumBrush}\u0022 Opacity=\u0022.75\u0022\u003E\n \u003CTextBlock Text=\u0022{x:Bind Title}\u0022 Foreground=\u0022{ThemeResource SystemControlForegroundAltHighBrush}\u0022/\u003E\n \u003CStackPanel Orientation=\u0022Horizontal\u0022\u003E\n \u003CTextBlock Text=\u0022{x:Bind Likes}\u0022 Style=\u0022{ThemeResource CaptionTextBlockStyle}\u0022 Foreground=\u0022{ThemeResource SystemControlForegroundAltHighBrush}\u0022/\u003E\n \u003CTextBlock Text=\u0022 Likes\u0022 Style=\u0022{ThemeResource CaptionTextBlockStyle}\u0022 Foreground=\u0022{ThemeResource SystemControlForegroundAltHighBrush}\u0022/\u003E\n \u003C/StackPanel\u003E\n \u003C/StackPanel\u003E\n \u003C/Grid\u003E\n \u003C/ItemContainer\u003E\n\u003C/DataTemplate\u003E\n\n\u003CItemsView Width=\u0022500\u0022 Height=\u0022400\u0022 HorizontalAlignment=\u0022Left\u0022\n ItemTemplate=\u0022{StaticResource LinedFlowLayoutItemTemplate}\u0022\u003E\n \u003CItemsView.Layout\u003E\n \u003CLinedFlowLayout ItemsStretch=\u0022Fill\u0022 LineHeight=\u0022160\u0022 LineSpacing=\u00225\u0022 MinItemSpacing=\u00225\u0022/\u003E\n \u003C/ItemsView.Layout\u003E\n\u003C/ItemsView\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A control that presents a collection of items using various layouts.","relatedControls":["AnnotatedScrollBar","ItemsRepeater","ListView","GridView","ScrollView"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"ItemsView - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.itemsview"},{"title":"CollectionViewSource - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Data.CollectionViewSource"}]},{"id":"itemsview-3","controlId":"itemsview","controlName":"ItemsView","headerText":"ItemsView item invocation and selection","xaml":"\u003CDataTemplate x:Key=\u0022UniformGridLayoutItemTemplate\u0022 x:DataType=\u0022local:CustomDataObject\u0022\u003E\n \u003CItemContainer AutomationProperties.Name=\u0022{x:Bind Title}\u0022\u003E\n \u003CGrid Width=\u0022150\u0022\u003E\n \u003CImage Source=\u0022{x:Bind ImageLocation}\u0022 Stretch=\u0022UniformToFill\u0022 HorizontalAlignment=\u0022Center\u0022 VerticalAlignment=\u0022Center\u0022/\u003E\n \u003CStackPanel Orientation=\u0022Vertical\u0022 Height=\u002240\u0022 VerticalAlignment=\u0022Bottom\u0022 Padding=\u00225,1,5,1\u0022 Background=\u0022{ThemeResource SystemControlBackgroundBaseMediumBrush}\u0022 Opacity=\u0022.75\u0022\u003E\n \u003CTextBlock Text=\u0022{x:Bind Title}\u0022 Foreground=\u0022{ThemeResource SystemControlForegroundAltHighBrush}\u0022/\u003E\n \u003CStackPanel Orientation=\u0022Horizontal\u0022\u003E\n \u003CTextBlock Text=\u0022{x:Bind Likes}\u0022 Style=\u0022{ThemeResource CaptionTextBlockStyle}\u0022 Foreground=\u0022{ThemeResource SystemControlForegroundAltHighBrush}\u0022/\u003E\n \u003CTextBlock Text=\u0022 Likes\u0022 Style=\u0022{ThemeResource CaptionTextBlockStyle}\u0022 Foreground=\u0022{ThemeResource SystemControlForegroundAltHighBrush}\u0022/\u003E\n \u003C/StackPanel\u003E\n \u003C/StackPanel\u003E\n \u003C/Grid\u003E\n \u003C/ItemContainer\u003E\n\u003C/DataTemplate\u003E\n\n\u003CItemsView Width=\u0022500\u0022 Height=\u0022400\u0022 HorizontalAlignment=\u0022Left\u0022\n SelectionMode=\u0022...\u0022\n IsItemInvokedEnabled=\u0022...\u0022\n ItemTemplate=\u0022{StaticResource UniformGridLayoutItemTemplate}\u0022\n ItemInvoked=\u0022SwappableSelectionModesItemsView_ItemInvoked\u0022\n SelectionChanged=\u0022SwappableSelectionModesItemsView_SelectionChanged\u0022\u003E\n \u003CItemsView.Layout\u003E\n \u003CUniformGridLayout MinRowSpacing=\u00225\u0022 MinColumnSpacing=\u00225\u0022 MaximumRowsOrColumns=\u00223\u0022/\u003E\n \u003C/ItemsView.Layout\u003E\n\u003C/ItemsView\u003E","csharp":"private void SwappableSelectionModesItemsView_ItemInvoked(ItemsView sender, ItemsViewItemInvokedEventArgs e)\n{\n tblInvocationOutput.Text = \u0022You invoked \u0022 \u002B (e.InvokedItem as CustomDataObject).Title \u002B \u0022.\u0022;\n}\n\nprivate void SwappableSelectionModesItemsView_SelectionChanged(ItemsView sender, ItemsViewSelectionChangedEventArgs e)\n{\n tblSelectionOutput.Text = string.Format(\u0022You have selected {0} item(s).\u0022, SwappableSelectionModesItemsView.SelectedItems.Count);\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A control that presents a collection of items using various layouts.","relatedControls":["AnnotatedScrollBar","ItemsRepeater","ListView","GridView","ScrollView"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"ItemsView - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.itemsview"},{"title":"CollectionViewSource - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Data.CollectionViewSource"}]},{"id":"listview-1","controlId":"listview","controlName":"ListView","headerText":"Basic ListView with Simple DataTemplate","xaml":"\u003C!-- XAML Code --\u003E\n\n\u003CListView\n x:Name=\u0022BaseExample\u0022\n ItemTemplate=\u0022{StaticResource ContactListViewTemplate}\u0022\n BorderThickness=\u00221\u0022\n BorderBrush=\u0022{ThemeResource SystemControlForegroundBaseMediumLowBrush}\u0022\n HorizontalAlignment=\u0022Left\u0022/\u003E\n \n\u003C!-- In this example, the ListView\u0027s ItemTemplate property is bound to a data template (shown below)\ncalled ContactListViewTemplate, defined in a Page.Resources section. --\u003E\n \n\u003CDataTemplate x:Key=\u0022ContactListViewTemplate\u0022 x:DataType=\u0022local:Contact\u0022\u003E\n \u003CTextBlock Text=\u0022{x:Bind Name}\u0022 x:Phase=\u00221\u0022 Margin=\u00220,5,0,5\u0022/\u003E\n\u003C/DataTemplate\u003E","csharp":"// The data template is defined to display a Contact object (class definition shown below), and the text \n// displayed is bound to the Contact object\u0027s Name attribute.\n\npublic class Contact\n{\n public string FirstName { get; private set; } = string.Empty;\n public string LastName { get; private set; } = string.Empty;\n public string Company { get; private set; } = string.Empty;\n public string Name =\u003E FirstName \u002B \u0022 \u0022 \u002B LastName;\n\n public Contact(string firstName, string lastName, string company)\n {\n FirstName = firstName;\n LastName = lastName;\n Company = company;\n } \n}\n \n// The ItemsSource for the ListView is generated by a method of the Contact class called \n// GetContactsAsync().This method pulls data from an internal data source and creates \n// Contact objects from that data. Those Contact objects are placed in a collection \n// which is returned from the GetContactsAsync() function.\n\nBaseExample.ItemsSource = await Contact.GetContactsAsync();","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A control that presents a collection of items in a vertical list.","relatedControls":["ItemsView","GridView","StandardUICommand","FlipView","SemanticZoom"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"ListView - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.listview"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/listview-and-gridview"},{"title":"Drag and Drop - Full Sample","uri":"https://github.com/microsoft/Windows-universal-samples/tree/master/Samples/XamlDragAndDrop"},{"title":"CollectionViewSource - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Data.CollectionViewSource"},{"title":"Filtering collections and lists through user input","uri":"https://learn.microsoft.com/windows/apps/design/controls/listview-filtering"},{"title":"Inverted Lists","uri":"https://learn.microsoft.com/windows/apps/design/controls/inverted-lists"},{"title":"Inverted Lists - Full Sample","uri":"https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/XamlBottomUpList"}]},{"id":"listview-2","controlId":"listview","controlName":"ListView","headerText":"ListView with Selection Support","xaml":"\u003C!-- To create this sample, add/change the following properties onto the code for the base example above: --\u003E\n \n\u003CListView \n SelectionMode=\u0022...\u0022 \n ItemTemplate=\u0022{StaticResource ContactListViewTemplate}\u0022/\u003E\n \n\u003C!-- DataTemplate used: --\u003E\n\n\u003CDataTemplate x:Key=\u0022ContactListViewTemplate\u0022 x:DataType=\u0022local:Contact\u0022\u003E\n \u003CGrid\u003E\n \u003CGrid.RowDefinitions\u003E\n \u003CRowDefinition Height=\u0022*\u0022/\u003E\n \u003CRowDefinition Height=\u0022*\u0022/\u003E\n \u003C/Grid.RowDefinitions\u003E\n \u003CGrid.ColumnDefinitions\u003E\n \u003CColumnDefinition Width=\u0022Auto\u0022/\u003E\n \u003CColumnDefinition Width=\u0022*\u0022/\u003E\n \u003C/Grid.ColumnDefinitions\u003E\n \u003CEllipse x:Name=\u0022Ellipse\u0022\n Grid.RowSpan=\u00222\u0022\n Width =\u002232\u0022\n Margin=\u00226\u0022\n VerticalAlignment=\u0022Center\u0022\n HorizontalAlignment=\u0022Center\u0022\n Fill=\u0022{ThemeResource SystemControlBackgroundBaseMediumBrush}\u0022/\u003E\n \u003CTextBlock Grid.Column=\u00221\u0022\n Text=\u0022{x:Bind Name}\u0022\n x:Phase=\u00221\u0022\n Style=\u0022{ThemeResource BaseTextBlockStyle}\u0022\n Margin=\u002212,6,0,0\u0022/\u003E\n \u003CTextBlock Grid.Column=\u00221\u0022\n Grid.Row=\u00221\u0022\n Text=\u0022{x:Bind Company}\u0022\n x:Phase=\u00222\u0022\n Style=\u0022{ThemeResource BodyTextBlockStyle}\u0022\n Margin=\u002212,0,0,6\u0022/\u003E\n \u003C/Grid\u003E\n\u003C/DataTemplate\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A control that presents a collection of items in a vertical list.","relatedControls":["ItemsView","GridView","StandardUICommand","FlipView","SemanticZoom"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"ListView - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.listview"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/listview-and-gridview"},{"title":"Drag and Drop - Full Sample","uri":"https://github.com/microsoft/Windows-universal-samples/tree/master/Samples/XamlDragAndDrop"},{"title":"CollectionViewSource - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Data.CollectionViewSource"},{"title":"Filtering collections and lists through user input","uri":"https://learn.microsoft.com/windows/apps/design/controls/listview-filtering"},{"title":"Inverted Lists","uri":"https://learn.microsoft.com/windows/apps/design/controls/inverted-lists"},{"title":"Inverted Lists - Full Sample","uri":"https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/XamlBottomUpList"}]},{"id":"listview-3","controlId":"listview","controlName":"ListView","headerText":"ListViews with Drag, Drop, and Reordering Support","xaml":"\u003C!-- Full code to implement dragging and dropping between lists can be found in the \nsource code for the WinUI Gallery. --\u003E\n\n\u003C!-- The following properties should be added to the ListView definitions to build this sample. --\u003E\n\u003CListView CanDragItems=\u0022True\u0022 CanReorderItems=\u0022True\u0022 AllowDrop=\u0022True\u0022\n SelectionMode=\u0022Single\u0022 /\u003E\n \n\u003C!-- DataTemplate used is the same as the above sample. --\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A control that presents a collection of items in a vertical list.","relatedControls":["ItemsView","GridView","StandardUICommand","FlipView","SemanticZoom"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"ListView - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.listview"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/listview-and-gridview"},{"title":"Drag and Drop - Full Sample","uri":"https://github.com/microsoft/Windows-universal-samples/tree/master/Samples/XamlDragAndDrop"},{"title":"CollectionViewSource - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Data.CollectionViewSource"},{"title":"Filtering collections and lists through user input","uri":"https://learn.microsoft.com/windows/apps/design/controls/listview-filtering"},{"title":"Inverted Lists","uri":"https://learn.microsoft.com/windows/apps/design/controls/inverted-lists"},{"title":"Inverted Lists - Full Sample","uri":"https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/XamlBottomUpList"}]},{"id":"listview-4","controlId":"listview","controlName":"ListView","headerText":"ListView with Grouped Headers","xaml":"\u003C!-- XAML Code --\u003E\n\n\u003C!-- ListViews with grouped items must be bound to a CollectionViewSource, as shown below.\nThis CollectionViewSource is defined in the XAML below, but is bound to an ItemsSource in the C#\ncode-behind. See the C# code below for more details on how to create/bind to a grouped list. --\u003E\n\n\u003CCollectionViewSource x:Name=\u0022ContactsCVS\u0022 IsSourceGrouped=\u0022True\u0022/\u003E\n \n\u003CListView ItemsSource=\u0022{x:Bind ContactsCVS.View, Mode=OneWay}\u0022\u003E\n \u003CListView.ItemsPanel\u003E\n \u003CItemsPanelTemplate\u003E\n \u003CItemsStackPanel AreStickyGroupHeadersEnabled=\u0022...\u0022/\u003E\n \u003C/ItemsPanelTemplate\u003E\n \u003C/ListView.ItemsPanel\u003E\n \u003CListView.GroupStyle\u003E\n \u003CGroupStyle \u003E\n \u003CGroupStyle.HeaderTemplate\u003E\n \u003CDataTemplate x:DataType=\u0022local:GroupInfoList\u0022\u003E\n \u003CBorder AutomationProperties.AccessibilityView=\u0022Raw\u0022\u003E\n \u003CTextBlock Text=\u0022{x:Bind Key}\u0022 Style=\u0022{ThemeResource TitleTextBlockStyle}\u0022 AutomationProperties.AccessibilityView=\u0022Raw\u0022/\u003E\n \u003C/Border\u003E\n \u003C/DataTemplate\u003E\n \u003C/GroupStyle.HeaderTemplate\u003E\n \u003C/GroupStyle\u003E\n \u003C/ListView.GroupStyle\u003E\n\u003C/ListView\u003E\n \n\u003C!-- Data template used is same as above examples. --\u003E","csharp":"// To create a collection of grouped items, create a query that groups\n// an existing list, or returns a grouped collection from a database.\n// The following method is used to create the ItemsSource for our CollectionViewSource:\n\npublic static async Task\u003CObservableCollection\u003CGroupInfoList\u003E\u003E GetContactsGroupedAsync()\n{\n // Grab Contact objects from pre-existing list (list is returned from function GetContactsAsync())\n var query = from item in await GetContactsAsync()\n\n // Group the items returned from the query, sort and select the ones you want to keep\n group item by item.LastName.Substring(0, 1).ToUpper() into g\n orderby g.Key\n\n // GroupInfoList is a simple custom class that has an IEnumerable type attribute, and\n // a key attribute. The IGrouping-typed variable g now holds the Contact objects, \n // and these objects will be used to create a new GroupInfoList object.\n select new GroupInfoList(g) { Key = g.Key };\n \n return new ObservableCollection\u003CGroupInfoList\u003E(query);\n}\n\n// GroupInfoList class definition:\npublic class GroupInfoList : List\u003Cobject\u003E\n{\n public GroupInfoList(IEnumerable\u003Cobject\u003E items) : base(items)\n {\n }\n\n public object Key { get; set; }\n\n public override string ToString()\n {\n return \u0022Group \u0022 \u002B Key.ToString();\n }\n}\n\n// Contact class definition:\npublic class Contact\n{\n public string FirstName { get; private set; } = string.Empty;\n public string LastName { get; private set; } = string.Empty;\n public string Company { get; private set; } = string.Empty;\n public string Name =\u003E FirstName \u002B \u0022 \u0022 \u002B LastName;\n\n public Contact(string firstName, string lastName, string company)\n {\n FirstName = firstName;\n LastName = lastName;\n Company = company;\n }\n\n // ... Methods ...\n}\n\nContactsCVS.Source = await Contact.GetContactsGroupedAsync();","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A control that presents a collection of items in a vertical list.","relatedControls":["ItemsView","GridView","StandardUICommand","FlipView","SemanticZoom"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"ListView - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.listview"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/listview-and-gridview"},{"title":"Drag and Drop - Full Sample","uri":"https://github.com/microsoft/Windows-universal-samples/tree/master/Samples/XamlDragAndDrop"},{"title":"CollectionViewSource - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Data.CollectionViewSource"},{"title":"Filtering collections and lists through user input","uri":"https://learn.microsoft.com/windows/apps/design/controls/listview-filtering"},{"title":"Inverted Lists","uri":"https://learn.microsoft.com/windows/apps/design/controls/inverted-lists"},{"title":"Inverted Lists - Full Sample","uri":"https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/XamlBottomUpList"}]},{"id":"listview-5","controlId":"listview","controlName":"ListView","headerText":"ListView with filtering","xaml":"\u003C!-- XAML Code --\u003E\n\n\u003C!-- The ListView\u0027s ItemsSource is an ObservableCollection\u003CContact\u003E that is defined and bound\nin the code-behind, called contactsFiltered. This ListView uses the same DataTemplate as the\nsamples above it, called ContactListViewTemplate - you can see its definition above. --\u003E\n\n\u003CListView \n x:Name=\u0022FilteredListView\u0022\n ItemTemplate=\u0022{StaticResource ContactListViewTemplate}\u0022\n SelectionMode=\u0022Single\u0022\n ShowsScrollingPlaceholders=\u0022True\u0022\n BorderThickness=\u00221\u0022\n BorderBrush=\u0022{ThemeResource SystemControlForegroundBaseMediumLowBrush}\u0022/\u003E\n\n\u003C!-- The textboxes used for filtering are shown below: --\u003E\n\u003CStackPanel Width=\u0022200\u0022\u003E\n \u003CTextBlock Margin=\u00228,8,8,4\u0022 Style=\u0022{ThemeResource BaseTextBlockStyle}\u0022\u003EFilter by...\u003C/TextBlock\u003E\n \u003CTextBox x:Name=\u0022FilterByFirstName\u0022 Width=\u0022150\u0022 Header=\u0022First name\u0022 Margin=\u00228\u0022\n\t HorizontalAlignment=\u0022Left\u0022 TextChanged=\u0022OnFilterChanged\u0022/\u003E\n \u003CTextBox x:Name=\u0022FilterByLastName\u0022 Width=\u0022150\u0022 Header=\u0022Last name\u0022 Margin=\u00228\u0022\n\t HorizontalAlignment=\u0022Left\u0022 TextChanged=\u0022OnFilterChanged\u0022/\u003E\n \u003CTextBox x:Name=\u0022FilterByCompany\u0022 Width=\u0022150\u0022 Header=\u0022Company\u0022 Margin=\u00228\u0022 \n\t HorizontalAlignment=\u0022Left\u0022 TextChanged=\u0022OnFilterChanged\u0022/\u003E\n\u003C/StackPanel\u003E","csharp":"// Make sure to add this to your declarations at the top for the filtering method:\nusing System.Linq;\n// ...\n\n// Define an ObservableCollection\u003CContact\u003E object to serve as the ListView\u0027s\n// ItemsSource. This collection will get updated after the filters are used:\nObservableCollection\u003CContact\u003E contactsFiltered = new ObservableCollection\u003CContact\u003E();\n\n/* Populate contactsFiltered with all contact objects (in this case, contacts holds\nall of our Contact objects so we copy them into contactsFiltered). Set this newly populated\ncollection as the ItemsSource for the ListView. */\ncontactsFiltered = new ObservableCollection\u003CContact\u003E(allContacts);\nFilteredListView.ItemsSource = contactsFiltered;\n\n// Whenever text changes in any of the filtering text boxes, the following function is called:\nprivate void OnFilterChanged(object sender, TextChangedEventArgs args)\n{\n // This is a Linq query that selects only items that return True after being passed through\n // the Filter function, and adds all of those selected items to filtered.\n var filtered = allContacts.Where(contact =\u003E Filter(contact));\n Remove_NonMatching(filtered);\n AddBack_Contacts(filtered);\n}\n\n// The following functions are called inside OnFilterChanged:\n\n/* When the text in any filter is changed, perform a check on each item in the original \ncontact list to see if the item should be displayed, taking into account all three of the\nfilters currently applied. If the item passes all three checks for all three filters, \nthe function returns true and the item is added to the filtered list above. */\nprivate bool Filter(Contact contact)\n{\n return contact.FirstName.Contains(FilterByFirstName.Text, StringComparison.InvariantCultureIgnoreCase) \u0026\u0026\n contact.LastName.Contains(FilterByLastName.Text, StringComparison.InvariantCultureIgnoreCase) \u0026\u0026\n contact.Company.Contains(FilterByCompany.Text, StringComparison.InvariantCultureIgnoreCase);\n}\n// NOTE: snippet truncated \u2014 refer to full sample for additional code","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A control that presents a collection of items in a vertical list.","relatedControls":["ItemsView","GridView","StandardUICommand","FlipView","SemanticZoom"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"ListView - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.listview"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/listview-and-gridview"},{"title":"Drag and Drop - Full Sample","uri":"https://github.com/microsoft/Windows-universal-samples/tree/master/Samples/XamlDragAndDrop"},{"title":"CollectionViewSource - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Data.CollectionViewSource"},{"title":"Filtering collections and lists through user input","uri":"https://learn.microsoft.com/windows/apps/design/controls/listview-filtering"},{"title":"Inverted Lists","uri":"https://learn.microsoft.com/windows/apps/design/controls/inverted-lists"},{"title":"Inverted Lists - Full Sample","uri":"https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/XamlBottomUpList"}]},{"id":"listview-6","controlId":"listview","controlName":"ListView","headerText":"ListView for Messaging or Data Logging","xaml":"\u003CListView x:Name=\u0022InvertedListView\u0022\n ItemTemplate=\u0022{StaticResource MessageViewTemplate}\u0022\u003E\n \n \u003C!-- The ItemsStackPanel must be edited to update the following two properties --\u003E\n \u003C!-- These properties allow the list to grow from the bottom --\u003E\n \u003CListView.ItemsPanel\u003E\n \u003CItemsPanelTemplate\u003E\n \u003CItemsStackPanel ItemsUpdatingScrollMode=\u0022KeepLastItemInView\u0022 \n VerticalAlignment=\u0022Bottom\u0022/\u003E\n \u003C/ItemsPanelTemplate\u003E\n \u003C/ListView.ItemsPanel\u003E\n\n \u003C!-- This setter property is created so ListViewItems correctly align to the left or right. --\u003E\n \u003CListView.ItemContainerStyle\u003E\n \u003CStyle TargetType=\u0022ListViewItem\u0022\u003E\n \u003CSetter Property=\u0022HorizontalContentAlignment\u0022 Value=\u0022Stretch\u0022/\u003E\n \u003C/Style\u003E\n \u003C/ListView.ItemContainerStyle\u003E\n\u003C/ListView\u003E\n\n\u003C!-- Data template used: --\u003E\n\u003C!-- The data template is bound to a custom DataType called Message. --\u003E\n\u003C!-- Each Message object has a color and alignment assigned to it based on whether it was \nsent or received, and those values are bound in the DataTemplate.--\u003E\n\u003CDataTemplate x:Key=\u0022MessageViewTemplate\u0022 x:DataType=\u0022local:Message\u0022\u003E\n \u003CGrid Height=\u0022Auto\u0022 Margin=\u00224\u0022 HorizontalAlignment=\u0022{x:Bind MsgAlignment}\u0022\u003E\n \u003CStackPanel MinHeight=\u002275\u0022 Width=\u0022350\u0022 Padding=\u002210, 0, 0, 10\u0022 Background=\u0022{ThemeResource SystemColorHighlightColor}\u0022 CornerRadius=\u0022{StaticResource ControlCornerRadius}\u0022\u003E\n \u003CTextBlock Text=\u0022{x:Bind MsgText}\u0022 Padding=\u00220, 10, 0, 0\u0022 FontSize=\u002220\u0022 Foreground=\u0022{ThemeResource SystemColorHighlightTextColor}\u0022/\u003E\n \u003CTextBlock Text=\u0022{x:Bind MsgDateTime}\u0022 Padding=\u00220, 0, 0, 10\u0022 FontSize=\u002215\u0022 Foreground=\u0022{ThemeResource SystemColorHighlightTextColor}\u0022/\u003E\n \u003C/StackPanel\u003E\n \u003C/Grid\u003E\n\u003C/DataTemplate\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A control that presents a collection of items in a vertical list.","relatedControls":["ItemsView","GridView","StandardUICommand","FlipView","SemanticZoom"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"ListView - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.listview"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/listview-and-gridview"},{"title":"Drag and Drop - Full Sample","uri":"https://github.com/microsoft/Windows-universal-samples/tree/master/Samples/XamlDragAndDrop"},{"title":"CollectionViewSource - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Data.CollectionViewSource"},{"title":"Filtering collections and lists through user input","uri":"https://learn.microsoft.com/windows/apps/design/controls/listview-filtering"},{"title":"Inverted Lists","uri":"https://learn.microsoft.com/windows/apps/design/controls/inverted-lists"},{"title":"Inverted Lists - Full Sample","uri":"https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/XamlBottomUpList"}]},{"id":"listview-7","controlId":"listview","controlName":"ListView","headerText":"ListView with Images","xaml":"\u003CListView x:Name=\u0022Control4\u0022\n BorderThickness=\u00221\u0022\n BorderBrush=\u0022{ThemeResource ControlStrongStrokeColorDefaultBrush}\u0022\u003E\n \n\u003C!-- Data Template Used: --\u003E\n\u003C!-- The data template is bound to a custom-created data type called CustomDataObject. --\u003E\n\u003C!-- The full code for the class can be found in this page\u0027s source code, but its attributes are referenced/bound below. --\u003E\n\n\u003CDataTemplate x:DataType=\u0022local:CustomDataObject\u0022\u003E\n \u003CGrid Margin=\u00220,12,0,12\u0022 AutomationProperties.Name=\u0022{x:Bind Title}\u0022\u003E\n \u003CGrid.ColumnDefinitions\u003E\n \u003CColumnDefinition Width=\u0022Auto\u0022 MinWidth=\u0022150\u0022/\u003E\n \u003CColumnDefinition Width=\u0022*\u0022 /\u003E\n \u003C/Grid.ColumnDefinitions\u003E\n \u003CImage Source=\u0022{x:Bind ImageLocation}\u0022 MaxHeight=\u0022100\u0022 Stretch=\u0022Fill\u0022/\u003E\n\n \u003CStackPanel Margin=\u002212,0,0,0\u0022 Grid.Column=\u00221\u0022 \u003E\n \u003CTextBlock Text=\u0022{x:Bind Title}\u0022 FontSize=\u002214\u0022 FontWeight=\u0022SemiBold\u0022 Style=\u0022{ThemeResource BaseTextBlockStyle}\u0022\n HorizontalAlignment=\u0022Left\u0022 Margin=\u00220,0,0,6\u0022 LineHeight=\u002220\u0022/\u003E\n \u003CTextBlock Text=\u0022{x:Bind Description}\u0022 FontFamily=\u0022Segoe UI\u0022 FontWeight=\u0022Normal\u0022 Style=\u0022{ThemeResource BodyTextBlockStyle}\u0022\n TextTrimming=\u0022CharacterEllipsis\u0022 Width=\u0022350\u0022 MaxLines=\u00221\u0022/\u003E\n \u003CStackPanel Orientation=\u0022Horizontal\u0022\u003E\n \u003CTextBlock Text=\u0022{x:Bind Views}\u0022 HorizontalAlignment=\u0022Left\u0022 Style=\u0022{ThemeResource CaptionTextBlockStyle}\u0022 Margin=\u00220,0,0,0\u0022/\u003E\n \u003CTextBlock Text=\u0022 Views \u0022 HorizontalAlignment=\u0022Left\u0022 Style=\u0022{ThemeResource CaptionTextBlockStyle}\u0022/\u003E\n \u003CTextBlock Text=\u0022 \u00B7 \u0022 Style=\u0022{ThemeResource CaptionTextBlockStyle}\u0022 \n HorizontalAlignment=\u0022Left\u0022/\u003E\n \u003CTextBlock Text=\u0022{x:Bind Likes}\u0022 HorizontalAlignment=\u0022Left\u0022 Style=\u0022{ThemeResource CaptionTextBlockStyle}\u0022 Margin=\u00225,0,0,0\u0022/\u003E\n \u003CTextBlock Text=\u0022 Likes\u0022 HorizontalAlignment=\u0022Left\u0022 Style=\u0022{ThemeResource CaptionTextBlockStyle}\u0022/\u003E\n \u003C/StackPanel\u003E\u003C/StackPanel\u003E\u003C/Grid\u003E\u003C/DataTemplate\u003E\u003C/ListView\u003E\n\u003C!-- ...truncated --\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A control that presents a collection of items in a vertical list.","relatedControls":["ItemsView","GridView","StandardUICommand","FlipView","SemanticZoom"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"ListView - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.listview"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/listview-and-gridview"},{"title":"Drag and Drop - Full Sample","uri":"https://github.com/microsoft/Windows-universal-samples/tree/master/Samples/XamlDragAndDrop"},{"title":"CollectionViewSource - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Data.CollectionViewSource"},{"title":"Filtering collections and lists through user input","uri":"https://learn.microsoft.com/windows/apps/design/controls/listview-filtering"},{"title":"Inverted Lists","uri":"https://learn.microsoft.com/windows/apps/design/controls/inverted-lists"},{"title":"Inverted Lists - Full Sample","uri":"https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/XamlBottomUpList"}]},{"id":"listview-8","controlId":"listview","controlName":"ListView","headerText":"ListView with context menus","xaml":"\u003CListView\n ItemsSource=\u0022{x:Bind contacts, Mode=OneWay}\u0022\n SelectionMode=\u0022Single\u0022\n ShowsScrollingPlaceholders=\u0022True\u0022\n BorderThickness=\u00221\u0022\n BorderBrush=\u0022{ThemeResource ControlStrongStrokeColorDefaultBrush}\u0022\n HorizontalAlignment=\u0022Left\u0022\u003E\n \u003CListView.ItemTemplate\u003E\n \u003CDataTemplate x:DataType=\u0022local:Contact\u0022\u003E\n \u003CGrid\u003E\n \u003CGrid.ContextFlyout\u003E\n \u003CMenuFlyout\u003E\n \u003CMenuFlyoutItem Text=\u0022Delete\u0022 Click=\u0022ContactDeleteMenuItem_Click\u0022/\u003E\n \u003C/MenuFlyout\u003E\n \u003C/Grid.ContextFlyout\u003E\n \n \u003CGrid.RowDefinitions\u003E\n \u003CRowDefinition Height=\u0022*\u0022/\u003E\n \u003CRowDefinition Height=\u0022*\u0022/\u003E\n \u003C/Grid.RowDefinitions\u003E\n \u003CGrid.ColumnDefinitions\u003E\n \u003CColumnDefinition Width=\u0022Auto\u0022/\u003E\n \u003CColumnDefinition Width=\u0022*\u0022/\u003E\n \u003C/Grid.ColumnDefinitions\u003E\n \u003CEllipse x:Name=\u0022Ellipse\u0022\n Grid.RowSpan=\u00222\u0022\n Width =\u002232\u0022\n Margin=\u00226\u0022\n VerticalAlignment=\u0022Center\u0022\n HorizontalAlignment=\u0022Center\u0022\n Fill=\u0022{ThemeResource ControlStrongFillColorDefaultBrush}\u0022/\u003E\n \u003CTextBlock Grid.Column=\u00221\u0022\n Text=\u0022{x:Bind Name}\u0022\n x:Phase=\u00221\u0022\n Style=\u0022{ThemeResource BaseTextBlockStyle}\u0022\n Margin=\u002212,6,0,0\u0022/\u003E\n \u003CTextBlock Grid.Column=\u00221\u0022\n Grid.Row=\u00221\u0022\n Text=\u0022{x:Bind Company}\u0022\n x:Phase=\u00222\u0022\n Style=\u0022{ThemeResource BodyTextBlockStyle}\u0022\n Margin=\u002212,0,0,6\u0022/\u003E\n \u003C/Grid\u003E\n \u003C/DataTemplate\u003E\n \u003C/ListView.ItemTemplate\u003E\n\u003C/DataTemplate\u003E\u003C/ListView\u003E","csharp":"ObservableCollection\u003CContact\u003E contacts = new ObservableCollection\u003CContact\u003E();\n\nprivate void ContactDeleteMenuItem_Click(object sender, RoutedEventArgs e)\n{\n var item = (sender as FrameworkElement).DataContext;\n var contact = item as Contact;\n contacts.Remove(contact);\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A control that presents a collection of items in a vertical list.","relatedControls":["ItemsView","GridView","StandardUICommand","FlipView","SemanticZoom"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"ListView - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.listview"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/listview-and-gridview"},{"title":"Drag and Drop - Full Sample","uri":"https://github.com/microsoft/Windows-universal-samples/tree/master/Samples/XamlDragAndDrop"},{"title":"CollectionViewSource - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Data.CollectionViewSource"},{"title":"Filtering collections and lists through user input","uri":"https://learn.microsoft.com/windows/apps/design/controls/listview-filtering"},{"title":"Inverted Lists","uri":"https://learn.microsoft.com/windows/apps/design/controls/inverted-lists"},{"title":"Inverted Lists - Full Sample","uri":"https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/XamlBottomUpList"}]},{"id":"pulltorefresh-1","controlId":"pulltorefresh","controlName":"PullToRefresh","headerText":"Basic PullToRefresh","xaml":"\u003CRefreshContainer x:Name=\u0022rc\u0022 RefreshRequested=\u0022rc_RefreshRequested\u0022\u003E\n \u003CListView x:Name=\u0022lv\u0022 Width=\u0022300\u0022 Height=\u0022300\u0022 BorderThickness=\u00221\u0022 BorderBrush=\u0022Black\u0022/\u003E\n\u003C/RefreshContainer\u003E","csharp":"ObservableCollection\u003Cstring\u003E items = new ObservableCollection\u003Cstring\u003E();\nlistview.ItemsSource = items;\n\nprivate void rc_RefreshRequested(RefreshContainer sender, RefreshRequestedEventArgs args)\n{\n //Do some work to show new Content! Once the work is done, call RefreshCompletionDeferral.Complete()\n this.RefreshCompletionDeferral = args.GetDeferral();\n this.DoWork();\n}\n\nprivate void WorkCompleted()\n{\n items.Insert(0, \u0022NewControl\u0022);\n if (this.RefreshCompletionDeferral != null)\n {\n this.RefreshCompletionDeferral.Complete();\n this.RefreshCompletionDeferral.Dispose();\n this.RefreshCompletionDeferral = null;\n }\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Provides the ability to pull on a collection of items in a list/grid to refresh the contents of the collection.","relatedControls":["ScrollView","ScrollViewer","ListView"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"RefreshContainer - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Controls.RefreshContainer"},{"title":"RefreshVisualizer - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Controls.RefreshVisualizer"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/pull-to-refresh"}]},{"id":"pulltorefresh-2","controlId":"pulltorefresh","controlName":"PullToRefresh","headerText":"Custom Icon PullToRefresh","xaml":"\u003CRefreshContainer x:Name=\u0022rc\u0022 RefreshRequested=\u0022rc_RefreshRequested\u0022\u003E\n \u003CRefreshContainer.Visualizer\u003E\n \u003CRefreshVisualizer RefreshStateChanged=\u0022rv2_RefreshStateChanged\u0022\u003E\n \u003CRefreshVisualizer.Content\u003E\n \u003CSymbolIcon Symbol=\u0022AddFriend\u0022/\u003E\n \u003C/RefreshVisualizer.Content\u003E\n \u003C/RefreshVisualizer\u003E\n \u003C/RefreshContainer.Visualizer\u003E\n \u003CListView x:Name=\u0022lv\u0022 Width=\u0022300\u0022 Height=\u0022300\u0022 BorderThickness=\u00221\u0022 BorderBrush=\u0022Black\u0022/\u003E\n\u003C/RefreshContainer\u003E","csharp":"ObservableCollection\u003Cstring\u003E items = new ObservableCollection\u003Cstring\u003E();\nlistview.ItemsSource = items;\n\nprivate void rc_RefreshRequested(RefreshContainer sender, RefreshRequestedEventArgs args)\n{\n //Do some work to show new Content! Once the work is done, call RefreshCompletionDeferral.Complete()\n this.RefreshCompletionDeferral = args.GetDeferral();\n this.DoWork();\n}\n\nprivate void WorkCompleted()\n{\n items.Insert(0, \u0022NewControl\u0022);\n if (this.RefreshCompletionDeferral != null)\n {\n this.RefreshCompletionDeferral.Complete();\n this.RefreshCompletionDeferral.Dispose();\n this.RefreshCompletionDeferral = null;\n }\n}\nprivate void rv2_RefreshStateChanged()\n{\n var visualizerContentVisual = ElementCompositionPreview.GetElementVisual(rv2.Content);\n visualizerContentVisual.StopAnimation(\u0022RotationAngle\u0022);\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Provides the ability to pull on a collection of items in a list/grid to refresh the contents of the collection.","relatedControls":["ScrollView","ScrollViewer","ListView"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"RefreshContainer - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Controls.RefreshContainer"},{"title":"RefreshVisualizer - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Controls.RefreshVisualizer"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/pull-to-refresh"}]},{"id":"treeview-1","controlId":"treeview","controlName":"TreeView","headerText":"A simple TreeView with drag and drop support","xaml":"\u003CTreeView x:Name=\u0022sampleTreeView\u0022 CanDragItems=\u0022True\u0022 AllowDrop=\u0022True\u0022/\u003E","csharp":"private void InitializeSampleTreeView(TreeView sampleTreeView)\n{\n // Create a root node with initial content and set it to be expanded.\n TreeViewNode workNode = new TreeViewNode() { Content = \u0022Work Documents\u0022 };\n workNode.IsExpanded = true;\n\n // Add child nodes with content related to the root node.\n workNode.Children.Add(new TreeViewNode() { Content = \u0022XYZ Functional Spec\u0022 });\n workNode.Children.Add(new TreeViewNode() { Content = \u0022Feature Schedule\u0022 });\n\n // Create another node with initial content and set it to be expanded.\n TreeViewNode remodelNode = new TreeViewNode() { Content = \u0022Home Remodel\u0022 };\n remodelNode.IsExpanded = true;\n\n // Add child nodes with specific content under this node.\n remodelNode.Children.Add(new TreeViewNode() { Content = \u0022Contractor Contact Info\u0022 });\n remodelNode.Children.Add(new TreeViewNode() { Content = \u0022Paint Color Scheme\u0022 });\n\n // Create a node with broader content that includes the previous node as a child.\n TreeViewNode personalNode = new TreeViewNode() { Content = \u0022Personal Documents\u0022 };\n personalNode.IsExpanded = true;\n personalNode.Children.Add(remodelNode);\n\n // Add the main nodes to the TreeView\u0027s root.\n sampleTreeView.RootNodes.Add(workNode);\n sampleTreeView.RootNodes.Add(personalNode);\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"The TreeView control is a hierarchical list pattern with expanding and collapsing nodes that contain nested items.","relatedControls":["ListView","ItemsRepeater"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"TreeView - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Controls.TreeView"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/tree-view"}]},{"id":"treeview-2","controlId":"treeview","controlName":"TreeView","headerText":"A TreeView with Multi-selection enabled","xaml":"\u003CTreeView x:Name=\u0022sampleTreeView\u0022 SelectionMode=\u0022Multiple\u0022 /\u003E","csharp":"private void InitializeSampleTreeView(TreeView sampleTreeView)\n{\n // Create a root node with initial content and set it to be expanded.\n TreeViewNode workNode = new TreeViewNode() { Content = \u0022Work Documents\u0022 };\n workNode.IsExpanded = true;\n\n // Add child nodes with content related to the root node.\n workNode.Children.Add(new TreeViewNode() { Content = \u0022XYZ Functional Spec\u0022 });\n workNode.Children.Add(new TreeViewNode() { Content = \u0022Feature Schedule\u0022 });\n\n // Create another node with initial content and set it to be expanded.\n TreeViewNode remodelNode = new TreeViewNode() { Content = \u0022Home Remodel\u0022 };\n remodelNode.IsExpanded = true;\n\n // Add child nodes with specific content under this node.\n remodelNode.Children.Add(new TreeViewNode() { Content = \u0022Contractor Contact Info\u0022 });\n remodelNode.Children.Add(new TreeViewNode() { Content = \u0022Paint Color Scheme\u0022 });\n\n // Create a node with broader content that includes the previous node as a child.\n TreeViewNode personalNode = new TreeViewNode() { Content = \u0022Personal Documents\u0022 };\n personalNode.IsExpanded = true;\n personalNode.Children.Add(remodelNode);\n\n // Add the main nodes to the TreeView\u0027s root.\n sampleTreeView.RootNodes.Add(workNode);\n sampleTreeView.RootNodes.Add(personalNode);\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"The TreeView control is a hierarchical list pattern with expanding and collapsing nodes that contain nested items.","relatedControls":["ListView","ItemsRepeater"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"TreeView - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Controls.TreeView"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/tree-view"}]},{"id":"treeview-3","controlId":"treeview","controlName":"TreeView","headerText":"A TreeView with DataBinding Using ItemSource","xaml":"\u003CTreeView ItemsSource=\u0022{x:Bind DataSource}\u0022\u003E\n \u003CTreeView.ItemTemplate\u003E\n \u003CDataTemplate x:DataType=\u0022local:ExplorerItem\u0022\u003E\n \u003CTreeViewItem ItemsSource=\u0022{x:Bind Children}\u0022 Content=\u0022{x:Bind Name}\u0022/\u003E\n \u003C/DataTemplate\u003E\n \u003C/TreeView.ItemTemplate\u003E\n\u003C/TreeView\u003E","csharp":"using System.Collections.ObjectModel;\nusing Microsoft.UI.Xaml;\nusing Microsoft.UI.Xaml.Controls;\n\nnamespace YourNamespace\n{\n public sealed partial class YourPage : Page\n {\n // DataSource is the data collection that will be bound to the TreeView\u0027s ItemsSource.\n public ObservableCollection\u003CExplorerItem\u003E DataSource { get; set; }\n\n public YourPage()\n {\n this.InitializeComponent();\n\n // Initialize the data source with sample data and set it as the context for data binding.\n DataSource = GetData();\n this.DataContext = this; // Bind the DataContext of the page to itself for XAML bindings.\n }\n\n // Method to provide sample data for the TreeView.\n private ObservableCollection\u003CExplorerItem\u003E GetData()\n {\n return new ObservableCollection\u003CExplorerItem\u003E\n {\n // Root folder with child files.\n new ExplorerItem\n {\n Name = \u0022Documents\u0022,\n Type = ExplorerItem.ExplorerItemType.Folder,\n Children =\n {\n new ExplorerItem\n {\n Name = \u0022ProjectProposal\u0022,\n Type = ExplorerItem.ExplorerItemType.File,\n },\n new ExplorerItem\n {\n Name = \u0022BudgetReport\u0022,\n Type = ExplorerItem.ExplorerItemType.File,\n },\n },\n },\n // Another root folder with one child file.\n new ExplorerItem\n {\n Name = \u0022Projects\u0022,\n Type = ExplorerItem.ExplorerItemType.Folder,\n Children =\n {\n new ExplorerItem\n {\n Name = \u0022Project Plan\u0022,\n Type = ExplorerItem.ExplorerItemType.File,\n },\n },\n },\n };\n }\n }\n\n // Class to represent items in the TreeView.\n public class ExplorerItem\n {\n // Enum to define the type of the item: Folder or File.\n public enum ExplorerItemType\n {\n Folder,\n File,\n }\n\n // Name of the item (displayed in the TreeView).\n public string Name { get; set; } = string.Empty;\n\n // Type of the item (Folder or File).\n public ExplorerItemType Type { get; set; }\n\n // Collection of child items. Used for nested nodes in the TreeView.\n public ObservableCollection\u003CExplorerItem\u003E Children { get; set; } = new ObservableCollection\u003CExplorerItem\u003E();\n }\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"The TreeView control is a hierarchical list pattern with expanding and collapsing nodes that contain nested items.","relatedControls":["ListView","ItemsRepeater"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"TreeView - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Controls.TreeView"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/tree-view"}]},{"id":"treeview-4","controlId":"treeview","controlName":"TreeView","headerText":"A TreeView with ItemTemplateSelector","xaml":"\u003CPage ...\n xmlns:local=\u0022using:YourNamespace\u0022 \u003E\n\n \u003CPage.Resources\u003E\n \u003C!-- DataTemplate for folders --\u003E\n \u003CDataTemplate x:Key=\u0022FolderTemplate\u0022 x:DataType=\u0022local:ExplorerItem\u0022\u003E \n \u003CTreeViewItem AutomationProperties.Name=\u0022{x:Bind Name}\u0022\n ItemsSource=\u0022{x:Bind Children}\u0022 IsExpanded=\u0022True\u0022\u003E\n \u003CStackPanel Orientation=\u0022Horizontal\u0022\u003E\n \u003CImage Width=\u002220\u0022 Source=\u0022../Assets/SampleMedia/folder.png\u0022/\u003E\n \u003CTextBlock Margin=\u00220,0,10,0\u0022/\u003E\n \u003CTextBlock Text=\u0022{x:Bind Name}\u0022 /\u003E\n \u003C/StackPanel\u003E\n \u003C/TreeViewItem\u003E\n \u003C/DataTemplate\u003E\n\n \u003C!-- DataTemplate for files --\u003E\n \u003CDataTemplate x:Key=\u0022FileTemplate\u0022 x:DataType=\u0022local:ExplorerItem\u0022\u003E \n \u003CTreeViewItem AutomationProperties.Name=\u0022{x:Bind Name}\u0022\u003E\n \u003CStackPanel Orientation=\u0022Horizontal\u0022\u003E\n \u003CFontIcon Glyph=\u0022\u0026#xE8A5;\u0022 /\u003E\n \u003CTextBlock Margin=\u00220,0,10,0\u0022/\u003E\n \u003CTextBlock Text=\u0022{x:Bind Name}\u0022/\u003E\n \u003C/StackPanel\u003E\n \u003C/TreeViewItem\u003E\n \u003C/DataTemplate\u003E\n\n \u003C!-- Template selector for ExplorerItem types --\u003E\n \u003Clocal:ExplorerItemTemplateSelector x:Key=\u0022ExplorerItemTemplateSelector\u0022\n FolderTemplate=\u0022{StaticResource FolderTemplate}\u0022\n FileTemplate=\u0022{StaticResource FileTemplate}\u0022 /\u003E\n \u003C/Page.Resources\u003E\n\n \u003C!-- TreeView bound to DataSource, using the ItemTemplateSelector --\u003E\n \u003CTreeView ItemsSource=\u0022{x:Bind DataSource}\u0022\n ItemTemplateSelector=\u0022{StaticResource ExplorerItemTemplateSelector}\u0022 /\u003E\n\u003C/Page\u003E","csharp":"using System.Collections.ObjectModel;\nusing Microsoft.UI.Xaml;\nusing Microsoft.UI.Xaml.Controls;\n\nnamespace YourNamespace\n{\n public sealed partial class YourPage : Page\n {\n public ObservableCollection\u003CExplorerItem\u003E DataSource { get; set; }\n\n public YourPage()\n {\n this.InitializeComponent();\n DataSource = GetData();\n this.DataContext = this;\n }\n\n private ObservableCollection\u003CExplorerItem\u003E GetData()\n {\n return new ObservableCollection\u003CExplorerItem\u003E\n {\n new ExplorerItem\n {\n Name = \u0022Documents\u0022,\n Type = ExplorerItem.ExplorerItemType.Folder,\n Children =\n {\n new ExplorerItem\n {\n Name = \u0022ProjectProposal\u0022,\n Type = ExplorerItem.ExplorerItemType.File,\n },\n new ExplorerItem\n {\n Name = \u0022BudgetReport\u0022,\n Type = ExplorerItem.ExplorerItemType.File,\n },\n },\n },\n new ExplorerItem\n {\n Name = \u0022Projects\u0022,\n Type = ExplorerItem.ExplorerItemType.Folder,\n Children =\n {\n new ExplorerItem\n {\n Name = \u0022Project Plan\u0022,\n Type = ExplorerItem.ExplorerItemType.File,\n },\n },\n },\n };\n }\n }\n\n public class ExplorerItem\n {\n public enum ExplorerItemType\n {\n Folder,\n File,\n }\n\n public string Name { get; set; } = string.Empty;\n public ExplorerItemType Type { get; set; }\n public ObservableCollection\u003CExplorerItem\u003E Children { get; set; } = new ObservableCollection\u003CExplorerItem\u003E();\n }\n\n class ExplorerItemTemplateSelector : DataTemplateSelector\n {\n // Template to use for folder items in the TreeView.\n public DataTemplate? FolderTemplate { get; set; }\n\n // Template to use for file items in the TreeView.\n public DataTemplate? FileTemplate { get; set; }\n\n // Determines which template to use for each item in the TreeView based on its type.\n protected override DataTemplate? SelectTemplateCore(object item)\n {\n // Cast the item to the ExplorerItem type.\n var explorerItem = (ExplorerItem)item;\n\n // Return the appropriate template: FolderTemplate for folders, FileTemplate for files.\n return explorerItem.Type == ExplorerItem.ExplorerItemType.Folder\n ? FolderTemplate\n : FileTemplate;\n }\n }\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"The TreeView control is a hierarchical list pattern with expanding and collapsing nodes that contain nested items.","relatedControls":["ListView","ItemsRepeater"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"TreeView - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Controls.TreeView"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/tree-view"}]},{"id":"calendardatepicker-1","controlId":"calendardatepicker","controlName":"CalendarDatePicker","headerText":"CalendarDatePicker with a header and placeholder text.","xaml":"\u003CCalendarDatePicker PlaceholderText=\u0022Pick a date\u0022 Header=\u0022Calendar\u0022 /\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A control that lets users pick a date value using a calendar.","relatedControls":["DatePicker","CalendarView"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"CalendarDatePicker - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.calendardatepicker"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/calendar-date-picker"}]},{"id":"calendarview-1","controlId":"calendarview","controlName":"CalendarView","headerText":"A basic calendar view.","xaml":"\u003CCalendarView \n SelectionMode=\u0022...\u0022 \n IsGroupLabelVisible=\u0022...\u0022\n IsOutOfScopeEnabled=\u0022...\u0022\n Language=\u0022...\u0022\n CalendarIdentifier=\u0022...\u0022 /\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A control that presents a calendar for a user to choose a date from.","relatedControls":["CalendarDatePicker","DatePicker","TimePicker"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"CalendarView - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.calendarview"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/calendar-view"}]},{"id":"datepicker-1","controlId":"datepicker","controlName":"DatePicker","headerText":"A simple DatePicker with a header.","xaml":"\u003CDatePicker Header=\u0022Pick a date\u0022 /\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A control that lets a user pick a date value.","relatedControls":["CalendarDatePicker","CalendarView","TimePicker"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"DatePicker - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.datepicker"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/date-picker"}]},{"id":"datepicker-2","controlId":"datepicker","controlName":"DatePicker","headerText":"A DatePicker with day formatted and year hidden.","xaml":"\u003CDatePicker DayFormat=\u0022{}{day.integer} ({dayofweek.abbreviated})\u0022 YearVisible=\u0022False\u0022 /\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A control that lets a user pick a date value.","relatedControls":["CalendarDatePicker","CalendarView","TimePicker"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"DatePicker - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.datepicker"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/date-picker"}]},{"id":"timepicker-1","controlId":"timepicker","controlName":"TimePicker","headerText":"A simple TimePicker.","xaml":"\u003CTimePicker/\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A configurable control that lets a user pick a time value.","relatedControls":["DatePicker","CalendarView"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"TimePicker - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.timepicker"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/time-picker"}]},{"id":"timepicker-2","controlId":"timepicker","controlName":"TimePicker","headerText":"A TimePicker with a header and minute increments specified.","xaml":"\u003CTimePicker Header=\u0022Arrival time\u0022 MinuteIncrement=\u002215\u0022 /\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A configurable control that lets a user pick a time value.","relatedControls":["DatePicker","CalendarView"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"TimePicker - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.timepicker"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/time-picker"}]},{"id":"timepicker-3","controlId":"timepicker","controlName":"TimePicker","headerText":"A TimePicker using a 24-hour clock, initialized to current time.","xaml":"\u003Cxmlns:sys=\u0022using:System\u0022\u003E\n \n \u003CTimePicker ClockIdentifier=\u002224HourClock\u0022 Header=\u002224 hour clock\u0022 SelectedTime=\u0022{x:Bind sys:DateTime.Now.TimeOfDay}\u0022 /\u003E\u003C/xmlns:sys\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A configurable control that lets a user pick a time value.","relatedControls":["DatePicker","CalendarView"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"TimePicker - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.timepicker"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/time-picker"}]},{"id":"button-1","controlId":"button","controlName":"Button","headerText":"A simple Button with text content.","xaml":"\u003CButton Content=\u0022Standard XAML button\u0022 Click=\u0022Button_Click\u0022 .../\u003E","csharp":"private void Button_Click(object sender, RoutedEventArgs e)\n{\n // Handle button click\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A control that responds to user input and raises a Click event.","relatedControls":["ToggleButton","RepeatButton","HyperlinkButton","AppBarButton"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"Button - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.button"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/buttons"}]},{"id":"button-2","controlId":"button","controlName":"Button","headerText":"A Button with graphical content.","xaml":"\u003CButton Content=\u0022Button\u0022 Click=\u0022Button_Click\u0022 AutomationProperties.Name=\u0022Pie\u0022\u003E\n \u003CImage Source=\u0022/Assets/SampleMedia/Slices.png\u0022 AutomationProperties.Name=\u0022Slice\u0022/\u003E\n\u003C/Button\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A control that responds to user input and raises a Click event.","relatedControls":["ToggleButton","RepeatButton","HyperlinkButton","AppBarButton"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"Button - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.button"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/buttons"}]},{"id":"button-3","controlId":"button","controlName":"Button","headerText":"Built-in styles applied to Button.","xaml":"\u003CButton Style=\u0022{StaticResource AccentButtonStyle}\u0022 Content=\u0022Accent style button\u0022/\u003E\n\u003CButton Style=\u0022{StaticResource SubtleButtonStyle}\u0022 Content=\u0022Subtle style button\u0022/\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A control that responds to user input and raises a Click event.","relatedControls":["ToggleButton","RepeatButton","HyperlinkButton","AppBarButton"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"Button - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.button"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/buttons"}]},{"id":"button-4","controlId":"button","controlName":"Button","headerText":"Wrapping Buttons with large content","xaml":"\u003CStackPanel\u003E\n \u003CTextBlock Text=\u0022The following buttons\u0027 content may get clipped if we don\u0027t pay careful attention to their layout containers.\u0022 Margin=\u00220,0,0,8\u0022 TextWrapping=\u0022Wrap\u0022/\u003E\n \u003CTextBlock Text=\u0022One option to mitigate clipped content is to place Buttons underneath each other, allowing for more space to grow horizontally:\u0022 Margin=\u00220,0,0,8\u0022 TextWrapping=\u0022Wrap\u0022/\u003E\n \u003CButton HorizontalAlignment=\u0022Stretch\u0022 Margin=\u00220,0,0,5\u0022\u003EThis is some text that is too long and will get cut off\u003C/Button\u003E\n \u003CButton HorizontalAlignment=\u0022Stretch\u0022\u003EThis is another text that would result in being cut off\u003C/Button\u003E\n\n \u003CTextBlock Text=\u0022Another option is to explicitly wrap the Button\u0027s content\u0022 Margin=\u00220,8,0,8\u0022/\u003E\n \u003CStackPanel Orientation=\u0022Horizontal\u0022 HorizontalAlignment=\u0022Center\u0022\u003E\n \u003CButton MaxWidth=\u0022240\u0022 Margin=\u00220,0,8,0\u0022\u003E\n \u003CTextBlock Text=\u0022This is some text that is too long and will get cut off\u0022 TextWrapping=\u0022WrapWholeWords\u0022/\u003E\n \u003C/Button\u003E\n \u003CButton MaxWidth=\u0022240\u0022\u003E\n \u003CTextBlock Text=\u0022This is another text that would result in being cut off\u0022 TextWrapping=\u0022WrapWholeWords\u0022/\u003E\n \u003C/Button\u003E\n \u003C/StackPanel\u003E\n\u003C/StackPanel\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A control that responds to user input and raises a Click event.","relatedControls":["ToggleButton","RepeatButton","HyperlinkButton","AppBarButton"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"Button - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.button"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/buttons"}]},{"id":"dropdownbutton-1","controlId":"dropdownbutton","controlName":"DropDownButton","headerText":"Simple DropDownButton","xaml":"\u003CDropDownButton Content=\u0022Email\u0022\u003E\n \u003CDropDownButton.Flyout\u003E\n \u003CMenuFlyout Placement=\u0022Bottom\u0022\u003E\n \u003CMenuFlyoutItem Text=\u0022Send\u0022/\u003E\n \u003CMenuFlyoutItem Text=\u0022Reply\u0022/\u003E\n \u003CMenuFlyoutItem Text=\u0022Reply All\u0022/\u003E\n \u003C/MenuFlyout\u003E\n \u003C/DropDownButton.Flyout\u003E\n\u003C/DropDownButton\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A button that displays a flyout of choices when clicked.","relatedControls":["SplitButton","ToggleSplitButton","ToggleButton","RepeatButton","HyperlinkButton","AppBarButton","CommandBar"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"DropDownButton - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.dropdownbutton"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/buttons"}]},{"id":"dropdownbutton-2","controlId":"dropdownbutton","controlName":"DropDownButton","headerText":"DropDownButton with Icons","xaml":"\u003CDropDownButton AutomationProperties.Name=\u0022Email\u0022\u003E\n \u003CDropDownButton.Content\u003E\n \u003CFontIcon Glyph=\u0022\u0026#xE715;\u0022/\u003E\n \u003C/DropDownButton.Content\u003E\n \u003CDropDownButton.Flyout\u003E\n \u003CMenuFlyout Placement=\u0022Bottom\u0022\u003E\n \u003CMenuFlyoutItem Text=\u0022Send\u0022\u003E\n \u003CMenuFlyoutItem.Icon\u003E\n \u003CFontIcon Glyph=\u0022\u0026#xE725;\u0022/\u003E\n \u003C/MenuFlyoutItem.Icon\u003E\n \u003C/MenuFlyoutItem\u003E\n \u003CMenuFlyoutItem Text=\u0022Reply\u0022\u003E\n \u003CMenuFlyoutItem.Icon\u003E\n \u003CFontIcon Glyph=\u0022\u0026#xE8CA;\u0022/\u003E\n \u003C/MenuFlyoutItem.Icon\u003E\n \u003C/MenuFlyoutItem\u003E\n \u003CMenuFlyoutItem Text=\u0022Reply All\u0022\u003E\n \u003CMenuFlyoutItem.Icon\u003E\n \u003CFontIcon Glyph=\u0022\u0026#xE8C2;\u0022/\u003E\n \u003C/MenuFlyoutItem.Icon\u003E\n \u003C/MenuFlyoutItem\u003E\n \u003C/MenuFlyout\u003E\n \u003C/DropDownButton.Flyout\u003E\n\u003C/DropDownButton\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A button that displays a flyout of choices when clicked.","relatedControls":["SplitButton","ToggleSplitButton","ToggleButton","RepeatButton","HyperlinkButton","AppBarButton","CommandBar"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"DropDownButton - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.dropdownbutton"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/buttons"}]},{"id":"hyperlinkbutton-1","controlId":"hyperlinkbutton","controlName":"HyperlinkButton","headerText":"A hyperlink button that navigates to a URI.","xaml":"\u003CHyperlinkButton Content=\u0022Microsoft home page\u0022 NavigateUri=\u0022https://www.microsoft.com\u0022 .../\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A button that appears as hyperlink text, and can navigate to a URI or handle a Click event.","relatedControls":["Button","ToggleButton","RepeatButton","AppBarButton"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"HyperlinkButton - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.hyperlinkbutton"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/hyperlinks"}]},{"id":"hyperlinkbutton-2","controlId":"hyperlinkbutton","controlName":"HyperlinkButton","headerText":"A hyperlink button that handles a Click event.","xaml":"\u003CHyperlinkButton Content=\u0022ToggleButton\u0022 Click=\u0022HyperlinkButton_Click\u0022/\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A button that appears as hyperlink text, and can navigate to a URI or handle a Click event.","relatedControls":["Button","ToggleButton","RepeatButton","AppBarButton"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"HyperlinkButton - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.hyperlinkbutton"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/hyperlinks"}]},{"id":"repeatbutton-1","controlId":"repeatbutton","controlName":"RepeatButton","headerText":"A simple RepeatButton with text content.","xaml":"\u003CRepeatButton Content=\u0022Click and hold\u0022 Click=\u0022RepeatButton_Click\u0022 .../\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A button that raises its Click event repeatedly from the time it\u0027s pressed until it\u0027s released.","relatedControls":["Button","ToggleButton","HyperlinkButton","AppBarButton"],"apiNamespace":"Microsoft.UI.Xaml.Controls.Primitives","docs":[{"title":"RepeatButton - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.primitives.repeatbutton"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/buttons"}]},{"id":"togglebutton-1","controlId":"togglebutton","controlName":"ToggleButton","headerText":"A simple ToggleButton with text content.","xaml":"\u003CToggleButton Content=\u0022ToggleButton\u0022 Click=\u0022Button_Click\u0022 .../\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A button that can be switched between two states like a CheckBox.","relatedControls":["Button","AppBarToggleButton","ToggleSwitch","CheckBox","CommandBarFlyout","CommandBar"],"apiNamespace":"Microsoft.UI.Xaml.Controls.Primitives","docs":[{"title":"ToggleButton - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.primitives.togglebutton"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/buttons#create-a-toggle-split-button"}]},{"id":"splitbutton-1","controlId":"splitbutton","controlName":"SplitButton","headerText":"A SplitButton controlling text color in a RichEditBox","xaml":"\u003CSplitButton x:Name=\u0022myColorButton\u0022 Click=\u0022myColorButton_Click\u0022\u003E\n \u003CBorder x:Name=\u0022CurrentColor\u0022 Width=\u002232\u0022 Height=\u002232\u0022 Background=\u0022Green\u0022 CornerRadius=\u00224,0,0,4\u0022/\u003E\n \u003CSplitButton.Flyout\u003E\n \u003CFlyout Placement=\u0022Bottom\u0022\u003E\n \u003C!-- flyout content --\u003E\n \u003C/Flyout\u003E\n \u003C/SplitButton.Flyout\u003E\n\u003C/SplitButton\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A two-part button that displays a flyout when its secondary part is clicked.","relatedControls":["Button","DropDownButton","ToggleSplitButton","AppBarButton","CommandBar"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"SplitButton - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.splitbutton"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/buttons#create-a-split-button"}]},{"id":"splitbutton-2","controlId":"splitbutton","controlName":"SplitButton","headerText":"A SplitButton with text","xaml":"\u003CSplitButton x:Name=\u0022myColorButton\u0022\u003E\n Choose color\n \u003CSplitButton.Flyout\u003E\n \u003CFlyout Placement=\u0022Bottom\u0022\u003E\n \u003C!-- flyout content --\u003E\n \u003C/Flyout\u003E\n \u003C/SplitButton.Flyout\u003E\n\u003C/SplitButton\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A two-part button that displays a flyout when its secondary part is clicked.","relatedControls":["Button","DropDownButton","ToggleSplitButton","AppBarButton","CommandBar"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"SplitButton - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.splitbutton"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/buttons#create-a-split-button"}]},{"id":"togglesplitbutton-1","controlId":"togglesplitbutton","controlName":"ToggleSplitButton","headerText":"Using ToggleSplitButton to control bulleted list functionality in RichEditBox","xaml":"\u003CToggleSplitButton x:Name=\u0022myListButton\u0022 VerticalAlignment=\u0022Top\u0022 Click=\u0022myListButton_Click\u0022\u003E\n \u003CSymbolIcon x:Name=\u0022mySymbolIcon\u0022 Symbol=\u0022List\u0022/\u003E\n \u003CToggleSplitButton.Flyout\u003E\n \u003CFlyout Placement=\u0022Bottom\u0022\u003E\n \u003C!-- flyout content --\u003E\n \u003C/Flyout\u003E\n \u003C/ToggleSplitButton.Flyout\u003E\n\u003C/ToggleSplitButton\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A version of the SplitButton where the activation target toggles on/off.","relatedControls":["SplitButton","DropDownButton","Button","ToggleButton","ToggleSwitch","CheckBox"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"ToggleSplitButton - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.togglesplitbutton"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/buttons"}]},{"id":"checkbox-1","controlId":"checkbox","controlName":"CheckBox","headerText":"A 2-state CheckBox.","xaml":"\u003CCheckBox Content=\u0022Two-state CheckBox\u0022\n Checked=\u0022TwoState_Checked\u0022\n Unchecked=\u0022TwoState_Unchecked\u0022 /\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A control that a user can select or clear.","relatedControls":["RadioButton","ToggleSwitch","ToggleButton"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"CheckBox - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.checkbox"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/checkbox"}]},{"id":"checkbox-2","controlId":"checkbox","controlName":"CheckBox","headerText":"A 3-state CheckBox.","xaml":"\u003CCheckBox Content=\u0022Three-state CheckBox\u0022\n IsThreeState=\u0022True\u0022\n Checked=\u0022ThreeState_Checked\u0022\n Unchecked=\u0022ThreeState_Unchecked\u0022\n Indeterminate=\u0022ThreeState_Indeterminate\u0022 /\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A control that a user can select or clear.","relatedControls":["RadioButton","ToggleSwitch","ToggleButton"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"CheckBox - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.checkbox"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/checkbox"}]},{"id":"checkbox-3","controlId":"checkbox","controlName":"CheckBox","headerText":"Using a 3-state CheckBox.","xaml":"\u003CStackPanel\u003E\n \u003CCheckBox x:Name=\u0022OptionsAllCheckBox\u0022 Content=\u0022Select all\u0022 IsThreeState=\u0022True\u0022\n Checked=\u0022SelectAll_Checked\u0022 Unchecked=\u0022SelectAll_Unchecked\u0022\n Indeterminate=\u0022SelectAll_Indeterminate\u0022 /\u003E\n \u003CCheckBox x:Name=\u0022Option1CheckBox\u0022 Content=\u0022Option 1\u0022 Margin=\u002224,0,0,0\u0022 Checked=\u0022Option_Checked\u0022 Unchecked=\u0022Option_Unchecked\u0022 /\u003E\n \u003CCheckBox x:Name=\u0022Option2CheckBox\u0022 Content=\u0022Option 2\u0022 Margin=\u002224,0,0,0\u0022 Checked=\u0022Option_Checked\u0022 Unchecked=\u0022Option_Unchecked\u0022 IsChecked=\u0022True\u0022 /\u003E\n \u003CCheckBox x:Name=\u0022Option3CheckBox\u0022 Content=\u0022Option 3\u0022 Margin=\u002224,0,0,0\u0022 Checked=\u0022Option_Checked\u0022 Unchecked=\u0022Option_Unchecked\u0022 /\u003E\n\u003C/StackPanel\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A control that a user can select or clear.","relatedControls":["RadioButton","ToggleSwitch","ToggleButton"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"CheckBox - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.checkbox"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/checkbox"}]},{"id":"colorpicker-1","controlId":"colorpicker","controlName":"ColorPicker","headerText":"ColorPicker Properties.","xaml":"\u003CColorPicker\n ColorSpectrumShape=\u0022...\u0022\n IsMoreButtonVisible=\u0022...\u0022\n IsColorSliderVisible=\u0022...\u0022\n IsColorChannelTextInputVisible=\u0022...\u0022\n IsHexInputVisible=\u0022...\u0022\n IsAlphaEnabled=\u0022...\u0022\n IsAlphaSliderVisible=\u0022...\u0022\n IsAlphaTextInputVisible=\u0022...\u0022 /\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A control that displays a selectable color spectrum.","relatedControls":["ComboBox"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"ColorPicker - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Controls.ColorPicker"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/color-picker"}]},{"id":"combobox-1","controlId":"combobox","controlName":"ComboBox","headerText":"A ComboBox with items defined inline and its width set.","xaml":"\u003CComboBox SelectionChanged=\u0022ColorComboBox_SelectionChanged\u0022 Header=\u0022Colors\u0022 PlaceholderText=\u0022Pick a color\u0022 Width=\u0022200\u0022\u003E\n \u003Cx:String\u003EBlue\u003C/x:String\u003E\n \u003Cx:String\u003EGreen\u003C/x:String\u003E\n \u003Cx:String\u003ERed\u003C/x:String\u003E\n \u003Cx:String\u003EYellow\u003C/x:String\u003E\n\u003C/ComboBox\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A drop-down list of items a user can select from.","relatedControls":["RadioButton","CheckBox","ListView","AutoSuggestBox","RatingControl"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"ComboBox - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.combobox"},{"title":"ComboBoxItem - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.comboboxitem"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/combo-box"}]},{"id":"combobox-2","controlId":"combobox","controlName":"ComboBox","headerText":"A ComboBox with its ItemsSource set.","xaml":"\u003CComboBox ItemsSource=\u0022{x:Bind Fonts}\u0022 DisplayMemberPath=\u0022Item1\u0022 SelectedValuePath=\u0022Item2\u0022\n Header=\u0022Font\u0022 Width=\u0022200\u0022 Loaded=\u0022Combo2_Loaded\u0022/\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A drop-down list of items a user can select from.","relatedControls":["RadioButton","CheckBox","ListView","AutoSuggestBox","RatingControl"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"ComboBox - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.combobox"},{"title":"ComboBoxItem - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.comboboxitem"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/combo-box"}]},{"id":"combobox-3","controlId":"combobox","controlName":"ComboBox","headerText":"An editable ComboBox.","xaml":"\u003CComboBox IsEditable=\u0022True\u0022 ItemsSource=\u0022{x:Bind FontSizes}\u0022 Width=\u0022200\u0022 TextSubmitted=\u0022Combo3_TextSubmitted\u0022/\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A drop-down list of items a user can select from.","relatedControls":["RadioButton","CheckBox","ListView","AutoSuggestBox","RatingControl"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"ComboBox - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.combobox"},{"title":"ComboBoxItem - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.comboboxitem"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/combo-box"}]},{"id":"radiobutton-1","controlId":"radiobutton","controlName":"RadioButton","headerText":"A group of RadioButton controls in a RadioButtons group.","xaml":"\u003CRadioButtons Header=\u0022Options:\u0022\u003E\n \u003CRadioButton Content=\u0022Option 1\u0022 Checked=\u0022RadioButton_Checked\u0022/\u003E\n \u003CRadioButton Content=\u0022Option 2\u0022 Checked=\u0022RadioButton_Checked\u0022/\u003E\n \u003CRadioButton Content=\u0022Option 3\u0022 Checked=\u0022RadioButton_Checked\u0022/\u003E\n\u003C/RadioButtons\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A control that allows a user to select a single option from a group of options.","relatedControls":["CheckBox","ToggleSwitch","ToggleButton"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"RadioButton - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.radiobutton"},{"title":"RadioButtons - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.radiobuttons"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/radio-button"}]},{"id":"radiobutton-2","controlId":"radiobutton","controlName":"RadioButton","headerText":"Two RadioButtons controls with strings as options.","xaml":"\u003CRadioButtons x:Name=\u0022BackgroundRadioButtons\u0022 SelectedIndex=\u0022...\u0022 MaxColumns=\u00223\u0022 Header=\u0022Background\u0022 SelectionChanged=\u0022BackgroundColor_SelectionChanged\u0022\u003E\n \u003Cx:String\u003EGreen\u003C/x:String\u003E\n \u003Cx:String\u003EYellow\u003C/x:String\u003E\n \u003Cx:String\u003EWhite\u003C/x:String\u003E\n\u003C/RadioButtons\u003E\n\u003CRadioButtons x:Name=\u0022BorderRadioButtons\u0022 SelectedIndex=\u0022...\u0022 MaxColumns=\u00223\u0022 Header=\u0022Border\u0022 SelectionChanged=\u0022BorderBrush_SelectionChanged\u0022\u003E\n \u003Cx:String\u003EGreen\u003C/x:String\u003E\n \u003Cx:String\u003EYellow\u003C/x:String\u003E\n \u003Cx:String\u003EWhite\u003C/x:String\u003E\n\u003C/RadioButtons\u003E\n\n\u003CBorder x:Name=\u0022ControlOutput\u0022 BorderThickness=\u002210\u0022 BorderBrush=\u0022#FFFFD700\u0022 Background=\u0022#FFFFFFFF\u0022\n Height=\u002250\u0022 Margin=\u00220,10,0,10\u0022 /\u003E","csharp":"private void BackgroundColor_SelectionChanged(object sender, SelectionChangedEventArgs e)\n{\n if (ControlOutput != null \u0026\u0026 sender is RadioButtons rb)\n {\n string colorName = rb.SelectedItem as string;\n switch (colorName)\n {\n case \u0022Yellow\u0022:\n ControlOutput.Background = new SolidColorBrush(Colors.Yellow);\n break;\n case \u0022Green\u0022:\n ControlOutput.Background = new SolidColorBrush(Colors.Green);\n break;\n case \u0022White\u0022:\n ControlOutput.Background = new SolidColorBrush(Colors.White);\n break;\n }\n }\n}\n\nprivate void BorderBrush_SelectionChanged(object sender, SelectionChangedEventArgs e)\n{\n if (ControlOutput != null \u0026\u0026 sender is RadioButtons rb)\n {\n string colorName = rb.SelectedItem as string;\n switch (colorName)\n {\n case \u0022Yellow\u0022:\n ControlOutput.BorderBrush = new SolidColorBrush(Colors.Gold);\n break;\n case \u0022Green\u0022:\n ControlOutput.BorderBrush = new SolidColorBrush(Colors.DarkGreen);\n break;\n case \u0022White\u0022:\n ControlOutput.BorderBrush = new SolidColorBrush(Colors.White);\n break;\n }\n }\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A control that allows a user to select a single option from a group of options.","relatedControls":["CheckBox","ToggleSwitch","ToggleButton"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"RadioButton - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.radiobutton"},{"title":"RadioButtons - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.radiobuttons"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/radio-button"}]},{"id":"ratingcontrol-1","controlId":"ratingcontrol","controlName":"RatingControl","headerText":"A simple RatingControl","xaml":"\u003CRatingControl AutomationProperties.Name=\u0022Simple RatingControl\u0022 IsClearEnabled=\u0022...\u0022\n IsReadOnly=\u0022...\u0022 Caption=\u0022...\u0022/\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Rate something 1 to 5 stars.","relatedControls":["Slider","ComboBox"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"RatingControl - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Controls.RatingControl"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/rating"}]},{"id":"ratingcontrol-2","controlId":"ratingcontrol","controlName":"RatingControl","headerText":"PlaceholderValue of RatingControl","xaml":"\u003CRatingControl AutomationProperties.Name=\u0022RatingControl with placeholder\u0022 PlaceholderValue=\u0022...\u0022 /\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Rate something 1 to 5 stars.","relatedControls":["Slider","ComboBox"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"RatingControl - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Controls.RatingControl"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/rating"}]},{"id":"slider-1","controlId":"slider","controlName":"Slider","headerText":"A simple Slider.","xaml":"\u003CSlider AutomationProperties.Name=\u0022simple slider\u0022 Width=\u0022200\u0022/\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A control that lets the user select from a range of values by moving a Thumb control along a track.","relatedControls":["ComboBox","RatingControl"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"Slider - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.slider"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/slider"}]},{"id":"slider-2","controlId":"slider","controlName":"Slider","headerText":"A Slider with range and steps specified.","xaml":"\u003CSlider Width=\u0022200\u0022 Minimum=\u0022...\u0022 Maximum=\u0022...\u0022 StepFrequency=\u0022...\u0022\n SmallChange=\u0022...\u0022 Value=\u0022...\u0022 /\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A control that lets the user select from a range of values by moving a Thumb control along a track.","relatedControls":["ComboBox","RatingControl"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"Slider - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.slider"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/slider"}]},{"id":"slider-3","controlId":"slider","controlName":"Slider","headerText":"A Slider with tick marks.","xaml":"\u003CSlider\n AutomationProperties.Name=\u0022Slider with ticks\u0022\n TickFrequency=\u002220\u0022\n TickPlacement=\u0022Outside\u0022\n SnapsTo=\u0022...\u0022 /\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A control that lets the user select from a range of values by moving a Thumb control along a track.","relatedControls":["ComboBox","RatingControl"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"Slider - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.slider"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/slider"}]},{"id":"slider-4","controlId":"slider","controlName":"Slider","headerText":"A vertical slider with range and tick marks specified.","xaml":"\u003CSlider AutomationProperties.Name=\u0022vertical slider\u0022 Width=\u0022100\u0022 Orientation=\u0022Vertical\u0022\n TickFrequency=\u002210\u0022 TickPlacement=\u0022Outside\u0022 Maximum=\u002250\u0022 Minimum=\u0022-50\u0022/\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A control that lets the user select from a range of values by moving a Thumb control along a track.","relatedControls":["ComboBox","RatingControl"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"Slider - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.slider"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/slider"}]},{"id":"toggleswitch-1","controlId":"toggleswitch","controlName":"ToggleSwitch","headerText":"A simple ToggleSwitch.","xaml":"\u003CToggleSwitch AutomationProperties.Name=\u0022simple ToggleSwitch\u0022/\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A switch that can be toggled between 2 states.","relatedControls":["ToggleButton","RadioButton","CheckBox","AppBarToggleButton"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"ToggleSwitch - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.toggleswitch"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/toggles"}]},{"id":"toggleswitch-2","controlId":"toggleswitch","controlName":"ToggleSwitch","headerText":"A ToggleSwitch with custom header and content.","xaml":"\u003CStackPanel Orientation=\u0022Horizontal\u0022\u003E\n \u003CToggleSwitch Header=\u0022Toggle work\u0022 OffContent=\u0022Do work\u0022 OnContent=\u0022Working\u0022 IsOn=\u0022......\u0022 /\u003E\n \u003CProgressRing IsActive=\u0022{x:Bind ToggleSwitch2.IsOn, Mode=OneWay}\u0022 Width=\u002232\u0022/\u003E\n\u003C/StackPanel\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A switch that can be toggled between 2 states.","relatedControls":["ToggleButton","RadioButton","CheckBox","AppBarToggleButton"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"ToggleSwitch - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.toggleswitch"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/toggles"}]},{"id":"infobadge-1","controlId":"infobadge","controlName":"InfoBadge","headerText":"InfoBadge embedded in NavigationView","xaml":"\u003CNavigationViewItem x:Name=\u0022InboxPage\u0022 Content=\u0022Inbox\u0022 Icon=\u0022Mail\u0022 AutomationProperties.Name=\u0022Inbox, 5 notifications\u0022\u003E\n \u003CNavigationViewItem.InfoBadge\u003E\n \u003CInfoBadge x:Name=\u0022infoBadge1\u0022 Value=\u00225\u0022 Opacity=\u0022{x:Bind InfoBadgeOpacity, Mode=OneWay}\u0022/\u003E\n \u003C/NavigationViewItem.InfoBadge\u003E\n\u003C/NavigationViewItem\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"An non-intrusive UI to display notifications or bring focus to an area.","relatedControls":["InfoBar","TeachingTip","BadgeNotificationManager"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"InfoBadge - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.infobadge"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/info-badge"}]},{"id":"infobadge-2","controlId":"infobadge","controlName":"InfoBadge","headerText":"Different InfoBadge Styles","xaml":"\u003CStackPanel Orientation=\u0022Horizontal\u0022 Spacing=\u002220\u0022 HorizontalAlignment=\u0022Center\u0022/\u003E\n \u003CInfoBadge x:Name=\u0022infoBadge2\u0022 Style=\u0022{StaticResource ...IconInfoBadgeStyle}\u0022 HorizontalAlignment=\u0022Right\u0022/\u003E\n \u003CInfoBadge x:Name=\u0022infoBadge3\u0022 Style=\u0022{StaticResource ...ValueInfoBadgeStyle}\u0022 HorizontalAlignment=\u0022Right\u0022 Value=\u002210\u0022 /\u003E\n \u003CInfoBadge x:Name=\u0022infoBadge4\u0022 Style=\u0022{StaticResource ...DotInfoBadgeStyle}\u0022 VerticalAlignment=\u0022Center\u0022/\u003E\n\u003C/StackPanel\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"An non-intrusive UI to display notifications or bring focus to an area.","relatedControls":["InfoBar","TeachingTip","BadgeNotificationManager"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"InfoBadge - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.infobadge"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/info-badge"}]},{"id":"infobadge-3","controlId":"infobadge","controlName":"InfoBadge","headerText":"Placing an InfoBadge Inside Another Control","xaml":"\u003CButton Padding=\u00220\u0022 Width=\u0022200\u0022 Height=\u002260\u0022 ToolTipService.ToolTip=\u0022Refresh required\u0022\n HorizontalAlignment=\u0022Center\u0022 HorizontalContentAlignment=\u0022Stretch\u0022 VerticalContentAlignment=\u0022Stretch\u0022\u003E\n \u003CGrid HorizontalAlignment=\u0022Stretch\u0022 VerticalAlignment=\u0022Stretch\u0022 Width=\u0022Auto\u0022 Height=\u0022Auto\u0022\u003E\n \u003CSymbolIcon Symbol=\u0022Sync\u0022 HorizontalAlignment=\u0022Center\u0022/\u003E\n \u003CInfoBadge Background=\u0022#C42B1C\u0022 HorizontalAlignment=\u0022Right\u0022 VerticalAlignment=\u0022Top\u0022\u003E\n \u003CInfoBadge.IconSource\u003E\n \u003CFontIconSource FontFamily=\u0022{StaticResource SymbolThemeFontFamily}\u0022 Glyph=\u0022\u0026#xF13C;\u0022 /\u003E\n \u003C/InfoBadge.IconSource\u003E\n \u003C/InfoBadge\u003E\n \u003C/Grid\u003E\n\u003C/Button\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"An non-intrusive UI to display notifications or bring focus to an area.","relatedControls":["InfoBar","TeachingTip","BadgeNotificationManager"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"InfoBadge - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.infobadge"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/info-badge"}]},{"id":"infobadge-4","controlId":"infobadge","controlName":"InfoBadge","headerText":"InfoBadge with Dynamic Value","xaml":"\u003CInfoBadge Value=\u0022{Binding ElementName=ValueNumberBox, Path=Value, Mode=TwoWay}\u0022 /\u003E\n\u003CNumberBox x:Name=\u0022ValueNumberBox\u0022 Header=\u0022InfoBadge Value\u0022 Value=\u00221\u0022 Minimum=\u0022-1\u0022\n SpinButtonPlacementMode=\u0022Inline\u0022 ValueChanged=\u0022ValueNumberBox_ValueChanged\u0022 /\u003E","csharp":"private void ValueNumberBox_ValueChanged(Microsoft.UI.Xaml.Controls.NumberBox sender, Microsoft.UI.Xaml.Controls.NumberBoxValueChangedEventArgs args)\n{\n if((int)args.NewValue \u003E= -1)\n {\n DynamicInfoBadge.Value = (int)args.NewValue;\n }\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"An non-intrusive UI to display notifications or bring focus to an area.","relatedControls":["InfoBar","TeachingTip","BadgeNotificationManager"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"InfoBadge - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.infobadge"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/info-badge"}]},{"id":"infobar-1","controlId":"infobar","controlName":"InfoBar","headerText":"A closable InfoBar with options to change its Severity.","xaml":"\u003CInfoBar \n IsOpen=\u0022True\u0022\n Severity=\u0022Informational\u0022\n Title=\u0022Title\u0022\n Message=\u0022Essential app message for your users to be informed of, acknowledge, or take action on.\u0022 /\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"An inline message to display app-wide status change information.","relatedControls":["TeachingTip","ContentDialog"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"InfoBar - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.infobar"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/infobar"}]},{"id":"infobar-2","controlId":"infobar","controlName":"InfoBar","headerText":"A closable InfoBar with a long or short message and various buttons","xaml":"\u003CInfoBar \n IsOpen=\u0022True\u0022\n Title=\u0022Title\u0022\n Message=\u0022...\u0022 \u003E\n ...\n\u003C/InfoBar\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"An inline message to display app-wide status change information.","relatedControls":["TeachingTip","ContentDialog"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"InfoBar - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.infobar"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/infobar"}]},{"id":"infobar-3","controlId":"infobar","controlName":"InfoBar","headerText":"A closable InfoBar with options to display the close button and icon","xaml":"\u003CInfoBar \n IsOpen=\u0022True\u0022\n IsIconVisible=\u0022...\u0022 \n IsClosable=\u0022...\u0022\n Title=\u0022Title\u0022\n Message=\u0022Essential app message for your users to be informed of, acknowledge, or take action on.\u0022 /\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"An inline message to display app-wide status change information.","relatedControls":["TeachingTip","ContentDialog"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"InfoBar - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.infobar"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/infobar"}]},{"id":"progressbar-1","controlId":"progressbar","controlName":"ProgressBar","headerText":"An indeterminate progress bar.","xaml":"\u003CProgressBar Width=\u0022130\u0022 IsIndeterminate=\u0022True\u0022 ShowPaused=\u0022...\u0022 ShowError=\u0022...\u0022 /\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Shows the apps progress on a task, or that the app is performing ongoing work that doesn\u0027t block user interaction.","relatedControls":["ProgressRing"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"ProgressBar - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Controls.ProgressBar"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/progress-controls"}]},{"id":"progressbar-2","controlId":"progressbar","controlName":"ProgressBar","headerText":"A determinate progress bar.","xaml":"\u003CProgressBar Width=\u0022130\u0022 Value=\u0022...\u0022 /\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Shows the apps progress on a task, or that the app is performing ongoing work that doesn\u0027t block user interaction.","relatedControls":["ProgressRing"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"ProgressBar - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Controls.ProgressBar"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/progress-controls"}]},{"id":"progressring-1","controlId":"progressring","controlName":"ProgressRing","headerText":"An indeterminate progress ring.","xaml":"\u003CProgressRing IsActive=\u0022...\u0022 .../\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Shows the apps progress on a task, or that the app is performing ongoing work that does block user interaction.","relatedControls":["ProgressBar"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"ProgressRing - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.progressring"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/progress-controls"}]},{"id":"progressring-2","controlId":"progressring","controlName":"ProgressRing","headerText":"A determinate progress ring.","xaml":"\u003CProgressRing Width=\u002260\u0022 Height=\u002260\u0022 Value=\u0022...\u0022\n IsIndeterminate=\u0022False\u0022\n .../\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Shows the apps progress on a task, or that the app is performing ongoing work that does block user interaction.","relatedControls":["ProgressBar"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"ProgressRing - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.progressring"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/progress-controls"}]},{"id":"tooltip-1","controlId":"tooltip","controlName":"ToolTip","headerText":"A button with a simple ToolTip.","xaml":"\u003CButton Content=\u0022Button with a simple ToolTip.\u0022 ToolTipService.ToolTip=\u0022Simple ToolTip\u0022/\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Displays information for an element in a pop-up window.","relatedControls":["TeachingTip","Flyout","ContentDialog"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"ToolTip - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.tooltip"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/tooltips"}]},{"id":"tooltip-2","controlId":"tooltip","controlName":"ToolTip","headerText":"A TextBlock with an offset ToolTip.","xaml":"\u003CTextBlock Text=\u0022TextBlock with an offset ToolTip.\u0022\u003E\n \u003CToolTipService.ToolTip\u003E\n \u003CToolTip Content=\u0022Offset ToolTip.\u0022 VerticalOffset=\u0022-80\u0022/\u003E\n \u003C/ToolTipService.ToolTip\u003E\n\u003C/TextBlock\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Displays information for an element in a pop-up window.","relatedControls":["TeachingTip","Flyout","ContentDialog"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"ToolTip - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.tooltip"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/tooltips"}]},{"id":"tooltip-3","controlId":"tooltip","controlName":"ToolTip","headerText":"An Image with a ToolTip using PlacementRect.","xaml":"\u003CImage Source=\u0022/Assets/SampleMedia/cliff.jpg\u0022 Width=\u0022400\u0022 Height=\u0022266\u0022\u003E\n \u003CToolTipService.ToolTip\u003E\n \u003CToolTip Content=\u0022Non-occluding ToolTip.\u0022 PlacementRect=\u00220,0,400,266\u0022/\u003E\n \u003C/ToolTipService.ToolTip\u003E\n\u003C/Image\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Displays information for an element in a pop-up window.","relatedControls":["TeachingTip","Flyout","ContentDialog"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"ToolTip - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.tooltip"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/tooltips"}]},{"id":"contentdialog-1","controlId":"contentdialog","controlName":"ContentDialog","headerText":"A basic content dialog with content.","xaml":"\u003CPage\n x:Class=\u0022YourApp.YourPage\u0022\n xmlns=\u0022http://schemas.microsoft.com/winfx/2006/xaml/presentation\u0022\n xmlns:x=\u0022http://schemas.microsoft.com/winfx/2006/xaml\u0022\u003E\n\n \u003CStackPanel VerticalAlignment=\u0022Stretch\u0022 HorizontalAlignment=\u0022Stretch\u0022\u003E\n \u003C!-- Content body --\u003E\n \u003CTextBlock Text=\u0022Lorem ipsum dolor sit amet, adipisicing elit.\u0022 TextWrapping=\u0022Wrap\u0022 /\u003E\n \u003CCheckBox Content=\u0022Upload your content to the cloud.\u0022/\u003E\n \u003C/StackPanel\u003E\n\n\u003C/Page\u003E","csharp":"private async void ShowDialog_Click(object sender, RoutedEventArgs e)\n{\n ContentDialog dialog = new ContentDialog();\n\n // XamlRoot must be set in the case of a ContentDialog running in a Desktop app\n dialog.XamlRoot = this.XamlRoot;\n dialog.Style = Application.Current.Resources[\u0022DefaultContentDialogStyle\u0022] as Style;\n dialog.Title = \u0022Save your work?\u0022;\n dialog.PrimaryButtonText = \u0022Save\u0022;\n dialog.SecondaryButtonText = \u0022Don\u0027t Save\u0022;\n dialog.CloseButtonText = \u0022Cancel\u0022;\n dialog.DefaultButton = ContentDialogButton.Primary;\n dialog.Content = new ContentDialogContent();\n\n var result = await dialog.ShowAsync();\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A dialog box that can be customized to contain any XAML content.","relatedControls":["Flyout","MenuFlyout","TeachingTip","ToolTip"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"ContentDialog - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.contentdialog"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/dialogs-and-flyouts/dialogs"}]},{"id":"contentdialog-2","controlId":"contentdialog","controlName":"ContentDialog","headerText":"A content dialog without a default button.","xaml":"\u003CPage\n x:Class=\u0022YourApp.YourPage\u0022\n xmlns=\u0022http://schemas.microsoft.com/winfx/2006/xaml/presentation\u0022\n xmlns:x=\u0022http://schemas.microsoft.com/winfx/2006/xaml\u0022\u003E\n\n \u003CStackPanel VerticalAlignment=\u0022Stretch\u0022 HorizontalAlignment=\u0022Stretch\u0022\u003E\n \u003C!-- Content body --\u003E\n \u003CTextBlock Text=\u0022Lorem ipsum dolor sit amet, adipisicing elit.\u0022 TextWrapping=\u0022Wrap\u0022 /\u003E\n \u003CCheckBox Content=\u0022Upload your content to the cloud.\u0022/\u003E\n \u003C/StackPanel\u003E\n\n\u003C/Page\u003E","csharp":"private async void ShowDialogNoDefault_Click(object sender, RoutedEventArgs e)\n{\n ContentDialog dialog = new ContentDialog();\n\n // XamlRoot must be set in the case of a ContentDialog running in a Desktop app\n dialog.XamlRoot = this.XamlRoot;\n dialog.Title = \u0022Replace file?\u0022;\n dialog.PrimaryButtonText = \u0022Replace\u0022;\n dialog.SecondaryButtonText = \u0022Keep\u0022;\n dialog.CloseButtonText = \u0022Cancel\u0022;\n dialog.DefaultButton = ContentDialogButton.None;\n dialog.Content = new ContentDialogContent();\n\n var result = await dialog.ShowAsync();\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A dialog box that can be customized to contain any XAML content.","relatedControls":["Flyout","MenuFlyout","TeachingTip","ToolTip"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"ContentDialog - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.contentdialog"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/dialogs-and-flyouts/dialogs"}]},{"id":"flyout-1","controlId":"flyout","controlName":"Flyout","headerText":"A button with a flyout","xaml":"\u003CButton Content=\u0022Empty cart\u0022\u003E\n \u003CButton.Flyout\u003E\n \u003CFlyout\u003E\n \u003CStackPanel\u003E\n \u003CTextBlock Style=\u0022{ThemeResource BaseTextBlockStyle}\u0022 Text=\u0022All items will be removed. Do you want to continue?\u0022 Margin=\u00220,0,0,12\u0022 /\u003E\n \u003CButton Click=\u0022DeleteConfirmation_Click\u0022 Content=\u0022Yes, empty my cart\u0022 /\u003E\n \u003C/StackPanel\u003E\n \u003C/Flyout\u003E\n \u003C/Button.Flyout\u003E\n\u003C/Button\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Shows contextual information and enables user interaction.","relatedControls":["TeachingTip","ContentDialog","MenuFlyout","Button","AppBarButton"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"Flyout - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.flyout"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/dialogs-and-flyouts"}]},{"id":"popup-1","controlId":"popup","controlName":"Popup","headerText":"Popup with Offset Positioning","xaml":"\u003CGrid x:Name=\u0022Output\u0022 HorizontalAlignment=\u0022Left\u0022 VerticalAlignment=\u0022Top\u0022 \u003E\n \u003CButton Content=\u0022Show Popup (using Offset)\u0022 Click=\u0022ShowPopupOffsetClicked\u0022 /\u003E\n \u003CPopup x:Name=\u0022StandardPopup\u0022 VerticalOffset=\u0022...\u0022 HorizontalOffset=\u0022...\u0022 IsLightDismissEnabled=\u0022...\u0022\u003E\n \u003CBorder Padding=\u002220\u0022 CornerRadius=\u0022{StaticResource OverlayCornerRadius}\u0022 Width=\u0022200\u0022 Height=\u0022160\u0022 BorderThickness=\u00221\u0022 BorderBrush=\u0022{ThemeResource SurfaceStrokeColorDefaultBrush}\u0022\n Background=\u0022{ThemeResource AcrylicBackgroundFillColorDefaultBrush}\u0022\u003E\n \u003CStackPanel HorizontalAlignment=\u0022Center\u0022 VerticalAlignment=\u0022Center\u0022 Spacing=\u00228\u0022\u003E\n \u003CTextBlock Text=\u0022Simple Popup\u0022 FontSize=\u002216\u0022 HorizontalAlignment=\u0022Center\u0022 /\u003E\n \u003CButton Content=\u0022Close\u0022 Click=\u0022ClosePopupClicked\u0022 /\u003E\n \u003C/StackPanel\u003E\n \u003C/Border\u003E\n \u003C/Popup\u003E\n\u003C/Grid\u003E","csharp":"// Handles the Click event on the Button on the page and opens the Popup. \nprivate void ShowPopupOffsetClicked(object sender, RoutedEventArgs e)\n{\n // open the Popup if it isn\u0027t open already \n if (!StandardPopup.IsOpen) { StandardPopup.IsOpen = true; }\n}\n\n// Handles the Click event on the Button inside the Popup control and closes the Popup. \nprivate void ClosePopupClicked(object sender, RoutedEventArgs e)\n{\n // if the Popup is open, then close it \n if (StandardPopup.IsOpen) { StandardPopup.IsOpen = false; }\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A UI element displaying temporary content over existing interface.","relatedControls":["ContentDialog"],"apiNamespace":"Microsoft.UI.Xaml.Controls.Primitives","docs":[{"title":"Popup - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.primitives.popup"}]},{"id":"teachingtip-1","controlId":"teachingtip","controlName":"TeachingTip","headerText":"Show a targeted TeachingTip on a button.","xaml":"\u003CButton\n x:Name=\u0022TestButton1\u0022\n Click=\u0022TestButton1Click\u0022\n Content=\u0022Show TeachingTip\u0022 /\u003E\n\u003CTeachingTip\n x:Name=\u0022TestButton1TeachingTip\u0022\n Title=\u0022This is the title\u0022\n Subtitle=\u0022And this is the subtitle\u0022\n Target=\u0022{x:Bind TestButton1}\u0022\u003E\n \u003CTeachingTip.IconSource\u003E\n \u003CSymbolIconSource Symbol=\u0022Refresh\u0022 /\u003E\n \u003C/TeachingTip.IconSource\u003E\n\u003C/TeachingTip\u003E","csharp":"private void TestButton1Click(object sender, RoutedEventArgs e)\n{\n TestButton1TeachingTip.IsOpen = true;\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A content-rich flyout for guiding users and enabling teaching moments.","relatedControls":["ContentDialog","Flyout","ToolTip"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"TeachingTip - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.teachingtip"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/dialogs-and-flyouts/teaching-tip"}]},{"id":"teachingtip-2","controlId":"teachingtip","controlName":"TeachingTip","headerText":"Show a non-targeted TeachingTip with buttons.","xaml":"\u003CButton\n Click=\u0022TestButton2Click\u0022\n Content=\u0022Show TeachingTip\u0022 /\u003E\n\u003CTeachingTip\n x:Name=\u0022TestButton2TeachingTip\u0022\n Title=\u0022This is the title\u0022\n ActionButtonContent=\u0022Action button\u0022\n CloseButtonContent=\u0022Close button\u0022\n IsLightDismissEnabled=\u0022True\u0022\n PlacementMargin=\u002220\u0022\n PreferredPlacement=\u0022Auto\u0022\n Subtitle=\u0022And this is the subtitle\u0022 /\u003E","csharp":"private void TestButton2Click(object sender, RoutedEventArgs e)\n{\n TestButton2TeachingTip.IsOpen = true;\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A content-rich flyout for guiding users and enabling teaching moments.","relatedControls":["ContentDialog","Flyout","ToolTip"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"TeachingTip - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.teachingtip"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/dialogs-and-flyouts/teaching-tip"}]},{"id":"teachingtip-3","controlId":"teachingtip","controlName":"TeachingTip","headerText":"Show a targeted TeachingTip with hero content on a button.","xaml":"\u003CButton\n x:Name=\u0022TestButton3\u0022\n Click=\u0022TestButton3Click\u0022\n Content=\u0022Show TeachingTip\u0022 /\u003E\n\u003CTeachingTip\n x:Name=\u0022TestButton3TeachingTip\u0022\n Title=\u0022This is the title\u0022\n PreferredPlacement=\u0022Bottom\u0022\n Subtitle=\u0022And this is the subtitle\u0022\n Target=\u0022{x:Bind TestButton3}\u0022\u003E\n \u003CTeachingTip.HeroContent\u003E\n \u003CImage\n AutomationProperties.Name=\u0022Sunset\u0022\n Source=\u0022/Assets/SampleMedia/sunset.jpg\u0022 /\u003E\n \u003C/TeachingTip.HeroContent\u003E\n \u003CTeachingTip.Content\u003E\n \u003CTextBlock\n Margin=\u00220,16,0,0\u0022\n Text=\u0022Description can go here\u0022\n TextWrapping=\u0022WrapWholeWords\u0022 /\u003E\n \u003C/TeachingTip.Content\u003E\n\u003C/TeachingTip\u003E","csharp":"private void TestButton3Click(object sender, RoutedEventArgs e)\n{\n TestButton3TeachingTip.IsOpen = true;\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A content-rich flyout for guiding users and enabling teaching moments.","relatedControls":["ContentDialog","Flyout","ToolTip"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"TeachingTip - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.teachingtip"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/dialogs-and-flyouts/teaching-tip"}]},{"id":"annotatedscrollbar-1","controlId":"annotatedscrollbar","controlName":"AnnotatedScrollBar","headerText":"AnnotatedScrollBar linked to a ScrollView.","xaml":"\u003CScrollView x:Name=\u0022scrollView\u0022\n Background=\u0022LightGray\u0022 MaxWidth=\u0022800\u0022 MaxHeight=\u0022500\u0022\n VerticalScrollBarVisibility=\u0022Hidden\u0022\u003E\n \u003C!-- ... --\u003E\n\u003C/ScrollView\u003E\n \n\u003CAnnotatedScrollBar x:Name=\u0022annotatedScrollBar\u0022\n Margin=\u00224,0,48,0\u0022 MaxHeight=\u0022500\u0022\n HorizontalAlignment=\u0022Right\u0022\n DetailLabelRequested=\u0022AnnotatedScrollBar_DetailLabelRequested\u0022/\u003E","csharp":"private void AnnotatedScrollBarPage_Loaded(object sender, Microsoft.UI.Xaml.RoutedEventArgs e)\n{\n scrollView.ScrollPresenter.VerticalScrollController = annotatedScrollBar.ScrollController;\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A control that extends a regular vertical scrollbar\u0027s functionality for an easy navigation through large collections.","relatedControls":["ItemsView","ScrollView"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"AnnotatedScrollBar - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.annotatedscrollbar"}]},{"id":"pipspager-1","controlId":"pipspager","controlName":"PipsPager","headerText":"PipsPager integrated with a FlipView","xaml":"\u003CStackPanel\u003E\n \u003CFlipView x:Name=\u0022Gallery\u0022 MaxWidth=\u0022400\u0022 Height=\u0022270\u0022 ItemsSource=\u0022{x:Bind Pictures}\u0022\u003E\n \u003CFlipView.ItemTemplate\u003E\n \u003CDataTemplate x:DataType=\u0022x:String\u0022\u003E\n \u003CImage Source=\u0022{x:Bind Mode=OneTime}\u0022 /\u003E\n \u003C/DataTemplate\u003E\n \u003C/FlipView.ItemTemplate\u003E\n \u003C/FlipView\u003E\n \u003CPipsPager x:Name=\u0022FlipViewPipsPager\u0022\n HorizontalAlignment=\u0022Center\u0022\n Margin=\u00220, 12, 0, 0\u0022\n NumberOfPages=\u0022{x:Bind Pictures.Count}\u0022\n SelectedPageIndex=\u0022{x:Bind Path=Gallery.SelectedIndex, Mode=TwoWay}\u0022 /\u003E\n\u003C/StackPanel\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A control to let the user navigate through a paginated collection when the page numbers do not need to be visually known.","relatedControls":["ScrollViewer","FlipView","ItemsRepeater"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"PipsPager - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.pipspager"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/pipspager"}]},{"id":"pipspager-2","controlId":"pipspager","controlName":"PipsPager","headerText":"PipsPager with options to change its orientation, button visibility, and wrap mode.","xaml":"\u003CPipsPager\n Orientation=\u0022...\u0022\n PreviousButtonVisibility=\u0022...\u0022\n NextButtonVisibility=\u0022...\u0022\n WrapMode=\u0022...\u0022 /\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A control to let the user navigate through a paginated collection when the page numbers do not need to be visually known.","relatedControls":["ScrollViewer","FlipView","ItemsRepeater"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"PipsPager - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.pipspager"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/pipspager"}]},{"id":"scrollview-1","controlId":"scrollview","controlName":"ScrollView","headerText":"Content inside of a ScrollView.","xaml":"\u003CScrollView Height=\u0022266\u0022 Width=\u0022400\u0022 ContentOrientation=\u0022None\u0022\n ZoomMode=\u0022...\u0022 IsTabStop=\u0022True\u0022\n VerticalAlignment=\u0022Top\u0022 HorizontalAlignment=\u0022Left\u0022\n HorizontalScrollMode=\u0022...\u0022 HorizontalScrollBarVisibility=\u0022...\u0022\n VerticalScrollMode=\u0022...\u0022 VerticalScrollBarVisibility=\u0022...\u0022\u003E\n \u003CImage Source=\u0022ms-appx:///Assets/YourImage.png\u0022 AutomationProperties.Name=\u0022cliff\u0022 Stretch=\u0022None\u0022\n HorizontalAlignment=\u0022Center\u0022 VerticalAlignment=\u0022Center\u0022/\u003E\n\u003C/ScrollView\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A container control that lets the user pan and zoom its content.","relatedControls":["Viewbox","Canvas","Grid","StackPanel","RelativePanel","ParallaxView","ItemsView","ScrollViewer"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"ScrollView - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.scrollview"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/scroll-controls"}]},{"id":"scrollview-2","controlId":"scrollview","controlName":"ScrollView","headerText":"Constant velocity scrolling.","xaml":"\u003CScrollView Height=\u0022300\u0022 Width=\u0022400\u0022 IsTabStop=\u0022True\u0022\n VerticalAlignment=\u0022Top\u0022 HorizontalAlignment=\u0022Left\u0022\u003E\n \u003CImage Source=\u0022ms-appx:///Assets/YourImage.png\u0022 Stretch=\u0022Uniform\u0022 AutomationProperties.Name=\u0022grapes\u0022/\u003E\n \u003CImage Source=\u0022ms-appx:///Assets/YourImage.png\u0022 Stretch=\u0022Uniform\u0022 AutomationProperties.Name=\u0022rainier\u0022/\u003E\n \u003CImage Source=\u0022ms-appx:///Assets/YourImage.png\u0022 Stretch=\u0022Uniform\u0022 AutomationProperties.Name=\u0022sunset\u0022/\u003E\n \u003CImage Source=\u0022ms-appx:///Assets/YourImage.png\u0022 Stretch=\u0022Uniform\u0022 AutomationProperties.Name=\u0022treetops\u0022/\u003E\n \u003CImage Source=\u0022ms-appx:///Assets/YourImage.png\u0022 Stretch=\u0022Uniform\u0022 AutomationProperties.Name=\u0022valley\u0022/\u003E\n \u003CImage Source=\u0022ms-appx:///Assets/YourImage.png\u0022 Stretch=\u0022Uniform\u0022 AutomationProperties.Name=\u0022cliff\u0022/\u003E\n\u003C/ScrollView\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A container control that lets the user pan and zoom its content.","relatedControls":["Viewbox","Canvas","Grid","StackPanel","RelativePanel","ParallaxView","ItemsView","ScrollViewer"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"ScrollView - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.scrollview"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/scroll-controls"}]},{"id":"scrollview-3","controlId":"scrollview","controlName":"ScrollView","headerText":"Programmatic scroll with custom animation.","xaml":"\u003CScrollView Height=\u0022300\u0022 Width=\u0022400\u0022 IsTabStop=\u0022True\u0022\n ScrollAnimationStarting=\u0022ScrollView_ScrollAnimationStarting\u0022\n VerticalAlignment=\u0022Top\u0022 HorizontalAlignment=\u0022Left\u0022\u003E\n \u003CImage Source=\u0022ms-appx:///Assets/YourImage.png\u0022 Stretch=\u0022Uniform\u0022 AutomationProperties.Name=\u0022leaves\u0022/\u003E\n \u003CImage Source=\u0022ms-appx:///Assets/YourImage.png\u0022 Stretch=\u0022Uniform\u0022 AutomationProperties.Name=\u0022carousel\u0022/\u003E\n \u003CImage Source=\u0022ms-appx:///Assets/YourImage.png\u0022 Stretch=\u0022Uniform\u0022 AutomationProperties.Name=\u0022bicycles\u0022/\u003E\n \u003CImage Source=\u0022ms-appx:///Assets/YourImage.png\u0022 Stretch=\u0022Uniform\u0022 AutomationProperties.Name=\u0022pond\u0022/\u003E\n \u003CImage Source=\u0022ms-appx:///Assets/YourImage.png\u0022 Stretch=\u0022Uniform\u0022 AutomationProperties.Name=\u0022marina\u0022/\u003E\n \u003CImage Source=\u0022ms-appx:///Assets/YourImage.png\u0022 Stretch=\u0022Uniform\u0022 AutomationProperties.Name=\u0022beach\u0022/\u003E\n \u003CImage Source=\u0022ms-appx:///Assets/YourImage.png\u0022 Stretch=\u0022Uniform\u0022 AutomationProperties.Name=\u0022rampart\u0022/\u003E\n \u003CImage Source=\u0022ms-appx:///Assets/YourImage.png\u0022 Stretch=\u0022Uniform\u0022 AutomationProperties.Name=\u0022mountain\u0022/\u003E\n\u003C/ScrollView\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A container control that lets the user pan and zoom its content.","relatedControls":["Viewbox","Canvas","Grid","StackPanel","RelativePanel","ParallaxView","ItemsView","ScrollViewer"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"ScrollView - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.scrollview"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/scroll-controls"}]},{"id":"scrollviewer-1","controlId":"scrollviewer","controlName":"ScrollViewer","headerText":"Content inside of a ScrollViewer.","xaml":"\u003CScrollViewer Height=\u0022266\u0022 Width=\u0022400\u0022 ZoomMode=\u0022...\u0022\n IsTabStop=\u0022True\u0022 IsVerticalScrollChainingEnabled=\u0022True\u0022\n HorizontalAlignment=\u0022Left\u0022 VerticalAlignment=\u0022Top\u0022\n ViewChanged=\u0022ScrollViewerControl_ViewChanged\u0022\n HorizontalScrollMode=\u0022...\u0022 HorizontalScrollBarVisibility=\u0022...\u0022\n VerticalScrollMode=\u0022...\u0022 VerticalScrollBarVisibility=\u0022...\u0022\u003E\n \u003CImage Source=\u0022ms-appx:///Assets/YourImage.png\u0022 AutomationProperties.Name=\u0022cliff\u0022 Stretch=\u0022None\u0022\n HorizontalAlignment=\u0022Left\u0022 VerticalAlignment=\u0022Top\u0022/\u003E\n\u003C/ScrollViewer\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A container control that lets the user pan and zoom its content.","relatedControls":["Viewbox","Canvas","Grid","StackPanel","RelativePanel","ParallaxView","ScrollView"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"ScrollViewer - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.scrollviewer"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/scroll-controls"}]},{"id":"semanticzoom-1","controlId":"semanticzoom","controlName":"SemanticZoom","headerText":"A simple SemanticZoom","xaml":"\u003CSemanticZoom Height=\u0022500\u0022\u003E\n \u003CSemanticZoom.ZoomedInView\u003E\n \u003CGridView ItemsSource=\u0022{x:Bind cvsGroups.View}\u0022 SelectionMode=\u0022None\u0022\n ItemTemplate=\u0022{StaticResource ZoomedInTemplate}\u0022\u003E\n \u003CGridView.GroupStyle\u003E\n \u003CGroupStyle HeaderTemplate=\u0022{StaticResource ZoomedInGroupHeaderTemplate}\u0022 /\u003E\n \u003C/GridView.GroupStyle\u003E\n \u003C/GridView\u003E\n \u003C/SemanticZoom.ZoomedInView\u003E\n\n \u003CSemanticZoom.ZoomedOutView\u003E\n \u003CListView ItemsSource=\u0022{x:Bind cvsGroups.View.CollectionGroups}\u0022 HorizontalAlignment=\u0022Stretch\u0022\n SelectionMode=\u0022None\u0022 ItemTemplate=\u0022{StaticResource ZoomedOutTemplate}\u0022 /\u003E\n \u003C/SemanticZoom.ZoomedOutView\u003E\n\u003C/SemanticZoom\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Lets the user zoom between two different views of a collection, making it easier to navigate through large collections of items.","relatedControls":["GridView","ListView"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"SemanticZoom - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.semanticzoom"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/semantic-zoom"}]},{"id":"border-1","controlId":"border","controlName":"Border","headerText":"A Border around a TextBlock.","xaml":"\u003CBorder BorderThickness=\u0022...\u0022 BorderBrush=\u0022...\u0022 Background=\u0022...\u0022\u003E\n \u003CTextBlock Text=\u0022Text inside a border\u0022 FontSize=\u002218\u0022 Foreground=\u0022Black\u0022 /\u003E\n\u003C/Border\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A container control that draws a boundary line, background, or both, around another object.","relatedControls":["Canvas","Grid","StackPanel","VariableSizedWrapGrid","RelativePanel"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"Border - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.border"}]},{"id":"canvas-1","controlId":"canvas","controlName":"Canvas","headerText":"A Canvas control.","xaml":"\u003CCanvas Width=\u0022120\u0022 Height=\u0022120\u0022 Background=\u0022Gray\u0022\u003E\n \u003CRectangle Fill=\u0022Red\u0022 Canvas.Left=\u0022...\u0022 Canvas.Top=\u0022...\u0022 Canvas.ZIndex=\u0022...\u0022 /\u003E\n \u003CRectangle Fill=\u0022Blue\u0022 Canvas.Left=\u002220\u0022 Canvas.Top=\u002220\u0022 Canvas.ZIndex=\u00221\u0022 /\u003E\n \u003CRectangle Fill=\u0022Green\u0022 Canvas.Left=\u002240\u0022 Canvas.Top=\u002240\u0022 Canvas.ZIndex=\u00222\u0022 /\u003E\n \u003CRectangle Fill=\u0022Yellow\u0022 Canvas.Left=\u002260\u0022 Canvas.Top=\u002260\u0022 Canvas.ZIndex=\u00223\u0022 /\u003E\n\u003C/Canvas\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A layout panel that supports absolute positioning of child elements relative to the top left corner of the canvas.","relatedControls":["Border","Grid","StackPanel","VariableSizedWrapGrid","RelativePanel"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"Canvas - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.canvas"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/layout/layout-panels"}]},{"id":"expander-1","controlId":"expander","controlName":"Expander","headerText":"An Expander with text in the header and content areas","xaml":"\u003CExpander\n IsExpanded=\u0022...\u0022\n ExpandDirection=\u0022...\u0022\n VerticalAlignment=\u0022...\u0022\n Header=\u0022This text is in the header\u0022\n Content=\u0022This is in the content\u0022/\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A container with a header that can be expanded to show a body with more content.","relatedControls":["Flyout","ItemsRepeater","SplitView"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"Expander - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.expander"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/expander"}]},{"id":"expander-2","controlId":"expander","controlName":"Expander","headerText":"Modifying Expanders content alignment","xaml":"\u003CExpander Width=\u0022500\u0022 HorizontalContentAlignment=\u0022Left\u0022 Padding=\u00220\u0022\u003E\n \u003CExpander.Header\u003E\n \u003CToggleButton Content=\u0022This ToggleButton is centered\u0022 HorizontalAlignment=\u0022Center\u0022/\u003E\n \u003C/Expander.Header\u003E\n \u003CExpander.Content\u003E\n \u003CButton Margin=\u00224\u0022 Content=\u0022This Button is left aligned\u0022/\u003E\n \u003C/Expander.Content\u003E\n\u003C/Expander\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A container with a header that can be expanded to show a body with more content.","relatedControls":["Flyout","ItemsRepeater","SplitView"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"Expander - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.expander"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/expander"}]},{"id":"grid-1","controlId":"grid","controlName":"Grid","headerText":"A 3x3 Grid control.","xaml":"\u003CGrid\n Background=\u0022Gray\u0022\n ColumnDefinitions=\u002250, 50, 50\u0022\n RowDefinitions =\u002250, 50, 50\u0022\n ColumnSpacing=\u0022...\u0022\n RowSpacing=\u0022...\u0022\u003E\n \u003CRectangle Fill=\u0022Red\u0022 Grid.Column=\u0022...\u0022 Grid.Row=\u0022...\u0022 /\u003E\n \u003CRectangle Fill=\u0022Blue\u0022 Grid.Row=\u00221\u0022 /\u003E\n \u003CRectangle Fill=\u0022Green\u0022 Grid.Column=\u00221\u0022 /\u003E\n \u003CRectangle Fill=\u0022Yellow\u0022 Grid.Column=\u00221\u0022 Grid.Row=\u00221\u0022 /\u003E\n\u003C/Grid\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A layout panel that supports arranging child elements in rows and columns. ","relatedControls":["Border","Canvas","StackPanel","VariableSizedWrapGrid","RelativePanel"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"Grid - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.grid"},{"title":"Tutorial","uri":"https://learn.microsoft.com/windows/apps/design/layout/grid-tutorial"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/layout/layout-panels#grid"}]},{"id":"relativepanel-1","controlId":"relativepanel","controlName":"RelativePanel","headerText":"A RelativePanel control.","xaml":"\u003CRelativePanel Width=\u0022300\u0022\u003E\n \u003CRectangle x:Name=\u0022Rectangle1\u0022 Fill=\u0022Red\u0022 Height=\u002250\u0022 Width=\u002250\u0022/\u003E\n \u003CRectangle x:Name=\u0022Rectangle2\u0022 Fill=\u0022Blue\u0022 Height=\u002250\u0022 Width=\u002250\u0022 RelativePanel.RightOf=\u0022Rectangle1\u0022 Margin=\u00228,0,0,0\u0022/\u003E\n \u003CRectangle x:Name=\u0022Rectangle3\u0022 Fill=\u0022Green\u0022 Height=\u002250\u0022 Width=\u002250\u0022 RelativePanel.AlignRightWithPanel=\u0022True\u0022/\u003E\n \u003CRectangle x:Name=\u0022Rectangle4\u0022 Fill=\u0022Yellow\u0022 Height=\u002250\u0022 Width=\u002250\u0022 RelativePanel.Below=\u0022Rectangle3\u0022 RelativePanel.AlignHorizontalCenterWith=\u0022Rectangle3\u0022 Margin=\u00220,8,0,0\u0022/\u003E\n\u003C/RelativePanel\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A panel that uses relationships between elements to define layout.","relatedControls":["Grid","StackPanel","Border","Canvas","Viewbox"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"RelativePanel - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.relativepanel"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/layout/layout-panels"}]},{"id":"splitview-1","controlId":"splitview","controlName":"SplitView","headerText":"A basic SplitView.","xaml":"\u003CSplitView x:Name=\u0022splitView\u0022 PaneBackground=\u0022...\u0022\n IsPaneOpen=\u0022...\u0022 OpenPaneLength=\u0022...\u0022 CompactPaneLength=\u0022...\u0022 DisplayMode=\u0022...\u0022\u003E\n \u003CSplitView.Pane\u003E\n \u003CGrid\u003E\n \u003CGrid.RowDefinitions\u003E\n \u003CRowDefinition Height=\u0022Auto\u0022/\u003E\n \u003CRowDefinition Height=\u0022*\u0022/\u003E\n \u003CRowDefinition Height=\u0022Auto\u0022/\u003E\n \u003C/Grid.RowDefinitions\u003E\n \u003CTextBlock Text=\u0022PANE CONTENT\u0022 x:Name=\u0022PaneHeader\u0022 Margin=\u002260,12,0,0\u0022 Style=\u0022{StaticResource BaseTextBlockStyle}\u0022/\u003E\n \u003CListView x:Name=\u0022NavLinksList\u0022 Margin=\u00220,12,0,0\u0022 SelectionMode=\u0022Single\u0022 Grid.Row=\u00221\u0022 VerticalAlignment=\u0022Stretch\u0022\n ItemClick=\u0022NavLinksList_ItemClick\u0022 IsItemClickEnabled=\u0022True\u0022\n ItemsSource=\u0022{x:Bind NavLinks}\u0022 ItemTemplate=\u0022{StaticResource NavLinkItemTemplate}\u0022/\u003E\n \u003C/Grid\u003E\n \u003C/SplitView.Pane\u003E\n \n \u003CGrid\u003E\n \u003CGrid.RowDefinitions\u003E\n \u003CRowDefinition Height=\u0022Auto\u0022/\u003E\n \u003CRowDefinition Height=\u0022*\u0022/\u003E\n \u003C/Grid.RowDefinitions\u003E\n \u003CTextBlock Text=\u0022SPLITVIEW CONTENT\u0022 Margin=\u002212,12,0,0\u0022 Style=\u0022{StaticResource BaseTextBlockStyle}\u0022/\u003E\n \u003CTextBlock x:Name=\u0022content\u0022 Grid.Row=\u00221\u0022 Margin=\u002212,12,0,0\u0022 Style=\u0022{StaticResource BodyTextBlockStyle}\u0022 /\u003E\n \u003C/Grid\u003E\n\u003C/SplitView\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A container that has 2 content areas, with multiple display options for the pane.","relatedControls":["StackPanel","ListView","GridView","Grid","RelativePanel"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"SplitView - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.splitview"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/split-view"}]},{"id":"stackpanel-1","controlId":"stackpanel","controlName":"StackPanel","headerText":"A StackPanel control.","xaml":"\u003CStackPanel\n Orientation=\u0022...\u0022\n Spacing=\u0022...\u0022\u003E\n \u003CRectangle Fill=\u0022Red\u0022/\u003E\n \u003CRectangle Fill=\u0022Blue\u0022/\u003E\n \u003CRectangle Fill=\u0022Green\u0022/\u003E\n \u003CRectangle Fill=\u0022Yellow\u0022/\u003E\n\u003C/StackPanel\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A layout panel that arranges child elements into a single line that can be oriented horizontally or vertically.","relatedControls":["Border","Canvas","Grid","VariableSizedWrapGrid","RelativePanel"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"StackPanel - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.stackpanel"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/layout/layout-panels"}]},{"id":"variablesizedwrapgrid-1","controlId":"variablesizedwrapgrid","controlName":"VariableSizedWrapGrid","headerText":"A VariableSizedWrapGrid control.","xaml":"\u003CVariableSizedWrapGrid Orientation=\u0022...\u0022 MaximumRowsOrColumns=\u00223\u0022 ItemHeight=\u002244\u0022 ItemWidth=\u002244\u0022\u003E\n \u003CRectangle Fill=\u0022Red\u0022/\u003E\n \u003CRectangle Fill=\u0022Blue\u0022 Height=\u002280\u0022 VariableSizedWrapGrid.RowSpan=\u00222\u0022/\u003E\n \u003CRectangle Fill=\u0022Green\u0022 Width=\u002280\u0022 VariableSizedWrapGrid.ColumnSpan=\u00222\u0022/\u003E\n \u003CRectangle Fill=\u0022Yellow\u0022 Height=\u002280\u0022 Width=\u002280\u0022 VariableSizedWrapGrid.RowSpan=\u00222\u0022 VariableSizedWrapGrid.ColumnSpan=\u00222\u0022/\u003E\n\u003C/VariableSizedWrapGrid\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A layout panel that supports arranging child elements in rows and columns. Each child element can span multiple rows and columns.","relatedControls":["Border","Canvas","Grid","StackPanel","RelativePanel"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"VariableSizedWrapGrid - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.variablesizedwrapgrid"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/layout/layout-panels"}]},{"id":"viewbox-1","controlId":"viewbox","controlName":"Viewbox","headerText":"Content inside of a Viewbox.","xaml":"\u003CViewbox Height=\u0022...\u0022 Width=\u0022...\u0022 Stretch=\u0022...\u0022 StretchDirection=\u0022...\u0022\u003E\n \u003CBorder BorderBrush=\u0022Gray\u0022 BorderThickness=\u002215\u0022\u003E\n \u003CStackPanel Background=\u0022DarkGray\u0022\u003E\n \u003CStackPanel Orientation=\u0022Horizontal\u0022\u003E\n \u003CRectangle Fill=\u0022Blue\u0022 Height=\u002210\u0022 Width=\u002240\u0022/\u003E\n \u003CRectangle Fill=\u0022Green\u0022 Height=\u002210\u0022 Width=\u002240\u0022/\u003E\n \u003CRectangle Fill=\u0022Red\u0022 Height=\u002210\u0022 Width=\u002240\u0022/\u003E\n \u003CRectangle Fill=\u0022Yellow\u0022 Height=\u002210\u0022 Width=\u002240\u0022/\u003E\n \u003C/StackPanel\u003E\n \u003CImage Source=\u0022ms-appx:///Assets/YourImage.png\u0022/\u003E\n \u003CTextBlock Text=\u0022This is text.\u0022 HorizontalAlignment=\u0022Center\u0022/\u003E\n \u003C/StackPanel\u003E\n \u003C/Border\u003E\n\u003C/Viewbox\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A container control that scales its content to a specified size.","relatedControls":["ScrollViewer","Canvas","Grid","StackPanel","RelativePanel"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"Viewbox - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.Viewbox"}]},{"id":"breadcrumbbar-1","controlId":"breadcrumbbar","controlName":"BreadcrumbBar","headerText":"A BreadcrumbBar control","xaml":"\u003CBreadcrumbBar x:Name=\u0022BreadcrumbBar1\u0022/\u003E","csharp":"BreadcrumbBar1.ItemsSource = new string[] { \u0022Home\u0022, \u0022Documents\u0022, \u0022Design\u0022, \u0022Northwind\u0022, \u0022Images\u0022, \u0022Folder1\u0022, \u0022Folder2\u0022, \u0022Folder3\u0022 };","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Shows the trail of navigation taken to the current location.","relatedControls":["NavigationView","Pivot","TabView"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"BreadcrumbBar - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.breadcrumbbar"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/breadcrumbbar"}]},{"id":"breadcrumbbar-2","controlId":"breadcrumbbar","controlName":"BreadcrumbBar","headerText":"BreadCrumbBar Control with Custom DataTemplate","xaml":"\u003CBreadcrumbBar x:Name=\u0022BreadcrumbBar2\u0022\u003E\n \u003CBreadcrumbBar.ItemTemplate\u003E\n \u003CDataTemplate x:DataType=\u0022l:Folder\u0022\u003E\n \u003CBreadcrumbBarItem Content=\u0022{Binding}\u0022 AutomationProperties.Name=\u0022{Binding Name}\u0022\u003E\n \u003CBreadcrumbBarItem.ContentTemplate\u003E\n \u003CDataTemplate\u003E\n \u003CTextBlock Text=\u0022{Binding Name}\u0022 /\u003E\n \u003C/DataTemplate\u003E\n \u003C/BreadcrumbBarItem.ContentTemplate\u003E\n \u003C/BreadcrumbBarItem\u003E\n \u003C/DataTemplate\u003E\n \u003C/BreadcrumbBar.ItemTemplate\u003E\n\u003C/BreadcrumbBar\u003E","csharp":"public class Folder\n{\n public string Name { get; set; }\n}\n\nBreadcrumbBar2.ItemsSource = new ObservableCollection\u003CFolder\u003E{\n new Folder { Name = \u0022Home\u0022},\n new Folder { Name = \u0022Folder1\u0022 },\n new Folder { Name = \u0022Folder2\u0022 },\n new Folder { Name = \u0022Folder3\u0022 },\n};\nBreadcrumbBar2.ItemClicked \u002B= BreadcrumbBar2_ItemClicked;\n\nprivate void BreadcrumbBar2_ItemClicked(BreadcrumbBar sender, BreadcrumbBarItemClickedEventArgs args)\n{\n var items = BreadcrumbBar2.ItemsSource as ObservableCollection\u003CFolder\u003E;\n for (int i = items.Count - 1; i \u003E= args.Index \u002B 1; i--)\n {\n items.RemoveAt(i);\n }\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Shows the trail of navigation taken to the current location.","relatedControls":["NavigationView","Pivot","TabView"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"BreadcrumbBar - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.breadcrumbbar"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/breadcrumbbar"}]},{"id":"navigationview-1","controlId":"navigationview","controlName":"NavigationView","headerText":"NavigationView with default PaneDisplayMode","xaml":"\u003CNavigationView x:Name=\u0022nvSample\u0022\u003E\n \u003CNavigationView.MenuItems\u003E\n \u003CNavigationViewItem Icon=\u0022Play\u0022 Content=\u0022Menu Item1\u0022 Tag=\u0022YourPage\u0022 /\u003E\n \u003CNavigationViewItem Icon=\u0022Save\u0022 Content=\u0022Menu Item2\u0022 Tag=\u0022YourPage\u0022 /\u003E\n \u003CNavigationViewItem Icon=\u0022Refresh\u0022 Content=\u0022Menu Item3\u0022 Tag=\u0022YourPage\u0022 /\u003E\n \u003CNavigationViewItem Icon=\u0022Download\u0022 Content=\u0022Menu Item4\u0022 Tag=\u0022YourPage\u0022 /\u003E\n \u003C/NavigationView.MenuItems\u003E\n \u003CFrame x:Name=\u0022contentFrame\u0022/\u003E\n\u003C/NavigationView\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Common vertical layout for top-level areas of your app via a collapsible navigation menu.","relatedControls":["SplitView","Pivot"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"NavigationView - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Controls.NavigationView"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/navigationview"}]},{"id":"navigationview-2","controlId":"navigationview","controlName":"NavigationView","headerText":"NavigationView with PaneDisplayMode set to Top","xaml":"\u003CNavigationView x:Name=\u0022nvSample\u0022 Header=\u0022This is Header Text\u0022 PaneDisplayMode=\u0022Top\u0022\u003E\n \u003CNavigationView.MenuItems\u003E\n \u003CNavigationViewItem Content=\u0022Menu Item1\u0022 Tag=\u0022YourPage\u0022 /\u003E\n \u003CNavigationViewItem Content=\u0022Menu Item2\u0022 Tag=\u0022YourPage\u0022 /\u003E\n \u003CNavigationViewItem Content=\u0022Menu Item3\u0022 Tag=\u0022YourPage\u0022 /\u003E\n \u003CNavigationViewItem Content=\u0022Menu Item4\u0022 Tag=\u0022YourPage\u0022 /\u003E\n \u003C/NavigationView.MenuItems\u003E\n \u003CFrame x:Name=\u0022contentFrame\u0022/\u003E\n\u003C/NavigationView\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Common vertical layout for top-level areas of your app via a collapsible navigation menu.","relatedControls":["SplitView","Pivot"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"NavigationView - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Controls.NavigationView"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/navigationview"}]},{"id":"navigationview-3","controlId":"navigationview","controlName":"NavigationView","headerText":"NavigationView that switches pane orientation based on window width","xaml":"\u003C!-- Put the following VisualStateGroup(s) inside the first component of your Page --\u003E\n\u003CVisualStateManager.VisualStateGroups\u003E\n \u003CVisualStateGroup\u003E\n \u003CVisualState\u003E\n \u003CVisualState.StateTriggers\u003E\n \u003CAdaptiveTrigger MinWindowWidth=\u0022{x:Bind nvSample.CompactModeThresholdWidth}\u0022 /\u003E\n \u003C/VisualState.StateTriggers\u003E\n \u003CVisualState.Setters\u003E\n \u003CSetter Target=\u0022nvSample.PaneDisplayMode\u0022 Value=\u0022Top\u0022 /\u003E\n \u003C/VisualState.Setters\u003E\n \u003C/VisualState\u003E\n \u003C/VisualStateGroup\u003E\n\u003C/VisualStateManager.VisualStateGroups \u003E\n\n\u003CNavigationView x:Name=\u0022nvSample\u0022\u003E\n \u003CNavigationView.MenuItems\u003E\n \u003CNavigationViewItem Content=\u0022Menu Item1\u0022 Tag=\u0022YourPage\u0022 /\u003E\n \u003CNavigationViewItem Content=\u0022Menu Item2\u0022 Tag=\u0022YourPage\u0022 /\u003E\n \u003CNavigationViewItem Content=\u0022Menu Item3\u0022 Tag=\u0022YourPage\u0022 /\u003E\n \u003CNavigationViewItem Content=\u0022Menu Item4\u0022 Tag=\u0022YourPage\u0022 /\u003E\n \u003C/NavigationView.MenuItems\u003E\n \u003CFrame x:Name=\u0022contentFrame\u0022/\u003E\n\u003C/NavigationView\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Common vertical layout for top-level areas of your app via a collapsible navigation menu.","relatedControls":["SplitView","Pivot"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"NavigationView - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Controls.NavigationView"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/navigationview"}]},{"id":"navigationview-4","controlId":"navigationview","controlName":"NavigationView","headerText":"Tying selection and focus - Tabs","xaml":"\u003CNavigationView x:Name=\u0022nvSample\u0022 PaneDisplayMode=\u0022Top\u0022 \n SelectionFollowsFocus=\u0022Enabled\u0022 IsBackButtonVisible=\u0022Collapsed\u0022\u003E\n \u003CNavigationView.MenuItems\u003E\n \u003CNavigationViewItem Icon=\u0022Play\u0022 Content=\u0022Item1\u0022 x:Name=\u0022YourPageItem\u0022 /\u003E\n \u003CNavigationViewItem Icon=\u0022Save\u0022 Content=\u0022Item2\u0022 x:Name=\u0022YourPageItem\u0022 /\u003E\n \u003CNavigationViewItem Icon=\u0022Refresh\u0022 Content=\u0022Item3\u0022 x:Name=\u0022YourPageItem\u0022 /\u003E\n \u003CNavigationViewItem Icon=\u0022Download\u0022 Content=\u0022Item4\u0022 x:Name=\u0022YourPageItem\u0022 /\u003E\n \u003C/NavigationView.MenuItems\u003E\n \u003CFrame x:Name=\u0022contentFrame\u0022/\u003E\n\u003C/NavigationView\u003E","csharp":"//C# code behind\nprivate void NavView_ItemInvoked(NavigationView sender, NavigationViewItemInvokedEventArgs args)\n{\n FrameNavigationOptions navOptions = new FrameNavigationOptions();\n navOptions.TransitionInfoOverride = args.RecommendedNavigationTransitionInfo;\n if (sender.PaneDisplayMode == NavigationViewPaneDisplayMode.Top)\n {\n navOptions.IsNavigationStackEnabled = False;\n }\n Type pageType;\n if (args.InvokedItem == YourPageItem) \n {\n pageType = typeof(YourPage);\n }\n else if (args.InvokedItem == YourPageItem) \n {\n pageType = typeof(YourPage);\n }\n else if (args.InvokedItem == YourPageItem) \n {\n pageType = typeof(YourPage);\n }\n else if (args.InvokedItem == YourPageItem) \n {\n pageType = typeof(YourPage);\n }\n ContentFrame.NavigateToType(pageType, null, navOptions);\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Common vertical layout for top-level areas of your app via a collapsible navigation menu.","relatedControls":["SplitView","Pivot"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"NavigationView - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Controls.NavigationView"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/navigationview"}]},{"id":"navigationview-5","controlId":"navigationview","controlName":"NavigationView","headerText":"Data binding","xaml":"\u003CNavigationView x:Name=\u0022nvSample\u0022 \n MenuItemTemplateSelector=\u0022{StaticResource selector}\u0022 \n MenuItemsSource=\u0022{x:Bind Categories, Mode=OneWay}\u0022 /\u003E\n \n\u003Clocal:MenuItemTemplateSelector x:Key=\u0022selector\u0022\u003E \n \u003Clocal:MenuItemTemplateSelector.ItemTemplate\u003E \n \u003CDataTemplate x:DataType=\u0022local:Category\u0022 \u003E \n \u003CNavigationViewItem Content=\u0022{x:Bind Name}\u0022 ToolTipService.ToolTip=\u0022{x:Bind Tooltip}\u0022\u003E \n \u003CNavigationViewItem.Icon\u003E \n \u003CSymbolIcon Symbol=\u0022{x:Bind Glyph}\u0022 /\u003E \n \u003C/NavigationViewItem.Icon\u003E \n \u003C/NavigationViewItem\u003E\n \u003C/DataTemplate\u003E \n \u003C/local:MenuItemTemplateSelector.ItemTemplate \u003E \n\u003C/local:MenuItemTemplateSelector\u003E","csharp":"//C# code behind\nCategories = new ObservableCollection\u003CCategoryBase\u003E(); \nCategories.Add(new Category { Name = \u0022Category 1\u0022, Glyph = Symbol.Home, Tooltip = \u0022This is category 1\u0022 }); \nCategories.Add(new Category { Name = \u0022Category 2\u0022, Glyph = Symbol.Keyboard, Tooltip = \u0022This is category 2\u0022 }); \nCategories.Add(new Category { Name = \u0022Category 3\u0022, Glyph = Symbol.Library, Tooltip = \u0022This is category 3\u0022 }); \nCategories.Add(new Category { Name = \u0022Category 4\u0022, Glyph = Symbol.Mail, Tooltip = \u0022This is category 4\u0022 }); \n\npublic class CategoryBase { } \n\npublic class Category : CategoryBase\n{\n public string Name { get; set; } = string.Empty;\n public string Tooltip { get; set; } = string.Empty;\n public Symbol Glyph { get; set; }\n}\n\npublic class Separator : CategoryBase { }\n\npublic class Header : CategoryBase\n{\n public string Name { get; set; }\n}\n\n[ContentProperty(Name = \u0022ItemTemplate\u0022)]\nclass MenuItemTemplateSelector : DataTemplateSelector\n{\n public DataTemplate? ItemTemplate { get; set; }\n\n protected override DataTemplate? SelectTemplateCore(object item)\n {\n return item is Separator ? SeparatorTemplate : item is Header ? HeaderTemplate : ItemTemplate;\n }\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Common vertical layout for top-level areas of your app via a collapsible navigation menu.","relatedControls":["SplitView","Pivot"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"NavigationView - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Controls.NavigationView"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/navigationview"}]},{"id":"navigationview-6","controlId":"navigationview","controlName":"NavigationView","headerText":"NavigationView with Footer Menu Items","xaml":"\u003CNavigationView x:Name=\u0022nvSample9\u0022 \n Header=\u0022This is Header Text\u0022 \n PaneDisplayMode=\u0022...\u0022 \n SelectionChanged=\u0022NavigationView_SelectionChanged9\u0022\n IsSettingsVisible=\u0022False\u0022\u003E\n \u003CNavigationView.MenuItems\u003E\n \u003CNavigationViewItem Content=\u0022Browse\u0022 Tag=\u0022YourPage\u0022 Icon=\u0022Library\u0022 /\u003E\n \u003CNavigationViewItem Content=\u0022Track an Order\u0022 Tag=\u0022YourPage\u0022 Icon=\u0022Map\u0022 /\u003E\n \u003CNavigationViewItem Content=\u0022Order History\u0022 Tag=\u0022YourPage\u0022 Icon=\u0022Tag\u0022 /\u003E\n \u003C/NavigationView.MenuItems\u003E\n \u003CNavigationView.FooterMenuItems\u003E\n \u003CNavigationViewItem Content=\u0022Account\u0022 Tag=\u0022YourPage\u0022 Icon=\u0022Contact\u0022 /\u003E\n \u003CNavigationViewItem Content=\u0022Your Cart\u0022 Tag=\u0022YourPage\u0022 Icon=\u0022Shop\u0022 /\u003E\n \u003CNavigationViewItem Content=\u0022Help\u0022 Tag=\u0022YourPage\u0022 Icon=\u0022Help\u0022 /\u003E\n \u003C/NavigationView.FooterMenuItems\u003E\n \u003CFrame x:Name=\u0022contentFrame9\u0022 /\u003E\n\u003C/NavigationView\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Common vertical layout for top-level areas of your app via a collapsible navigation menu.","relatedControls":["SplitView","Pivot"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"NavigationView - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Controls.NavigationView"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/navigationview"}]},{"id":"navigationview-7","controlId":"navigationview","controlName":"NavigationView","headerText":"Hierarchical NavigationView","xaml":"\u003CNavigationView x:Name=\u0022nvSample8\u0022 Grid.Row=\u00221\u0022 Height=\u0022460\u0022\n PaneDisplayMode=\u0022...\u0022 \n IsTabStop=\u0022False\u0022 \n SelectionChanged=\u0022NavigationView_SelectionChanged8\u0022\u003E\n \u003CNavigationView.MenuItems\u003E\n \u003CNavigationViewItem Content=\u0022Home\u0022 Icon=\u0022Home\u0022 ToolTipService.ToolTip=\u0022Home\u0022 Tag=\u0022YourPage\u0022/\u003E\n \u003CNavigationViewItem Content=\u0022Account\u0022 Icon=\u0022Contact\u0022 ToolTipService.ToolTip=\u0022Account\u0022 Tag=\u0022YourPage\u0022\u003E\n \u003CNavigationViewItem.MenuItems\u003E\n \u003CNavigationViewItem Content=\u0022Mail\u0022 Icon=\u0022Mail\u0022 ToolTipService.ToolTip=\u0022Mail\u0022 Tag=\u0022YourPage\u0022/\u003E\n \u003CNavigationViewItem Content=\u0022Calendar\u0022 Icon=\u0022Calendar\u0022 ToolTipService.ToolTip=\u0022Calendar\u0022 Tag=\u0022YourPage\u0022/\u003E\n \u003C/NavigationViewItem.MenuItems\u003E\n \u003C/NavigationViewItem\u003E\n \u003CNavigationViewItem Content=\u0022Document options\u0022 Icon=\u0022Page2\u0022 ToolTipService.ToolTip=\u0022Document options\u0022 SelectsOnInvoked=\u0022False\u0022\u003E\n \u003CNavigationViewItem.MenuItems\u003E\n \u003CNavigationViewItem Content=\u0022Create new\u0022 Icon=\u0022NewFolder\u0022 ToolTipService.ToolTip=\u0022Create new\u0022 Tag=\u0022YourPage\u0022/\u003E\n \u003CNavigationViewItem Content=\u0022Upload file\u0022 Icon=\u0022OpenLocal\u0022 ToolTipService.ToolTip=\u0022Upload file\u0022 Tag=\u0022YourPage\u0022/\u003E\n \u003C/NavigationViewItem.MenuItems\u003E\n \u003C/NavigationViewItem\u003E\n \u003C/NavigationView.MenuItems\u003E\n \u003CFrame x:Name=\u0022contentFrame8\u0022 /\u003E\n\u003C/NavigationView\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Common vertical layout for top-level areas of your app via a collapsible navigation menu.","relatedControls":["SplitView","Pivot"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"NavigationView - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Controls.NavigationView"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/navigationview"}]},{"id":"navigationview-8","controlId":"navigationview","controlName":"NavigationView","headerText":"API in action","xaml":"\u003CNavigationView x:Name=\u0022nvSample\u0022\n IsSettingsVisible=\u0022...\u0022\n IsBackButtonVisible=\u0022...\u0022\n IsBackEnabled=\u0022...\u0022\n SelectionChanged=\u0022NavigationView_SelectionChanged\u0022\n Header=\u0022...\u0022\n AlwaysShowHeader=\u0022...\u0022\n PaneTitle=\u0022...\u0022\n PaneDisplayMode=\u0022...\u0022 \n ExpandedModeThresholdWidth=\u0022500\u0022\n SelectionFollowsFocus=\u0022...\u0022\n IsTabStop=\u0022False\u0022\u003E\n \n \u003CNavigationView.MenuItems\u003E\n \u003CNavigationViewItem Content=\u0022Menu Item1\u0022 Tag=\u0022YourPage\u0022 x:Name=\u0022YourPageItem\u0022\u003E\n \u003CNavigationViewItem.Icon\u003E\n \u003CSymbolIcon Symbol=\u0022Play\u0022 /\u003E\n \u003C/NavigationViewItem.Icon\u003E\n \u003C/NavigationViewItem\u003E\n \u003CNavigationViewItemHeader Content=\u0022Actions\u0022/\u003E\n \u003CNavigationViewItem Content=\u0022Menu Item2\u0022 Tag=\u0022YourPage\u0022 x:Name=\u0022YourPageItem\u0022 SelectsOnInvoked=\u0022...\u0022\u003E\n \u003CNavigationViewItem.Icon\u003E\n \u003CSymbolIcon Symbol=\u0022Save\u0022 /\u003E\n \u003C/NavigationViewItem.Icon\u003E\n \u003C/NavigationViewItem\u003E\n \u003CNavigationViewItem Content=\u0022Menu Item3\u0022 Tag=\u0022YourPage\u0022 x:Name=\u0022YourPageItem\u0022\u003E\n \u003CNavigationViewItem.Icon\u003E\n \u003CSymbolIcon Symbol=\u0022Refresh\u0022 /\u003E\n \u003C/NavigationViewItem.Icon\u003E\n \u003C/NavigationViewItem\u003E\n \u003C/NavigationView.MenuItems\u003E\n \n \u003CNavigationView.PaneCustomContent\u003E\n \u003CHyperlinkButton x:Name=\u0022PaneHyperlink\u0022 Content=\u0022More info\u0022 Margin=\u002212,0\u0022 Visibility=\u0022...\u0022 /\u003E\n \u003C/NavigationView.PaneCustomContent\u003E\n ...\n \u003CNavigationView.PaneFooter\u003E\n \u003CStackPanel x:Name=\u0022FooterStackPanel\u0022 Orientation=\u0022Vertical\u0022 Visibility=\u0022...\u0022\u003E\n \u003CNavigationViewItem Icon=\u0022Download\u0022 AutomationProperties.Name=\u0022download\u0022 /\u003E\n \u003CNavigationViewItem Icon=\u0022Favorite\u0022 AutomationProperties.Name=\u0022favorite\u0022 /\u003E\n \u003C/StackPanel\u003E\n \u003C/NavigationView.PaneFooter\u003E\n\n \u003CFrame x:Name=\u0022contentFrame\u0022 /\u003E\n\u003C/NavigationView\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Common vertical layout for top-level areas of your app via a collapsible navigation menu.","relatedControls":["SplitView","Pivot"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"NavigationView - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Controls.NavigationView"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/navigationview"}]},{"id":"pivot-1","controlId":"pivot","controlName":"Pivot","headerText":"A basic pivot.","xaml":"\u003CPivot Title=\u0022EMAIL\u0022\u003E\n \u003CPivotItem Header=\u0022All\u0022\u003E\n \u003CTextBlock Text=\u0022all emails go here.\u0022 /\u003E\n \u003C/PivotItem\u003E\n \u003CPivotItem Header=\u0022Unread\u0022\u003E\n \u003CTextBlock Text=\u0022unread emails go here.\u0022 /\u003E\n \u003C/PivotItem\u003E\n \u003CPivotItem Header=\u0022Flagged\u0022\u003E\n \u003CTextBlock Text=\u0022flagged emails go here.\u0022 /\u003E\n \u003C/PivotItem\u003E\n \u003CPivotItem Header=\u0022Urgent\u0022\u003E\n \u003CTextBlock Text=\u0022urgent emails go here.\u0022 /\u003E\n \u003C/PivotItem\u003E\n\u003C/Pivot\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Presents information from different sources in a tabbed view.","relatedControls":["SelectorBar"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"Pivot - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.pivot"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/pivot"}]},{"id":"selectorbar-1","controlId":"selectorbar","controlName":"SelectorBar","headerText":"A Basic SelectorBar","xaml":"\u003CSelectorBar x:Name=\u0022SelectorBar1\u0022\u003E\n \u003CSelectorBarItem x:Name=\u0022SelectorBarItemRecent\u0022 Text=\u0022Recent\u0022 Icon=\u0022Clock\u0022 /\u003E\n \u003CSelectorBarItem x:Name=\u0022SelectorBarItemShared\u0022 Text=\u0022Shared\u0022 Icon=\u0022Share\u0022 /\u003E\n \u003CSelectorBarItem x:Name=\u0022SelectorBarItemFavorites\u0022 Text=\u0022Favorites\u0022 Icon=\u0022Favorite\u0022 /\u003E\n\u003C/SelectorBar\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Presents information from a small set of different sources. The user can pick one of them.","relatedControls":["NavigationView","PipsPager","Pivot"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"SelectorBar - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.selectorbar"},{"title":"SelectorBarItem - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.selectorbaritem"}]},{"id":"selectorbar-2","controlId":"selectorbar","controlName":"SelectorBar","headerText":"SelectorBar with Frame Slide Transitions","xaml":"\u003CSelectorBar x:Name=\u0022SelectorBar2\u0022 SelectionChanged=\u0022SelectorBar2_SelectionChanged\u0022\u003E\n \u003CSelectorBarItem x:Name=\u0022SelectorBarItemPage1\u0022 Text=\u0022Page1\u0022 IsSelected=\u0022True\u0022 /\u003E\n \u003CSelectorBarItem x:Name=\u0022SelectorBarItemPage2\u0022 Text=\u0022Page2\u0022 /\u003E\n \u003CSelectorBarItem x:Name=\u0022SelectorBarItemPage3\u0022 Text=\u0022Page3\u0022 /\u003E\n \u003CSelectorBarItem x:Name=\u0022SelectorBarItemPage4\u0022 Text=\u0022Page4\u0022 /\u003E\n \u003CSelectorBarItem x:Name=\u0022SelectorBarItemPage5\u0022 Text=\u0022Page5\u0022 /\u003E\n\u003C/SelectorBar\u003E\n\n\u003CFrame x:Name=\u0022ContentFrame\u0022 IsNavigationStackEnabled=\u0022False\u0022 /\u003E","csharp":"private void SelectorBar2_SelectionChanged(SelectorBar sender, SelectorBarSelectionChangedEventArgs args)\n {\n SelectorBarItem selectedItem = sender.SelectedItem;\n int currentSelectedIndex = sender.Items.IndexOf(selectedItem);\n System.Type pageType;\n\n switch (currentSelectedIndex)\n {\n case 0:\n pageType = typeof(YourPage);\n break;\n case 1:\n pageType = typeof(YourPage);\n break;\n case 2:\n pageType = typeof(YourPage);\n break;\n case 3:\n pageType = typeof(YourPage);\n break;\n default:\n pageType = typeof(YourPage);\n break;\n }\n\n var slideNavigationTransitionEffect = currentSelectedIndex - previousSelectedIndex \u003E 0 ? SlideNavigationTransitionEffect.FromRight : SlideNavigationTransitionEffect.FromLeft;\n\n ContentFrame.Navigate(pageType, null, new SlideNavigationTransitionInfo() { Effect = slideNavigationTransitionEffect });\n\n previousSelectedIndex = currentSelectedIndex;\n }","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Presents information from a small set of different sources. The user can pick one of them.","relatedControls":["NavigationView","PipsPager","Pivot"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"SelectorBar - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.selectorbar"},{"title":"SelectorBarItem - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.selectorbaritem"}]},{"id":"selectorbar-3","controlId":"selectorbar","controlName":"SelectorBar","headerText":"SelectorBar Displaying Different Collections Using ItemsView","xaml":"\u003CSelectorBar x:Name=\u0022SelectorBar3\u0022 SelectionChanged=\u0022SelectorBar3_SelectionChanged\u0022 \u003E\n \u003CSelectorBarItem x:Name=\u0022SelectorBarItemPink\u0022 Text=\u0022Pink\u0022 IsSelected=\u0022True\u0022 /\u003E\n \u003CSelectorBarItem x:Name=\u0022SelectorBarItemPlum\u0022 Text=\u0022Plum\u0022 /\u003E\n \u003CSelectorBarItem x:Name=\u0022SelectorBarItemPowderBlue\u0022 Text=\u0022PowderBlue\u0022 /\u003E\n\u003C/SelectorBar\u003E\n\n\u003CItemsView x:Name=\u0022ItemsView3\u0022 ItemTemplate=\u0022{StaticResource ColorsTemplate}\u0022 /\u003E\n \u003CItemsView.Layout\u003E\n \u003CUniformGridLayout /\u003E\n \u003C/ItemsView.Layout\u003E\n\u003C/ItemsView/\u003E","csharp":"private void SelectorBar3_SelectionChanged(SelectorBar sender, SelectorBarSelectionChangedEventArgs args)\n{\n if (sender.SelectedItem == SelectorBarItemPink)\n {\n ItemsView3.ItemsSource = PinkColorCollection;\n }\n else if (sender.SelectedItem == SelectorBarItemPlum)\n {\n ItemsView3.ItemsSource = PlumColorCollection;\n }\n else\n {\n ItemsView3.ItemsSource = PowderBlueColorCollection;\n }\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Presents information from a small set of different sources. The user can pick one of them.","relatedControls":["NavigationView","PipsPager","Pivot"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"SelectorBar - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.selectorbar"},{"title":"SelectorBarItem - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.selectorbaritem"}]},{"id":"tabview-1","controlId":"tabview","controlName":"TabView","headerText":"A TabView with support for adding, closing, and rearranging tabs","xaml":"\u003CTabView AddTabButtonClick=\u0022TabView_AddButtonClick\u0022 TabCloseRequested=\u0022TabView_TabCloseRequested\u0022 Loaded=\u0022TabView_Loaded\u0022 /\u003E","csharp":"private void TabView_AddButtonClick(TabView sender, object args)\n{\n sender.TabItems.Add(CreateNewTab(sender.TabItems.Count));\n}\n\nprivate void TabView_TabCloseRequested(TabView sender, TabViewTabCloseRequestedEventArgs args)\n{\n sender.TabItems.Remove(args.Tab);\n}\n\nprivate TabViewItem CreateNewTab(int index)\n{\n TabViewItem newItem = new TabViewItem();\n newItem.Header = $\u0022Document {index}\u0022;\n newItem.IconSource = new SymbolIconSource() { Symbol = Symbol.Document };\n newItem.IsClosable = true;\n\n // Content can be any UIElement \u2014 TextBox, Grid, UserControl, etc.\n var textBox = new TextBox\n {\n AcceptsReturn = true,\n TextWrapping = TextWrapping.Wrap,\n HorizontalAlignment = HorizontalAlignment.Stretch,\n VerticalAlignment = VerticalAlignment.Stretch,\n BorderThickness = new Thickness(0),\n };\n newItem.Content = textBox;\n\n return newItem;\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A control that displays a collection of tabs that can be used to display several documents.","relatedControls":["Pivot","NavigationView","ListView"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"TabView - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.tabview"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/tab-view"},{"title":"Show multiple views for an app","uri":"https://learn.microsoft.com/windows/apps/design/layout/show-multiple-views"}]},{"id":"tabview-2","controlId":"tabview","controlName":"TabView","headerText":"A TabView with TabViewItems defined in markup","xaml":"\u003CTabView AddTabButtonClick=\u0022TabView_AddButtonClick\u0022 TabCloseRequested=\u0022TabView_TabCloseRequested\u0022\u003E\n \u003CTabView.TabItems\u003E\n \u003CTabViewItem Header=\u0022Document 0\u0022\u003E\n \u003CTabViewItem.IconSource\u003E\n \u003CSymbolIconSource Symbol=\u0022Placeholder\u0022 /\u003E\n \u003C/TabViewItem.IconSource\u003E\n \u003Csamplepages:YourPage /\u003E\n \u003C/TabViewItem\u003E\n \u003CTabViewItem Header=\u0022Document 1\u0022\u003E\n \u003CTabViewItem.IconSource\u003E\n \u003CSymbolIconSource Symbol=\u0022Placeholder\u0022 /\u003E\n \u003C/TabViewItem.IconSource\u003E\n \u003Csamplepages:YourPage /\u003E\n \u003C/TabViewItem\u003E\n \u003CTabViewItem Header=\u0022Document 2\u0022\u003E\n \u003CTabViewItem.IconSource\u003E\n \u003CSymbolIconSource Symbol=\u0022Placeholder\u0022 /\u003E\n \u003C/TabViewItem.IconSource\u003E\n \u003Csamplepages:YourPage /\u003E\n \u003C/TabViewItem\u003E\n \u003C/TabView.TabItems\u003E\n\u003C/TabView\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A control that displays a collection of tabs that can be used to display several documents.","relatedControls":["Pivot","NavigationView","ListView"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"TabView - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.tabview"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/tab-view"},{"title":"Show multiple views for an app","uri":"https://learn.microsoft.com/windows/apps/design/layout/show-multiple-views"}]},{"id":"tabview-3","controlId":"tabview","controlName":"TabView","headerText":"A TabView bound to a collection of MyData objects","xaml":"\u003CTabView TabItemsSource=\u0022{x:Bind myDatas, Mode=OneWay}\u0022 AddTabButtonClick=\u0022TabViewItemsSourceSample_AddTabButtonClick\u0022 TabCloseRequested=\u0022TabViewItemsSourceSample_TabCloseRequested\u0022 /\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A control that displays a collection of tabs that can be used to display several documents.","relatedControls":["Pivot","NavigationView","ListView"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"TabView - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.tabview"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/tab-view"},{"title":"Show multiple views for an app","uri":"https://learn.microsoft.com/windows/apps/design/layout/show-multiple-views"}]},{"id":"tabview-4","controlId":"tabview","controlName":"TabView","headerText":"A TabView with keyboarding support","xaml":"\u003CTabView AddTabButtonClick=\u0022TabView_AddButtonClick\u0022 TabCloseRequested=\u0022TabView_TabCloseRequested\u0022 Loaded=\u0022TabView_Loaded\u0022\u003E\n \u003CTabView.KeyboardAccelerators\u003E\n \u003CKeyboardAccelerator Key=\u0022T\u0022 Modifiers=\u0022Control\u0022 Invoked=\u0022NewTabKeyboardAccelerator_Invoked\u0022 /\u003E\n \u003CKeyboardAccelerator Key=\u0022W\u0022 Modifiers=\u0022Control\u0022 Invoked=\u0022CloseSelectedTabKeyboardAccelerator_Invoked\u0022 /\u003E\n \u003CKeyboardAccelerator Key=\u0022Number1\u0022 Modifiers=\u0022Control\u0022 Invoked=\u0022NavigateToNumberedTabKeyboardAccelerator_Invoked\u0022 /\u003E\n \u003CKeyboardAccelerator Key=\u0022Number2\u0022 Modifiers=\u0022Control\u0022 Invoked=\u0022NavigateToNumberedTabKeyboardAccelerator_Invoked\u0022 /\u003E\n \u003CKeyboardAccelerator Key=\u0022Number3\u0022 Modifiers=\u0022Control\u0022 Invoked=\u0022NavigateToNumberedTabKeyboardAccelerator_Invoked\u0022 /\u003E\n \u003CKeyboardAccelerator Key=\u0022Number4\u0022 Modifiers=\u0022Control\u0022 Invoked=\u0022NavigateToNumberedTabKeyboardAccelerator_Invoked\u0022 /\u003E\n \u003CKeyboardAccelerator Key=\u0022Number5\u0022 Modifiers=\u0022Control\u0022 Invoked=\u0022NavigateToNumberedTabKeyboardAccelerator_Invoked\u0022 /\u003E\n \u003CKeyboardAccelerator Key=\u0022Number6\u0022 Modifiers=\u0022Control\u0022 Invoked=\u0022NavigateToNumberedTabKeyboardAccelerator_Invoked\u0022 /\u003E\n \u003CKeyboardAccelerator Key=\u0022Number7\u0022 Modifiers=\u0022Control\u0022 Invoked=\u0022NavigateToNumberedTabKeyboardAccelerator_Invoked\u0022 /\u003E\n \u003CKeyboardAccelerator Key=\u0022Number8\u0022 Modifiers=\u0022Control\u0022 Invoked=\u0022NavigateToNumberedTabKeyboardAccelerator_Invoked\u0022 /\u003E\n \u003CKeyboardAccelerator Key=\u0022Number9\u0022 Modifiers=\u0022Control\u0022 Invoked=\u0022NavigateToNumberedTabKeyboardAccelerator_Invoked\u0022 /\u003E\n \u003C/TabView.KeyboardAccelerators\u003E\n\u003C/TabView\u003E","csharp":"private void NewTabKeyboardAccelerator_Invoked(KeyboardAccelerator sender, KeyboardAcceleratorInvokedEventArgs args)\n{\n if (ars.Element is not TabView senderTabView)\n {\n return;\n }\n\n senderTabView.TabItems.Add(CreateNewTab(senderTabView.TabItems.Count));\n\n args.Handled = true;\n}\n\nprivate void CloseSelectedTabKeyboardAccelerator_Invoked(KeyboardAccelerator sender, KeyboardAcceleratorInvokedEventArgs args)\n{\n if (args.Element is not TabView invokedTabView)\n {\n return;\n }\n\n // Only close the selected tab if it is closeable\n if ((invokedTabView.SelectedItem as TabViewItem)?.IsClosable is true)\n {\n invokedTabView.TabItems.Remove(invokedTabView.SelectedItem);\n }\n\n args.Handled = true;\n}\n\nprivate void NavigateToNumberedTabKeyboardAccelerator_Invoked(KeyboardAccelerator sender, KeyboardAcceleratorInvokedEventArgs args)\n{\n if (args.Element is not TabView invokedTabView)\n {\n return;\n }\n\n int tabToSelect = 0;\n\n switch (sender.Key)\n {\n case Windows.System.VirtualKey.Number1:\n tabToSelect = 0;\n break;\n case Windows.System.VirtualKey.Number2:\n tabToSelect = 1;\n break;\n case Windows.System.VirtualKey.Number3:\n tabToSelect = 2;\n break;\n case Windows.System.VirtualKey.Number4:\n tabToSelect = 3;\n break;\n case Windows.System.VirtualKey.Number5:\n tabToSelect = 4;\n break;\n case Windows.System.VirtualKey.Number6:\n tabToSelect = 5;\n break;\n case Windows.System.VirtualKey.Number7:\n tabToSelect = 6;\n break;\n case Windows.System.VirtualKey.Number8:\n tabToSelect = 7;\n break;\n case Windows.System.VirtualKey.Number9:\n // Select the last tab\n tabToSelect = invokedTabView.TabItems.Count - 1;\n break;\n }\n\n // Only select the tab if it is in the list\n if (tabToSelect \u003C invokedTabView.TabItems.Count)\n {\n invokedTabView.SelectedIndex = tabToSelect;\n }\n\n args.Handled = true;\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A control that displays a collection of tabs that can be used to display several documents.","relatedControls":["Pivot","NavigationView","ListView"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"TabView - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.tabview"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/tab-view"},{"title":"Show multiple views for an app","uri":"https://learn.microsoft.com/windows/apps/design/layout/show-multiple-views"}]},{"id":"tabview-5","controlId":"tabview","controlName":"TabView","headerText":"You can put custom content in TabStripHeader and TabStripFooter","xaml":"\u003CTabView\u003E\n \u003CTabView.TabStripHeader\u003E\n \u003CTextBlock Text=\u0022TabStripHeader Content\u0022 VerticalAlignment=\u0022Center\u0022 Margin=\u00228,6\u0022 Style=\u0022{ThemeResource BaseTextBlockStyle}\u0022 /\u003E\n \u003C/TabView.TabStripHeader\u003E\n \u003CTabView.TabStripFooter\u003E\n \u003CTextBlock Text=\u0022TabStripFooter Content\u0022 VerticalAlignment=\u0022Center\u0022 HorizontalAlignment=\u0022Right\u0022 Margin=\u00226\u0022 Style=\u0022{ThemeResource BaseTextBlockStyle}\u0022 /\u003E\n \u003C/TabView.TabStripFooter\u003E\n\u003C/TabView\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A control that displays a collection of tabs that can be used to display several documents.","relatedControls":["Pivot","NavigationView","ListView"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"TabView - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.tabview"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/tab-view"},{"title":"Show multiple views for an app","uri":"https://learn.microsoft.com/windows/apps/design/layout/show-multiple-views"}]},{"id":"tabview-6","controlId":"tabview","controlName":"TabView","headerText":"Tab widths can either be equally sized, sized to the content of the tab, or sized to only show the icon when unselected","xaml":"\u003CTabView TabWidthMode=\u0022...\u0022 /\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A control that displays a collection of tabs that can be used to display several documents.","relatedControls":["Pivot","NavigationView","ListView"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"TabView - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.tabview"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/tab-view"},{"title":"Show multiple views for an app","uri":"https://learn.microsoft.com/windows/apps/design/layout/show-multiple-views"}]},{"id":"tabview-7","controlId":"tabview","controlName":"TabView","headerText":"The close button can be persistent or only visible on hover","xaml":"\u003CTabView CloseButtonOverlayMode=\u0022...\u0022 /\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A control that displays a collection of tabs that can be used to display several documents.","relatedControls":["Pivot","NavigationView","ListView"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"TabView - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.tabview"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/tab-view"},{"title":"Show multiple views for an app","uri":"https://learn.microsoft.com/windows/apps/design/layout/show-multiple-views"}]},{"id":"tabview-8","controlId":"tabview","controlName":"TabView","headerText":"TabView with color tab icons","xaml":"\u003CTabView\u003E\n \u003CTabView.TabItems\u003E\n \u003CTabViewItem Header=\u0022CMD Prompt\u0022\u003E\n \u003CTabViewItem.IconSource\u003E\n \u003CBitmapIconSource UriSource=\u0022/Assets/SampleMedia/cmd.png\u0022 ShowAsMonochrome=\u0022False\u0022 /\u003E\n \u003C/TabViewItem.IconSource\u003E\n \u003C/TabViewItem\u003E\n \u003CTabViewItem Header=\u0022PowerShell\u0022\u003E\n \u003CTabViewItem.IconSource\u003E\n \u003CBitmapIconSource UriSource=\u0022/Assets/SampleMedia/powershell.png\u0022 ShowAsMonochrome=\u0022False\u0022 /\u003E\n \u003C/TabViewItem.IconSource\u003E\n \u003C/TabViewItem\u003E\n \u003CTabViewItem Header=\u0022Windows Subsystem for Linux\u0022\u003E\n \u003CTabViewItem.IconSource\u003E\n \u003CBitmapIconSource UriSource=\u0022/Assets/SampleMedia/linux.png\u0022 ShowAsMonochrome=\u0022False\u0022 /\u003E\n \u003C/TabViewItem.IconSource\u003E\n \u003C/TabViewItem\u003E\n \u003C/TabView.TabItems\u003E\n\u003C/TabView\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A control that displays a collection of tabs that can be used to display several documents.","relatedControls":["Pivot","NavigationView","ListView"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"TabView - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.tabview"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/tab-view"},{"title":"Show multiple views for an app","uri":"https://learn.microsoft.com/windows/apps/design/layout/show-multiple-views"}]},{"id":"tabview-9","controlId":"tabview","controlName":"TabView","headerText":"A TabView with accent colored TabStrip background","xaml":"\u003CTabView\u003E\n \u003CTabView.Resources\u003E\n \u003CResourceDictionary\u003E\n \u003CResourceDictionary.ThemeDictionaries\u003E\n \u003CResourceDictionary x:Key=\u0022Light\u0022\u003E\n \u003CSolidColorBrush x:Key=\u0022TabViewBackground\u0022 Color=\u0022{ThemeResource SystemAccentColorLight2}\u0022/\u003E\n \u003C/ResourceDictionary\u003E\n \u003CResourceDictionary x:Key=\u0022Dark\u0022\u003E\n \u003CSolidColorBrush x:Key=\u0022TabViewBackground\u0022 Color=\u0022{ThemeResource SystemAccentColorDark2}\u0022/\u003E\n \u003C/ResourceDictionary\u003E\n \u003C/ResourceDictionary.ThemeDictionaries\u003E\n \u003C/ResourceDictionary\u003E\n \u003C/TabView.Resources\u003E\n\u003C/TabView\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A control that displays a collection of tabs that can be used to display several documents.","relatedControls":["Pivot","NavigationView","ListView"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"TabView - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.tabview"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/tab-view"},{"title":"Show multiple views for an app","uri":"https://learn.microsoft.com/windows/apps/design/layout/show-multiple-views"}]},{"id":"tabview-10","controlId":"tabview","controlName":"TabView","headerText":"Complete TabView windowing sample","xaml":"Check out the TabViewWindowingSamplePage.xaml and *.cs files to see the complete code.","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A control that displays a collection of tabs that can be used to display several documents.","relatedControls":["Pivot","NavigationView","ListView"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"TabView - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.tabview"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/tab-view"},{"title":"Show multiple views for an app","uri":"https://learn.microsoft.com/windows/apps/design/layout/show-multiple-views"}]},{"id":"animatedvisualplayer-1","controlId":"animatedvisualplayer","controlName":"AnimatedVisualPlayer","headerText":"Playback of a Lottie animation.","xaml":"\u003CAnimatedVisualPlayer x:Name=\u0022Player\u0022 AutoPlay=\u0022False\u0022\u003E\n \u003Canimatedvisuals:LottieLogo1/\u003E\n\u003C/AnimatedVisualPlayer\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"An element to render and control playback of motion graphics.","relatedControls":["AnimatedIcon"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"AnimatedVisualPlayer - API","uri":"https://learn.microsoft.com/windows/winui/api/microsoft.ui.xaml.controls.animatedvisualplayer"},{"title":"Full Samples","uri":"ms-windows-store://pdp/?productid=9N3J5TG8FF7F"},{"title":"Tutorials","uri":"https://learn.microsoft.com/windows/communitytoolkit/animations/lottie#tutorials"},{"title":"Lottie Overview","uri":"https://learn.microsoft.com/windows/communitytoolkit/animations/lottie"},{"title":"Lottie Windows - GitHub","uri":"https://github.com/CommunityToolkit/Lottie-Windows"}]},{"id":"captureelementpreview-1","controlId":"captureelementpreview","controlName":"Capture Element / Camera Preview","headerText":"A MediaCapture preview displayed via a MediaPlayerElement.","xaml":"\u003CGrid RowDefinitions=\u0022Auto,*\u0022 ColumnDefinitions=\u0022*,100\u0022 MinWidth=\u0022400\u0022 MinHeight=\u0022300\u0022 RowSpacing=\u002210\u0022 ColumnSpacing=\u00224\u0022\u003E\n \u003CTextBlock x:Name=\u0022frameSourceName\u0022 Grid.Row=\u00220\u0022 Grid.Column=\u00220\u0022 VerticalAlignment=\u0022Center\u0022/\u003E\n \u003CMediaPlayerElement x:Name=\u0022captureElement\u0022 Grid.Row=\u00221\u0022 Grid.Column=\u00220\u0022 Stretch=\u0022Uniform\u0022 AutoPlay=\u0022True\u0022 /\u003E\n \u003CTextBlock x:Name=\u0022capturedText\u0022 Visibility=\u0022Collapsed\u0022 Grid.Row=\u00220\u0022 Grid.Column=\u00221\u0022 VerticalAlignment=\u0022Center\u0022 Text=\u0022Captured:\u0022 /\u003E\n \u003CGrid x:Name=\u0022captureContainer\u0022 Grid.Row=\u00221\u0022 Grid.Column=\u00221\u0022\u003E\n \u003CScrollViewer VerticalScrollMode=\u0022Enabled\u0022\u003E\n \u003CStackPanel x:Name=\u0022snapshots\u0022 Spacing=\u00222\u0022/\u003E\n \u003C/ScrollViewer\u003E\n \u003C/Grid\u003E\n\u003C/Grid\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A sample for doing a camera preview.","relatedControls":["MediaPlayerElement","Image"],"apiNamespace":null,"docs":[{"title":"MediaCapture - API","uri":"https://learn.microsoft.com/uwp/api/windows.media.capture.mediacapture"}]},{"id":"image-1","controlId":"image","controlName":"Image","headerText":"A basic image from a local file.","xaml":"\u003CImage Source=\u0022/Assets/SampleMedia/treetops.jpg\u0022 Height=\u0022100\u0022 /\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A control to display image content.","relatedControls":["MediaPlayerElement","PersonPicture"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"Image - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.image"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/images-imagebrushes"}]},{"id":"image-2","controlId":"image","controlName":"Image","headerText":"An image decoded to the rendering size","xaml":"\u003CImage Height=\u0022100\u0022\u003E\n \u003CImage.Source\u003E\n \u003CBitmapImage UriSource=\u0022/Assets/SampleMedia/treetops.jpg\u0022\n DecodePixelHeight=\u0022100\u0022 /\u003E\n \u003C/Image.Source\u003E\n\u003C/Image\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A control to display image content.","relatedControls":["MediaPlayerElement","PersonPicture"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"Image - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.image"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/images-imagebrushes"}]},{"id":"image-3","controlId":"image","controlName":"Image","headerText":"Image stretching.","xaml":"\u003CImage Stretch=\u0022...\u0022 Height=\u0022100\u0022 Width=\u0022100\u0022 Source=\u0022/Assets/SampleMedia/valley.jpg\u0022 /\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A control to display image content.","relatedControls":["MediaPlayerElement","PersonPicture"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"Image - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.image"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/images-imagebrushes"}]},{"id":"image-4","controlId":"image","controlName":"Image","headerText":"Nine grid images.","xaml":"\u003CImage Source=\u0022/Assets/SampleMedia/ninegrid.gif\u0022 Height=\u002282\u0022 /\u003E\n\u003CImage Source=\u0022/Assets/SampleMedia/ninegrid.gif\u0022 NineGrid=\u00223,3,3,3\u0022 Height=\u0022164\u0022 /\u003E\n\u003CImage Source=\u0022/Assets/SampleMedia/ninegrid.gif\u0022 NineGrid=\u002230,20,30,20\u0022 Height=\u0022164\u0022 /\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A control to display image content.","relatedControls":["MediaPlayerElement","PersonPicture"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"Image - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.image"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/images-imagebrushes"}]},{"id":"image-5","controlId":"image","controlName":"Image","headerText":"An SVG image.","xaml":"\u003CImage Source=\u0022/Assets/SampleMedia/MirrorPCConsent.svg\u0022 Height=\u0022100\u0022 /\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A control to display image content.","relatedControls":["MediaPlayerElement","PersonPicture"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"Image - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.image"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/images-imagebrushes"}]},{"id":"image-6","controlId":"image","controlName":"Image","headerText":"Animated GIF playback.","xaml":"\u003CStackPanel Spacing=\u002212\u0022\u003E\n \u003CTextBlock Text=\u0022An Image element automatically plays an animated GIF source.\u0022 TextWrapping=\u0022Wrap\u0022/\u003E\n \u003CImage Height=\u002240\u0022 HorizontalAlignment=\u0022Left\u0022 Source=\u0022/Assets/SampleMedia/animated.gif\u0022/\u003E\n\n \u003CTextBlock Text=\u0022Set AutoPlay to False to prevent the GIF from playing automatically.\u0022 TextWrapping=\u0022Wrap\u0022/\u003E\n \u003CImage Height=\u002240\u0022 HorizontalAlignment=\u0022Left\u0022\u003E\n \u003CImage.Source\u003E\n \u003CBitmapImage AutoPlay=\u0022False\u0022 UriSource=\u0022/Assets/SampleMedia/animated.gif\u0022/\u003E\n \u003C/Image.Source\u003E\n \u003C/Image\u003E\n\n \u003CTextBlock Text=\u0022Control playback manually using BitmapImage.Play() and Stop().\u0022 TextWrapping=\u0022Wrap\u0022/\u003E\n \u003CImage Height=\u002240\u0022 HorizontalAlignment=\u0022Left\u0022\u003E\n \u003CImage.Source\u003E\n \u003CBitmapImage x:Name=\u0022ClickToPlaySource\u0022 AutoPlay=\u0022False\u0022\n UriSource=\u0022/Assets/SampleMedia/animated.gif\u0022\n ImageOpened=\u0022ClickToPlaySource_ImageOpened\u0022/\u003E\n \u003C/Image.Source\u003E\n \u003C/Image\u003E\n\u003C/StackPanel\u003E\n\n\u003C!-- The Play/Stop buttons live in ControlExample.Options so they appear in the side panel. --\u003E\n\u003CStackPanel x:Name=\u0022PlaybackButtons\u0022 Spacing=\u00228\u0022 Visibility=\u0022Collapsed\u0022\u003E\n \u003CButton Content=\u0022Play\u0022 Click=\u0022{x:Bind ClickToPlaySource.Play}\u0022/\u003E\n \u003CButton Content=\u0022Stop\u0022 Click=\u0022{x:Bind ClickToPlaySource.Stop}\u0022/\u003E\n\u003C/StackPanel\u003E","csharp":"private void ClickToPlaySource_ImageOpened(object sender, RoutedEventArgs e)\n{\n // BitmapImage.IsAnimatedBitmap is only valid after ImageOpened has been raised.\n if (ClickToPlaySource.IsAnimatedBitmap)\n {\n PlaybackButtons.Visibility = Visibility.Visible;\n }\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A control to display image content.","relatedControls":["MediaPlayerElement","PersonPicture"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"Image - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.image"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/images-imagebrushes"}]},{"id":"mapcontrol-1","controlId":"mapcontrol","controlName":"MapControl","headerText":"Showing a pin on the map","xaml":"\u003CMapControl x:Name=\u0022map1\u0022 MapServiceToken=\u0022MapServiceToken\u0022 Height=\u0022600\u0022/\u003E","csharp":"BasicGeoposition centerPosition = new BasicGeoposition { Latitude = 0, Longitude = 0 };\nGeopoint centerPoint = new Geopoint(centerPosition);\n\nmap1.Center = centerPoint;\nmap1.ZoomLevel = 1;\n\nvar myLandmarks = new List\u003CMapElement\u003E();\nBasicGeoposition position = new BasicGeoposition { Latitude = -30.034647, Longitude = -51.217659 };\nGeopoint point = new Geopoint(position);\n\nvar icon = new MapIcon\n{\n Location = point,\n};\n\nmyLandmarks.Add(icon);\n\nvar LandmarksLayer = new MapElementsLayer\n{\n MapElements = myLandmarks\n};\n\nmap1.Layers.Add(LandmarksLayer);","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Displays a symbolic map of the Earth.","relatedControls":[],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"MapControl - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.mapcontrol"}]},{"id":"mediaplayerelement-1","controlId":"mediaplayerelement","controlName":"MediaPlayerElement","headerText":"A MediaPlayerElement with transport controls.","xaml":"\u003CMediaPlayerElement Source=\u0022/Assets/SampleMedia/ladybug.wmv\u0022\n AutoPlay=\u0022False\u0022\n AreTransportControlsEnabled=\u0022True\u0022 /\u003E","csharp":"private async void OpenFileButton_Click(object sender, Microsoft.UI.Xaml.RoutedEventArgs e)\n{\n var picker = new FileOpenPicker((sender as Button).XamlRoot.ContentIslandEnvironment.AppWindowId);\n var file = await picker.PickSingleFileAsync();\n if (file == null)\n return;\n\n var mediaSource = MediaSource.CreateFromStorageFile(await StorageFile.GetFileFromPathAsync(file.Path));\n Player1.Source = mediaSource;\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A control to display video and image content.","relatedControls":["Image","CaptureElementPreview"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"MediaPlayerElement - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.MediaPlayerElement"},{"title":"Media Playback","uri":"https://learn.microsoft.com/windows/apps/design/controls/media-playback"}]},{"id":"mediaplayerelement-2","controlId":"mediaplayerelement","controlName":"MediaPlayerElement","headerText":"A MediaPlayerElement that autoplays the video.","xaml":"\u003CMediaPlayerElement Source=\u0022Assets/SampleMedia/fishes.wmv\u0022\n AutoPlay=\u0022True\u0022 /\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A control to display video and image content.","relatedControls":["Image","CaptureElementPreview"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"MediaPlayerElement - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.MediaPlayerElement"},{"title":"Media Playback","uri":"https://learn.microsoft.com/windows/apps/design/controls/media-playback"}]},{"id":"personpicture-1","controlId":"personpicture","controlName":"PersonPicture","headerText":"Select different looks for the person picture.","xaml":"\u003CPersonPicture ......... /\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Displays the picture of a person/contact.","relatedControls":["Image"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"PersonPicture - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Controls.PersonPicture"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/person-picture"}]},{"id":"sound-1","controlId":"sound","controlName":"Sound","headerText":"Toggling Sound","xaml":null,"csharp":"ElementSoundPlayer.State = ElementSoundPlayerState.Off;\nElementSoundPlayer.State = ElementSoundPlayerState.On;","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A code-behind only API that enables 2D and 3D UI sounds on all XAML controls.","relatedControls":[],"apiNamespace":"Microsoft.UI.Xaml","docs":[{"title":"Sound - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.elementsoundplayer"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/style/sound"}]},{"id":"sound-2","controlId":"sound","controlName":"Sound","headerText":"Toggling Spatial Audio","xaml":null,"csharp":"ElementSoundPlayer.State = ElementSoundPlayerState.On;\nElementSoundPlayer.SpatialAudioMode = ElementSpatialAudioMode.On","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A code-behind only API that enables 2D and 3D UI sounds on all XAML controls.","relatedControls":[],"apiNamespace":"Microsoft.UI.Xaml","docs":[{"title":"Sound - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.elementsoundplayer"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/style/sound"}]},{"id":"sound-3","controlId":"sound","controlName":"Sound","headerText":"Play Specific System Sound","xaml":null,"csharp":"ElementSoundPlayer.State = ElementSoundPlayerState.On;\n\nElementSoundPlayer.Play(ElementSoundKind.Focus);\nElementSoundPlayer.Play(ElementSoundKind.Invoke);\nElementSoundPlayer.Play(ElementSoundKind.Show);\nElementSoundPlayer.Play(ElementSoundKind.Hide);\nElementSoundPlayer.Play(ElementSoundKind.MovePrevious);\nElementSoundPlayer.Play(ElementSoundKind.MoveNext);\nElementSoundPlayer.Play(ElementSoundKind.GoBack);","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A code-behind only API that enables 2D and 3D UI sounds on all XAML controls.","relatedControls":[],"apiNamespace":"Microsoft.UI.Xaml","docs":[{"title":"Sound - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.elementsoundplayer"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/style/sound"}]},{"id":"webview2-1","controlId":"webview2","controlName":"WebView2","headerText":"A simple WebView2","xaml":"\u003CWebView2 x:Name=\u0022MyWebView2\u0022 Source=\u0022https://learn.microsoft.com/windows/apps/winui/winui3/\u0022 HorizontalAlignment=\u0022Stretch\u0022 VerticalAlignment=\u0022Stretch\u0022 Grid.Row=\u00221\u0022 MinHeight=\u0022200\u0022 MinWidth=\u0022200\u0022/\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A Microsoft Edge (Chromium) based control that hosts HTML content in an app.","relatedControls":[],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"WebView2 - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.webview2"},{"title":"Guidelines","uri":"https://learn.microsoft.com/microsoft-edge/webview2/gettingstarted/winui"},{"title":"Examples","uri":"https://github.com/MicrosoftEdge/WebView2Samples"}]},{"id":"acrylic-1","controlId":"acrylic","controlName":"AcrylicBrush","headerText":"Default in-app acrylic brush.","xaml":"\u003CRectangle Fill=\u0022{ThemeResource AcrylicInAppFillColorDefaultBrush}\u0022 /\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A translucent material recommended for panel backgrounds.","relatedControls":["SystemBackdrops","RadialGradientBrush","ThemeShadow"],"apiNamespace":"Microsoft.UI.Xaml.Media","docs":[{"title":"AcrylicBrush - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.acrylicbrush"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/style/acrylic"}]},{"id":"acrylic-2","controlId":"acrylic","controlName":"AcrylicBrush","headerText":"Custom acrylic in-app brush.","xaml":"\u003CRectangle Fill=\u0022{ThemeResource CustomAcrylicInAppBrush}\u0022 /\u003E\n\n\u003CResourceDictionary x:Key=\u0022Default\u0022\u003E\n \u003Cmedia:AcrylicBrush x:Key=\u0022CustomAcrylicBrush\u0022 \n TintOpacity=\u0022...\u0022 TintColor=\u0022...\u0022 FallbackColor=\u0022...\u0022 /\u003E\n\u003C/ResourceDictionary\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A translucent material recommended for panel backgrounds.","relatedControls":["SystemBackdrops","RadialGradientBrush","ThemeShadow"],"apiNamespace":"Microsoft.UI.Xaml.Media","docs":[{"title":"AcrylicBrush - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.acrylicbrush"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/style/acrylic"}]},{"id":"acrylic-3","controlId":"acrylic","controlName":"AcrylicBrush","headerText":"Luminosity with in-app Acrylic.","xaml":"\u003CRectangle Fill=\u0022{ThemeResource CustomAcrylicInAppLuminosity}\u0022 /\u003E\n\n\u003CResourceDictionary x:Key=\u0022Default\u0022\u003E\n \u003Cmedia:AcrylicBrush x:Key=\u0022CustomAcrylicInAppLuminosity\u0022 \n TintOpacity=\u0022...\u0022 TintLuminosityOpacity=\u0022...\u0022 TintColor=\u0022SkyBlue\u0022 FallbackColor=\u0022SkyBlue\u0022 /\u003E\n\u003C/ResourceDictionary\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A translucent material recommended for panel backgrounds.","relatedControls":["SystemBackdrops","RadialGradientBrush","ThemeShadow"],"apiNamespace":"Microsoft.UI.Xaml.Media","docs":[{"title":"AcrylicBrush - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.acrylicbrush"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/style/acrylic"}]},{"id":"animatedicon-1","controlId":"animatedicon","controlName":"AnimatedIcon","headerText":"Adding AnimatedIcon to a button","xaml":"\u003CButton PointerEntered=\u0022Button_PointerEntered\u0022 PointerExited=\u0022Button_PointerExited\u0022 Width=\u002275\u0022\u003E\n \u003CAnimatedIcon x:Name=\u0022SearchAnimatedIcon\u0022\u003E\n \u003CAnimatedIcon.Source\u003E\n \u003Canimatedvisuals:.../\u003E\n \u003C/AnimatedIcon.Source\u003E\n \u003CAnimatedIcon.FallbackIconSource\u003E\n \u003CSymbolIconSource Symbol=\u0022Find\u0022/\u003E\n \u003C/AnimatedIcon.FallbackIconSource\u003E\n \u003C/AnimatedIcon\u003E\n\u003C/Button\u003E","csharp":"private void Button_PointerEntered(object sender, PointerRoutedEventArgs e)\n{\n AnimatedIcon.SetState(this.SearchAnimatedIcon, \u0022PointerOver\u0022);\n}\n\nprivate void Button_PointerExited(object sender, PointerRoutedEventArgs e)\n{\n AnimatedIcon.SetState(this.SearchAnimatedIcon, \u0022Normal\u0022);\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"An element that displays and controls an icon that animates when the user interacts with the control.","relatedControls":["AnimatedVisualPlayer","IconElement"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"AnimatedIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.animatedicon"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/animated-icon"},{"title":"Lottie Overview","uri":"https://learn.microsoft.com/windows/communitytoolkit/animations/lottie"},{"title":"Lottie Windows - GitHub","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.animatedvisualplayer"}]},{"id":"animatedicon-2","controlId":"animatedicon","controlName":"AnimatedIcon","headerText":"Adding AnimatedIcon to a NavigationView","xaml":"\u003CNavigationView\u003E\n \u003CNavigationView.MenuItems\u003E\n \u003CNavigationViewItem Content = \u0022Game Settings\u0022\u003E\n \u003CNavigationViewItem.Icon\u003E\n \u003CAnimatedIcon x:Name=\u0027AnimatedIcon\u0027\u003E\n \u003CAnimatedIcon.Source\u003E\n \u003Canimatedvisuals:AnimatedSettingsVisualSource/\u003E\n \u003C/AnimatedIcon.Source\u003E\n \u003CAnimatedIcon.FallbackIconSource\u003E\n \u003CFontIconSource Glyph=\u0022\u0026#xE713;\u0022/\u003E\n \u003C/AnimatedIcon.FallbackIconSource\u003E\n \u003C/AnimatedIcon\u003E\n \u003C/NavigationViewItem.Icon\u003E\n \u003C/NavigationViewItem\u003E\n \u003C/NavigationView.MenuItems\u003E\n\u003C/NavigationView\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"An element that displays and controls an icon that animates when the user interacts with the control.","relatedControls":["AnimatedVisualPlayer","IconElement"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"AnimatedIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.animatedicon"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/animated-icon"},{"title":"Lottie Overview","uri":"https://learn.microsoft.com/windows/communitytoolkit/animations/lottie"},{"title":"Lottie Windows - GitHub","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.animatedvisualplayer"}]},{"id":"compactsizing-1","controlId":"compactsizing","controlName":"Compact Sizing","headerText":"Compact Sizing for controls","xaml":"\u003CPage.Resources\u003E\n \u003CResourceDictionary Source=\u0022ms-appx:///Microsoft.UI.Xaml/DensityStyles/Compact.xaml\u0022 /\u003E\n\u003C/Page.Resources\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"How to use a Resource Dictionary to enable compact sizing.","relatedControls":[],"apiNamespace":null,"docs":[{"title":"Spacing","uri":"https://learn.microsoft.com/windows/apps/design/style/spacing"}]},{"id":"iconelement-1","controlId":"iconelement","controlName":"IconElement","headerText":"A BitmapIcon with a multicolor bitmap image","xaml":"\u003CBitmapIcon x:Name=\u0022SlicesIcon\u0022 UriSource=\u0022ms-appx:///Assets/YourImage.png\u0022 Width=\u002250\u0022 ShowAsMonochrome=\u0022...\u0022/\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Represents icon controls that use different image types as its content.","relatedControls":["AnimatedIcon","AppBarButton"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"BitmapIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.bitmapicon"},{"title":"FontIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.fonticon"},{"title":"ImageIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.imageicon"},{"title":"PathIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.pathicon"},{"title":"SymbolIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.symbolicon"},{"title":"Icon Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/style/icons"}]},{"id":"iconelement-2","controlId":"iconelement","controlName":"IconElement","headerText":"A FontIcon using a glyph from a specific font family in a button","xaml":"\u003CButton Name=\u0022ExampleButton1\u0022\u003E\n \u003CFontIcon FontFamily=\u0022Segoe MDL2 Assets\u0022 Glyph=\u0022\u0026#xE790;\u0022/\u003E\n\u003C/Button\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Represents icon controls that use different image types as its content.","relatedControls":["AnimatedIcon","AppBarButton"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"BitmapIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.bitmapicon"},{"title":"FontIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.fonticon"},{"title":"ImageIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.imageicon"},{"title":"PathIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.pathicon"},{"title":"SymbolIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.symbolicon"},{"title":"Icon Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/style/icons"}]},{"id":"iconelement-3","controlId":"iconelement","controlName":"IconElement","headerText":"A ImageIcon using a bitmap image in a button","xaml":"\u003CButton Name=\u0022ImageExample1\u0022 Width=\u0022100\u0022\u003E\n \u003CImageIcon Source=\u0022/Assets/SampleMedia/slices.png\u0022/\u003E\n\u003C/Button\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Represents icon controls that use different image types as its content.","relatedControls":["AnimatedIcon","AppBarButton"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"BitmapIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.bitmapicon"},{"title":"FontIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.fonticon"},{"title":"ImageIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.imageicon"},{"title":"PathIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.pathicon"},{"title":"SymbolIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.symbolicon"},{"title":"Icon Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/style/icons"}]},{"id":"iconelement-4","controlId":"iconelement","controlName":"IconElement","headerText":"A ImageIcon using a SVG image in a button","xaml":"\u003CButton Name=\u0022ImageExample2\u0022\u003E\n \u003CImageIcon Source=\u0022https://raw.githubusercontent.com/DiemenDesign/LibreICONS/master/svg-color/libre-camera-panorama.svg\u0022 Width=\u002250\u0022/\u003E\n\u003C/Button\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Represents icon controls that use different image types as its content.","relatedControls":["AnimatedIcon","AppBarButton"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"BitmapIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.bitmapicon"},{"title":"FontIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.fonticon"},{"title":"ImageIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.imageicon"},{"title":"PathIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.pathicon"},{"title":"SymbolIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.symbolicon"},{"title":"Icon Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/style/icons"}]},{"id":"iconelement-5","controlId":"iconelement","controlName":"IconElement","headerText":"A PathIcon in a button","xaml":"\u003CButton Name=\u0022Example1Button\u0022\u003E\n \u003CPathIcon Data=\u0022F1 M 16,12 20,2L 20,16 1,16\u0022 HorizontalAlignment=\u0022Center\u0022/\u003E\n\u003C/Button\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Represents icon controls that use different image types as its content.","relatedControls":["AnimatedIcon","AppBarButton"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"BitmapIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.bitmapicon"},{"title":"FontIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.fonticon"},{"title":"ImageIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.imageicon"},{"title":"PathIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.pathicon"},{"title":"SymbolIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.symbolicon"},{"title":"Icon Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/style/icons"}]},{"id":"iconelement-6","controlId":"iconelement","controlName":"IconElement","headerText":"A SymbolIcon in a button","xaml":"\u003CButton Name=\u0022AcceptButton\u0022\u003E\n \u003CStackPanel\u003E\n \u003CSymbolIcon Symbol=\u0022Accept\u0022/\u003E\n \u003CTextBlock Text=\u0022Accept\u0022/\u003E\n \u003C/StackPanel\u003E\n\u003C/Button\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Represents icon controls that use different image types as its content.","relatedControls":["AnimatedIcon","AppBarButton"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"BitmapIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.bitmapicon"},{"title":"FontIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.fonticon"},{"title":"ImageIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.imageicon"},{"title":"PathIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.pathicon"},{"title":"SymbolIcon - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.symbolicon"},{"title":"Icon Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/style/icons"}]},{"id":"line-1","controlId":"line","controlName":"Line","headerText":"Line","xaml":"\u003CLine Stroke=\u0022SteelBlue\u0022\n X1=\u0022...\u0022 Y1=\u0022...\u0022\n X2=\u0022...\u0022 Y2=\u0022...\u0022\n StrokeThickness=\u0022...\u0022/\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Draws a straight line between two points.","relatedControls":["Shape"],"apiNamespace":"Microsoft.UI.Xaml.Shapes","docs":[{"title":"Lines - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.shapes"},{"title":"Guidelines","uri":"https://learn.microsoft.com/previous-versions/windows/apps/hh465055(v=win.10)"}]},{"id":"line-2","controlId":"line","controlName":"Line","headerText":"Polyline","xaml":"\u003CPolyline Stroke=\u0022Black\u0022 StrokeThickness=\u0022...\u0022\n Points=\u002210,100 60,40 200,40 250,100\u0022/\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Draws a straight line between two points.","relatedControls":["Shape"],"apiNamespace":"Microsoft.UI.Xaml.Shapes","docs":[{"title":"Lines - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.shapes"},{"title":"Guidelines","uri":"https://learn.microsoft.com/previous-versions/windows/apps/hh465055(v=win.10)"}]},{"id":"line-3","controlId":"line","controlName":"Line","headerText":"Path","xaml":"\u003C!-- The first segment is a cubic Bezier curve that begins at Point #1 and ends at Point #4, which is drawn by using Point #2 and 3 as the two control points. This segment is indicated by the \u0022C\u0022 command in the Data attribute string. --\u003E\n\u003C!-- The second segment begins with an absolute horizontal line command \u0022H\u0022, which specifies a line drawn from the preceding subpath endpoint (Point #4) to a new endpoint (Point #5). Because it\u0027s a horizontal line command, the value specified is an x-coordinate. --\u003E\n \n\u003CPath Stroke=\u0022DarkGoldenRod\u0022 StrokeThickness=\u0022...\u0022\n Data=\u0022M 10,100 C 100,25 300,250 400,75 H 200\u0022/\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Draws a straight line between two points.","relatedControls":["Shape"],"apiNamespace":"Microsoft.UI.Xaml.Shapes","docs":[{"title":"Lines - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.shapes"},{"title":"Guidelines","uri":"https://learn.microsoft.com/previous-versions/windows/apps/hh465055(v=win.10)"}]},{"id":"line-4","controlId":"line","controlName":"Line","headerText":"GeometryGroup","xaml":"\u003CPath Stroke=\u0022Black\u0022 StrokeThickness=\u00224\u0022 Fill=\u0022#CCCCFF\u0022\u003E\n \u003CPath.Data\u003E\n \n \u003C!-- Creates a composite shape from three geometries. --\u003E\n \u003CGeometryGroup FillRule=\u0022EvenOdd\u0022\u003E\n \u003CLineGeometry StartPoint=\u002210,10\u0022 EndPoint=\u002250,30\u0022 /\u003E\n \u003CEllipseGeometry Center=\u002240,70\u0022 RadiusX=\u0022...\u0022 RadiusY=\u0022...\u0022 /\u003E\n \u003CRectangleGeometry Rect=\u002230,55 100 30\u0022 /\u003E\n \u003C/GeometryGroup\u003E\n \u003C/Path.Data\u003E\n\u003C/Path\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Draws a straight line between two points.","relatedControls":["Shape"],"apiNamespace":"Microsoft.UI.Xaml.Shapes","docs":[{"title":"Lines - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.shapes"},{"title":"Guidelines","uri":"https://learn.microsoft.com/previous-versions/windows/apps/hh465055(v=win.10)"}]},{"id":"shape-1","controlId":"shape","controlName":"Shape","headerText":"Ellipse","xaml":"\u003CEllipse Fill=\u0022SteelBlue\u0022 Height=\u0022...\u0022 Width=\u0022...\u0022 StrokeThickness=\u0022...\u0022 Stroke=\u0022Black\u0022/\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"How to draw shapes, such as ellipses, rectangles, and polygons.","relatedControls":["Line"],"apiNamespace":"Microsoft.UI.Xaml.Shapes","docs":[{"title":"Shapes - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.shapes"},{"title":"Guidelines","uri":"https://learn.microsoft.com/previous-versions/windows/apps/hh465055(v=win.10)"}]},{"id":"shape-2","controlId":"shape","controlName":"Shape","headerText":"Rectangle","xaml":"\u003CRectangle Fill=\u0022SteelBlue\u0022 Height=\u0022...\u0022 Width=\u0022...\u0022\n Stroke=\u0022Black\u0022 StrokeThickness=\u0022...\u0022\n RadiusY=\u0022...\u0022 RadiusX=\u0022...\u0022/\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"How to draw shapes, such as ellipses, rectangles, and polygons.","relatedControls":["Line"],"apiNamespace":"Microsoft.UI.Xaml.Shapes","docs":[{"title":"Shapes - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.shapes"},{"title":"Guidelines","uri":"https://learn.microsoft.com/previous-versions/windows/apps/hh465055(v=win.10)"}]},{"id":"shape-3","controlId":"shape","controlName":"Shape","headerText":"Polygon","xaml":"\u003CPolygon Fill=\u0022SteelBlue\u0022 Points=\u002210,100 60,40 200,40 250,100\u0022\n StrokeThickness=\u0022...\u0022 Stroke=\u0022Black\u0022/\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"How to draw shapes, such as ellipses, rectangles, and polygons.","relatedControls":["Line"],"apiNamespace":"Microsoft.UI.Xaml.Shapes","docs":[{"title":"Shapes - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.shapes"},{"title":"Guidelines","uri":"https://learn.microsoft.com/previous-versions/windows/apps/hh465055(v=win.10)"}]},{"id":"radialgradientbrush-1","controlId":"radialgradientbrush","controlName":"RadialGradientBrush","headerText":"RadialGradientBrush Sample","xaml":"\u003CRectangle Width=\u0022200\u0022 Height=\u0022200\u0022\u003E\n \u003CRectangle.Fill\u003E\n \u003Cmedia:RadialGradientBrush\n MappingMode=\u0022...\u0022\n Center=\u0022...,...\u0022\n RadiusX=\u0022...\u0022\n RadiusY=\u0022...\u0022\n GradientOrigin=\u0022...,...\u0022\n SpreadMethod=\u0022...\u0022\u003E\n \u003CGradientStop Color=\u0022Yellow\u0022 Offset=\u00220.0\u0022 /\u003E\n \u003CGradientStop Color=\u0022Blue\u0022 Offset=\u00221\u0022 /\u003E\n \u003C/media:RadialGradientBrush\u003E\n \u003C/Rectangle.Fill\u003E\n\u003C/Rectangle\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A brush to show radial gradients.","relatedControls":["Acrylic"],"apiNamespace":"Microsoft.UI.Xaml.Media","docs":[{"title":"RadialGradientBrush - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.RadialGradientBrush"}]},{"id":"systembackdrops-1","controlId":"systembackdrops","controlName":"System Backdrops (Mica/Acrylic)","headerText":"Backdrop types","xaml":"\u003C!-- Mica --\u003E\n\u003CWindow.SystemBackdrop\u003E\n \u003CMicaBackdrop/\u003E\n\u003C/Window.SystemBackdrop\u003E\n \n\u003C!-- Mica Alt --\u003E\n\u003CWindow.SystemBackdrop\u003E\n \u003CMicaBackdrop Kind=\u0022BaseAlt\u0022/\u003E\n\u003C/Window.SystemBackdrop\u003E\n\n\u003C!-- Acrylic --\u003E\n\u003CWindow.SystemBackdrop\u003E\n \u003CDesktopAcrylicBackdrop/\u003E\n\u003C/Window.SystemBackdrop\u003E","csharp":"bool TrySetMicaBackdrop(bool useMicaAlt)\n{\n if (SystemBackdrops.MicaController.IsSupported())\n {\n MicaBackdrop micaBackdrop = new MicaBackdrop();\n micaBackdrop.Kind = useMicaAlt ? MicaKind.BaseAlt : MicaKind.Base;\n SystemBackdrop = micaBackdrop;\n\n return true; // Succeeded.\n }\n\n return false; // Mica is not supported on this system.\n}\n\nbool TrySetDesktopAcrylicBackdrop()\n{\n if (DesktopAcrylicController.IsSupported())\n {\n DesktopAcrylicBackdrop DesktopAcrylicBackdrop = new DesktopAcrylicBackdrop();\n SystemBackdrop = DesktopAcrylicBackdrop;\n\n return true; // Succeeded.\n }\n\n return false; // DesktopAcrylic is not supported on this system.\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"System backdrops, like Mica and Acrylic, for app windows.","relatedControls":["Acrylic"],"apiNamespace":"Microsoft.UI.Composition.SystemBackdrops","docs":[{"title":"SystemBackdrop - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.systembackdrop"},{"title":"MicaBackdrop - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.micabackdrop"},{"title":"DesktopAcrylicBackdrop - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.desktopacrylicbackdrop"},{"title":"MicaController - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.composition.systembackdrops.micacontroller"},{"title":"DesktopAcrylicController - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.composition.systembackdrops.desktopacryliccontroller"}]},{"id":"systembackdrops-2","controlId":"systembackdrops","controlName":"System Backdrops (Mica/Acrylic)","headerText":"MicaController","xaml":null,"csharp":"using System.Runtime.InteropServices;\nusing WinRT;\nusing Microsoft.UI.Composition;\nusing Microsoft.UI.Composition.SystemBackdrops;\n\nMicaController micaController;\nSystemBackdropConfiguration configurationSource;\n\nbool TrySetMicaBackdrop(bool useMicaAlt)\n{\n if (MicaController.IsSupported())\n {\n DispatcherQueue.EnsureSystemDispatcherQueue();\n\n // Hooking up the policy object\n configurationSource = new SystemBackdropConfiguration();\n Activated \u002B= Window_Activated;\n Closed \u002B= Window_Closed;\n ((FrameworkElement)Content).ActualThemeChanged \u002B= Window_ThemeChanged;\n\n // Initial configuration state.\n configurationSource.IsInputActive = true;\n SetConfigurationSourceTheme();\n\n micaController = new MicaController();\n micaController.Kind = useMicaAlt ? MicaKind.BaseAlt : MicaKind.Base;\n\n // Enable the system backdrop.\n micaController.AddSystemBackdropTarget(this.As\u003CICompositionSupportsSystemBackdrop\u003E());\n micaController.SetSystemBackdropConfiguration(configurationSource);\n return true; // Succeeded.\n }\n\n return false; // Mica is not supported on this system.\n}\n\nprivate void Window_Activated(object sender, WindowActivatedEventArgs args)\n{\n configurationSource.IsInputActive = args.WindowActivationState != WindowActivationState.Deactivated;\n}\n\nprivate void Window_Closed(object sender, WindowEventArgs args)\n{\n // Make sure any Mica/Acrylic controller is disposed\n if (micaController != null)\n {\n micaController.Dispose();\n micaController = null;\n }\n this.Activated -= Window_Activated;\n configurationSource = null;\n}\n\nprivate void Window_ThemeChanged(FrameworkElement sender, object args)\n{\n if (configurationSource != null)\n {\n SetConfigurationSourceTheme();\n }\n}\n\nprivate void SetConfigurationSourceTheme()\n{\n switch (((FrameworkElement)Content).ActualTheme)\n {\n case ElementTheme.Dark: configurationSource.Theme = SystemBackdropTheme.Dark; break;\n case ElementTheme.Light: configurationSource.Theme = SystemBackdropTheme.Light; break;\n case ElementTheme.Default: configurationSource.Theme = SystemBackdropTheme.Default; break;\n }\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"System backdrops, like Mica and Acrylic, for app windows.","relatedControls":["Acrylic"],"apiNamespace":"Microsoft.UI.Composition.SystemBackdrops","docs":[{"title":"SystemBackdrop - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.systembackdrop"},{"title":"MicaBackdrop - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.micabackdrop"},{"title":"DesktopAcrylicBackdrop - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.desktopacrylicbackdrop"},{"title":"MicaController - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.composition.systembackdrops.micacontroller"},{"title":"DesktopAcrylicController - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.composition.systembackdrops.desktopacryliccontroller"}]},{"id":"systembackdrops-3","controlId":"systembackdrops","controlName":"System Backdrops (Mica/Acrylic)","headerText":"DesktopAcrylicController","xaml":null,"csharp":"using System.Runtime.InteropServices;\nusing WinRT;\nusing Microsoft.UI.Composition;\nusing Microsoft.UI.Composition.SystemBackdrops;\n\nSystemBackdrops.DesktopAcrylicController acrylicController;\nSystemBackdrops.SystemBackdropConfiguration configurationSource;\n\nbool TrySetAcrylicBackdrop(bool useAcrylicThin)\n{\n if (DesktopAcrylicController.IsSupported())\n {\n DispatcherQueue.EnsureSystemDispatcherQueue();\n\n // Hooking up the policy object\n configurationSource = new SystemBackdropConfiguration();\n Activated \u002B= Window_Activated;\n Closed \u002B= Window_Closed;\n ((FrameworkElement)Content).ActualThemeChanged \u002B= Window_ThemeChanged;\n\n // Initial configuration state.\n configurationSource.IsInputActive = true;\n SetConfigurationSourceTheme();\n\n acrylicController = new DesktopAcrylicController();\n acrylicController.Kind = useAcrylicThin ? DesktopAcrylicKind.Thin : DesktopAcrylicKind.Base;\n\n // Enable the system backdrop.\n acrylicController.AddSystemBackdropTarget(As\u003CICompositionSupportsSystemBackdrop\u003E());\n acrylicController.SetSystemBackdropConfiguration(configurationSource);\n return true; // Succeeded.\n }\n\n return false; // Acrylic is not supported on this system.\n}\n\nprivate void Window_Activated(object sender, WindowActivatedEventArgs args)\n{\n configurationSource.IsInputActive = args.WindowActivationState != WindowActivationState.Deactivated;\n}\n\nprivate void Window_Closed(object sender, WindowEventArgs args)\n{\n // Make sure any Mica/Acrylic controller is disposed\n if (acrylicController != null)\n {\n acrylicController.Dispose();\n acrylicController = null;\n }\n Activated -= Window_Activated;\n configurationSource = null;\n}\n\nprivate void Window_ThemeChanged(FrameworkElement sender, object args)\n{\n if (configurationSource != null)\n {\n SetConfigurationSourceTheme();\n }\n}\n\nprivate void SetConfigurationSourceTheme()\n{\n switch (((FrameworkElement)this.Content).ActualTheme)\n {\n case ElementTheme.Dark: configurationSource.Theme = SystemBackdropTheme.Dark; break;\n case ElementTheme.Light: configurationSource.Theme = SystemBackdropTheme.Light; break;\n case ElementTheme.Default: configurationSource.Theme = SystemBackdropTheme.Default; break;\n }\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"System backdrops, like Mica and Acrylic, for app windows.","relatedControls":["Acrylic"],"apiNamespace":"Microsoft.UI.Composition.SystemBackdrops","docs":[{"title":"SystemBackdrop - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.systembackdrop"},{"title":"MicaBackdrop - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.micabackdrop"},{"title":"DesktopAcrylicBackdrop - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.desktopacrylicbackdrop"},{"title":"MicaController - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.composition.systembackdrops.micacontroller"},{"title":"DesktopAcrylicController - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.composition.systembackdrops.desktopacryliccontroller"}]},{"id":"themeshadow-1","controlId":"themeshadow","controlName":"ThemeShadow","headerText":"ThemeShadow applied to a Border","xaml":"\u003CGrid\u003E\n \u003CGrid x:Name=\u0022ShadowCastGrid\u0022/\u003E\n \u003CBorder x:Name=\u0022ShadowRect\u0022 Translation=\u00220,0,...\u0022 Loaded=\u0022ShadowRect_Loaded\u0022 Width=\u0022200\u0022 Height=\u0022200\u0022 CornerRadius=\u0022{ThemeResource OverlayCornerRadius}\u0022 Background=\u0022{ThemeResource CardBackgroundFillColorDefaultBrush}\u0022/\u003E\n \u003CBorder.Shadow\u003E\n \u003CThemeShadow x:Name=\u0022shadow\u0022/\u003E\n \u003C/Border.Shadow\u003E\n \u003C/Border\u003E \n\u003C/Grid\u003E","csharp":"private void ShadowRect_Loaded(object sender, RoutedEventArgs e)\n{\n shadow.Receivers.Add(ShadowCastGrid);\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Adds a depth-aware shadow to UI elements using system lighting.","relatedControls":["Acrylic"],"apiNamespace":"Microsoft.UI.Xaml.Media","docs":[{"title":"Z-depth and shadow design guidelines","uri":"https://learn.microsoft.com/windows/apps/design/layout/depth-shadow"},{"title":"ThemeShadow - API","uri":"https://learn.microsoft.com/en-us/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.themeshadow"}]},{"id":"autosuggestbox-1","controlId":"autosuggestbox","controlName":"AutoSuggestBox","headerText":"A basic autosuggest box.","xaml":"\u003CAutoSuggestBox TextChanged=\u0022AutoSuggestBox_TextChanged\u0022\n SuggestionChosen=\u0022AutoSuggestBox_SuggestionChosen\u0022\n Width=\u0022300\u0022 AutomationProperties.Name=\u0022Basic AutoSuggestBox\u0022/\u003E","csharp":"// List of cats\nprivate List\u003Cstring\u003E Cats = new List\u003Cstring\u003E()\n{\n \u0022Abyssinian\u0022,\n \u0022Aegean\u0022,\n \u0022American Bobtail\u0022,\n ...\n};\n\n// Handle text change and present suitable items\nprivate void AutoSuggestBox_TextChanged(AutoSuggestBox sender, AutoSuggestBoxTextChangedEventArgs args)\n{\n // Since selecting an item will also change the text,\n // only listen to changes caused by user entering text.\n if(args.Reason == AutoSuggestionBoxTextChangeReason.UserInput)\n {\n var suitableItems = new List\u003Cstring\u003E();\n var splitText = sender.Text.ToLower().Split(\u0022 \u0022);\n foreach(var cat in Cats)\n {\n var found = splitText.All((key)=\u003E\n {\n return cat.ToLower().Contains(key);\n });\n if(found)\n {\n suitableItems.Add(cat);\n }\n }\n if(suitableItems.Count == 0)\n {\n suitableItems.Add(\u0022No results found\u0022);\n }\n sender.ItemsSource = suitableItems;\n }\n}\n\n// Handle user selecting an item, in our case just output the selected item.\nprivate void AutoSuggestBox_SuggestionChosen(AutoSuggestBox sender, AutoSuggestBoxSuggestionChosenEventArgs args)\n{\n SuggestionOutput.Text = args.SelectedItem.ToString();\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A control to provide suggestions as a user is typing.","relatedControls":["ComboBox","TextBox"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"AutoSuggestBox - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.autosuggestbox"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/auto-suggest-box"}]},{"id":"autosuggestbox-2","controlId":"autosuggestbox","controlName":"AutoSuggestBox","headerText":"An AutoSuggestBox that provides a SearchBox experience","xaml":"\u003CAutoSuggestBox PlaceholderText=\u0022Type a control name\u0022\n TextChanged=\u0022Control2_TextChanged\u0022\n QueryIcon=\u0022Find\u0022\n QuerySubmitted=\u0022Control2_QuerySubmitted\u0022\n SuggestionChosen=\u0022Control2_SuggestionChosen\u0022/\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A control to provide suggestions as a user is typing.","relatedControls":["ComboBox","TextBox"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"AutoSuggestBox - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.autosuggestbox"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/auto-suggest-box"}]},{"id":"numberbox-1","controlId":"numberbox","controlName":"NumberBox","headerText":"A NumberBox that evaluates expressions.","xaml":"\u003CNumberBox Header=\u0022Enter an expression:\u0022 Value=\u0022NaN\u0022 PlaceholderText=\u00221 \u002B 2^2\u0022 AcceptsExpression=\u0022True\u0022 /\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A text control used for numeric input and evaluation of algebraic equations.","relatedControls":["TextBox","TextBlock","RichTextBlock","RichEditBox"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"NumberBox - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.numberbox"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/number-box"}]},{"id":"numberbox-2","controlId":"numberbox","controlName":"NumberBox","headerText":"A NumberBox with a spin button.","xaml":"\u003CNumberBox\n x:Name=\u0022NumberBoxSpinButtonPlacementExample\u0022\n Header=\u0022Enter an integer:\u0022 \n Value=\u00221\u0022 \n SpinButtonPlacementMode=\u0022...\u0022\n SmallChange=\u002210\u0022\n LargeChange=\u0022100\u0022 /\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A text control used for numeric input and evaluation of algebraic equations.","relatedControls":["TextBox","TextBlock","RichTextBlock","RichEditBox"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"NumberBox - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.numberbox"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/number-box"}]},{"id":"numberbox-3","controlId":"numberbox","controlName":"NumberBox","headerText":"A formatted NumberBox that rounds to the nearest 0.25.","xaml":"\u003CNumberBox x:Name=\u0022FormattedNumberBox\u0022 Header=\u0022Enter an dollar amount:\u0022 PlaceholderText=\u00220.00\u0022 /\u003E","csharp":"private void SetNumberBoxNumberFormatter()\n{\n IncrementNumberRounder rounder = new IncrementNumberRounder();\n rounder.Increment = 0.25;\n rounder.RoundingAlgorithm = RoundingAlgorithm.RoundHalfUp;\n\n DecimalFormatter formatter = new DecimalFormatter();\n formatter.IntegerDigits = 1;\n formatter.FractionDigits = 2;\n formatter.NumberRounder = rounder;\n FormattedNumberBox.NumberFormatter = formatter;\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A text control used for numeric input and evaluation of algebraic equations.","relatedControls":["TextBox","TextBlock","RichTextBlock","RichEditBox"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"NumberBox - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.numberbox"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/number-box"}]},{"id":"passwordbox-1","controlId":"passwordbox","controlName":"PasswordBox","headerText":"A simple PasswordBox.","xaml":"\u003CPasswordBox Width=\u0022300\u0022 AutomationProperties.Name=\u0022Simple PasswordBox\u0022/\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A control for entering passwords.","relatedControls":["TextBox","TextBlock","RichTextBlock","RichEditBox"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"PasswordBox - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.passwordbox"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/text-controls"}]},{"id":"passwordbox-2","controlId":"passwordbox","controlName":"PasswordBox","headerText":"A PasswordBox with header, placeholder text and custom character.","xaml":"\u003CPasswordBox Width=\u0022300\u0022 Header=\u0022Password\u0022 PlaceholderText=\u0022Enter your password\u0022 PasswordChar=\u0022#\u0022 /\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A control for entering passwords.","relatedControls":["TextBox","TextBlock","RichTextBlock","RichEditBox"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"PasswordBox - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.passwordbox"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/text-controls"}]},{"id":"passwordbox-3","controlId":"passwordbox","controlName":"PasswordBox","headerText":"A PasswordBox with reveal mode.","xaml":"\u003CPasswordBox Name=\u0022passworBoxWithRevealmode\u0022 Width=\u0022250\u0022 Margin=\u00220,0,8,0\u0022\n PasswordRevealMode=\u0022Hidden\u0022 AutomationProperties.Name=\u0022Sample password box\u0022/\u003E\n\u003CCheckBox Name=\u0022revealModeCheckBox\u0022 Content=\u0022Show password\u0022 IsChecked=\u0022False\u0022\n Checked=\u0022RevealModeCheckbox_Changed\u0022 Unchecked=\u0022RevealModeCheckbox_Changed\u0022/\u003E","csharp":"private void RevealModeCheckbox_Changed(object sender, RoutedEventArgs e)\n{\n if (revealModeCheckBox.IsChecked == true)\n {\n passworBoxWithRevealmode.PasswordRevealMode = PasswordRevealMode.Visible;\n }\n else\n {\n passworBoxWithRevealmode.PasswordRevealMode = PasswordRevealMode.Hidden;\n }\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A control for entering passwords.","relatedControls":["TextBox","TextBlock","RichTextBlock","RichEditBox"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"PasswordBox - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.passwordbox"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/text-controls"}]},{"id":"richeditbox-1","controlId":"richeditbox","controlName":"RichEditBox","headerText":"A simple text editor using RichEditBox.","xaml":"\u003CRichEditBox x:Name=\u0022editor\u0022 AutomationProperties.Name=\u0022simple text editor\u0022/\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A rich text editing control that supports formatted text, hyperlinks, and other rich content.","relatedControls":["NumberBox","TextBox","RichTextBlock","TextBlock"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"RichEditBox - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.richeditbox"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/text-controls"}]},{"id":"richeditbox-2","controlId":"richeditbox","controlName":"RichEditBox","headerText":"Customizing RichEditBox\u0027s CommandBarFlyout - Adding \u0027Share\u0027","xaml":"\u003CRichEditBox x:Name=\u0022REBCustom\u0022 \n AutomationProperties.Name=\u0022editor with custom menu\u0022\n Unloaded=\u0022REBCustom_Unloaded\u0022/\u003E","csharp":"private void Menu_Opening(object sender, object e)\n{\n if (sender is not CommandBarFlyout myFlyout)\n {\n return;\n }\n\n if (myFlyout.Target == REBCustom)\n {\n AppBarButton myButton = new AppBarButton();\n myButton.Command = new StandardUICommand(StandardUICommandKind.Share);\n myFlyout.PrimaryCommands.Add(myButton);\n }\n}\n\nprivate void REBCustom_Loaded(object sender, RoutedEventArgs e)\n{\n REBCustom.SelectionFlyout.Opening \u002B= Menu_Opening;\n REBCustom.ContextFlyout.Opening \u002B= Menu_Opening;\n}\n\nprivate void REBCustom_Unloaded(object sender, RoutedEventArgs e)\n{\n REBCustom.SelectionFlyout.Opening -= Menu_Opening;\n REBCustom.ContextFlyout.Opening -= Menu_Opening;\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A rich text editing control that supports formatted text, hyperlinks, and other rich content.","relatedControls":["NumberBox","TextBox","RichTextBlock","TextBlock"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"RichEditBox - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.richeditbox"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/text-controls"}]},{"id":"richeditbox-3","controlId":"richeditbox","controlName":"RichEditBox","headerText":"A custom editor with RichEditBox.","xaml":"\u003CRelativePanel Margin=\u00220,0,0,20\u0022 HorizontalAlignment=\u0022Stretch\u0022\u003E\n \u003CRelativePanel.Resources\u003E\n \u003CStyle TargetType=\u0022Button\u0022\u003E\n \u003CSetter Property=\u0022BorderThickness\u0022 Value=\u00220\u0022 /\u003E\n \u003CSetter Property=\u0022Background\u0022 Value=\u0022Transparent\u0022/\u003E\n \u003CSetter Property=\u0022Margin\u0022 Value=\u00220,0,8,0\u0022 /\u003E\n \u003C/Style\u003E\n \u003C/RelativePanel.Resources\u003E\n \u003CButton x:Name=\u0022openFileButton\u0022 Click=\u0022OpenButton_Click\u0022 AutomationProperties.Name=\u0022Open file\u0022 ToolTipService.ToolTip=\u0022Open file\u0022\u003E\n \u003CButton.Content\u003E\n \u003CFontIcon Glyph=\u0022\u0026#xE8E5;\u0022/\u003E\n \u003C/Button.Content\u003E\n \u003C/Button\u003E\n \u003CButton Click=\u0022SaveButton_Click\u0022 AutomationProperties.Name=\u0022Save file\u0022 ToolTipService.ToolTip=\u0022Save file\u0022 \n RelativePanel.RightOf=\u0022openFileButton\u0022\u003E\n \u003CButton.Content\u003E\n \u003CFontIcon Glyph=\u0022\u0026#xE74E;\u0022/\u003E\n \u003C/Button.Content\u003E\n \u003C/Button\u003E\n \u003CButton AutomationProperties.Name=\u0022Bold\u0022 ToolTipService.ToolTip=\u0022Bold\u0022 Click=\u0022BoldButton_Click\u0022 \n RelativePanel.LeftOf=\u0022italicButton\u0022 \u003E\n \u003CButton.Content\u003E\n \u003CFontIcon Glyph=\u0022\u0026#xE8DD;\u0022/\u003E\n \u003C/Button.Content\u003E\n \u003C/Button\u003E\n \u003CButton x:Name=\u0022italicButton\u0022 Click=\u0022ItalicButton_Click\u0022 AutomationProperties.Name=\u0022Italic\u0022 ToolTipService.ToolTip=\u0022Italic\u0022 \n RelativePanel.LeftOf=\u0022fontColorButton\u0022\u003E\n \u003CButton.Content\u003E\n \u003CFontIcon Glyph=\u0022\u0026#xE8DB;\u0022/\u003E\n \u003C/Button.Content\u003E\n \u003C/Button\u003E\n\n \u003CDropDownButton x:Name=\u0022fontColorButton\u0022 AutomationProperties.Name=\u0022Font color\u0022\n BorderThickness=\u00220\u0022 ToolTipService.ToolTip=\u0022Font color\u0022\n Background=\u0022Transparent\u0022 \n RelativePanel.AlignRightWithPanel=\u0022True\u0022\u003E\n \u003CSymbolIcon Symbol=\u0022FontColor\u0022/\u003E\n \u003CDropDownButton.Flyout\u003E\n \u003CFlyout Placement=\u0022Bottom\u0022\u003E\n \u003CVariableSizedWrapGrid Orientation=\u0022Horizontal\u0022 MaximumRowsOrColumns=\u00223\u0022\u003E\n \u003CVariableSizedWrapGrid.Resources\u003E\u003C/VariableSizedWrapGrid.Resources\u003E\u003C/VariableSizedWrapGrid\u003E\u003C/Flyout\u003E\u003C/DropDownButton.Flyout\u003E\u003C/DropDownButton\u003E\u003C/RelativePanel\u003E\n\u003C!-- ...truncated --\u003E","csharp":"private async void OpenButton_Click(object sender, RoutedEventArgs e)\n{\n if (sender is Button button)\n {\n // Create the picker using the AppWindowId from the element\n var picker = new FileOpenPicker(button.XamlRoot.ContentIslandEnvironment.AppWindowId)\n {\n SuggestedStartLocation = PickerLocationId.DocumentsLibrary\n };\n\n // Add file type filters\n picker.FileTypeFilter.Add(\u0022.rtf\u0022);\n\n // Show picker\n PickFileResult result = await picker.PickSingleFileAsync();\n\n if (result != null)\n {\n // Open with StorageFile (needed for RichEditBox)\n StorageFile file = await StorageFile.GetFileFromPathAsync(result.Path);\n\n using IRandomAccessStream randAccStream =\n await file.OpenAsync(FileAccessMode.Read);\n\n // Load file into the RichEditBox\n editor.Document.LoadFromStream(TextSetOptions.FormatRtf, randAccStream);\n }\n }\n}\n\nprivate async void SaveButton_Click(object sender, RoutedEventArgs e)\n{\n if (sender is Button button)\n {\n // Create the picker with AppWindowId\n var savePicker = new FileSavePicker(button.XamlRoot.ContentIslandEnvironment.AppWindowId)\n {\n SuggestedStartLocation = PickerLocationId.DocumentsLibrary,\n SuggestedFileName = \u0022New Document\u0022\n };\n\n // Dropdown of file types the user can save the file as\n savePicker.FileTypeChoices.Add(\u0022Rich Text\u0022, new List\u003Cstring\u003E() { \u0022.rtf\u0022 });\n\n // Show picker\n PickFileResult result = await savePicker.PickSaveFileAsync();\n\n if (result != null)\n {\n // Convert PickSaveFileResult to StorageFile\n StorageFile file = await StorageFile.GetFileFromPathAsync(result.Path);\n\n // Prevent updates to the remote version of the file until complete\n CachedFileManager.DeferUpdates(file);\n\n // Write content into the file\n using IRandomAccessStream randAccStream =\n await file.OpenAsync(FileAccessMode.ReadWrite);\n\n editor.Document.SaveToStream(TextGetOptions.FormatRtf, randAccStream);\n\n // Finalize file updates\n FileUpdateStatus status = await CachedFileManager.CompleteUpdatesAsync(file);\n\n if (status != FileUpdateStatus.Complete)\n {\n var errorBox = new Windows.UI.Popups.MessageDialog(\n $\u0022File {file.Name} couldn\u0027t be saved.\u0022);\n await errorBox.ShowAsync();\n }\n }\n }\n}\n\nprivate void BoldButton_Click(object sender, RoutedEventArgs e)\n{\n editor.Document.Selection.CharacterFormat.Bold = FormatEffect.Toggle;\n}\n// NOTE: snippet truncated \u2014 refer to full sample for additional code","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A rich text editing control that supports formatted text, hyperlinks, and other rich content.","relatedControls":["NumberBox","TextBox","RichTextBlock","TextBlock"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"RichEditBox - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.richeditbox"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/text-controls"}]},{"id":"richeditbox-4","controlId":"richeditbox","controlName":"RichEditBox","headerText":"Rich edit box in math mode","xaml":"\u003CRichEditBox x:Name=\u0022mathEditor\u0022 FontSize=\u002216\u0022 /\u003E","csharp":"mathEditor.TextDocument.SetMathMode(RichEditMathMode.MathOnly);","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A rich text editing control that supports formatted text, hyperlinks, and other rich content.","relatedControls":["NumberBox","TextBox","RichTextBlock","TextBlock"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"RichEditBox - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.richeditbox"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/text-controls"}]},{"id":"richeditbox-5","controlId":"richeditbox","controlName":"RichEditBox","headerText":"Working with MathML in RichEditBox","xaml":"\u003CRichEditBox x:Name=\u0022mathEditor2\u0022 FontSize=\u002216\u0022 /\u003E","csharp":"mathEditor2.TextDocument.SetMathMode(RichEditMathMode.MathOnly);\n\nprivate void mathEditor2_TextChanged(object sender, RoutedEventArgs e)\n{\n // Extracts the MathML content from the RichEditBox\n string extractedMathML;\n mathEditor2.Document.GetMathML(out extractedMathML);\n \n // If MathML content is available, format and display it in the MathML presenter\n if (!string.IsNullOrEmpty(extractedMathML))\n {\n MathmlPresenter.Code = MathModeHelper.FormatMathML(extractedMathML);\n }\n else\n {\n // If no MathML content exists, display a placeholder comment\n MathmlPresenter.Code = \u0022\u003C!-- No MathML content --\u003E\u0022;\n }\n}\n\nprivate void SetMathmlFormulaBtn_Click(object sender, RoutedEventArgs e)\n{\n // Defines a formula in MathML format\n string formulaMathML =\n \u0022\u003Cmml:math xmlns:mml=\\\u0022http://www.w3.org/1998/Math/MathML\\\u0022 display=\\\u0022block\\\u0022\u003E\\r\\n\u0022 \u002B\n \u0022 \u003Cmml:mi mathcolor=\\\u0022#000000\\\u0022\u003Ex\u003C/mml:mi\u003E\\r\\n\u0022 \u002B\n \u0022 \u003Cmml:mo mathcolor=\\\u0022#000000\\\u0022\u003E\\u2208\u003C/mml:mo\u003E\\r\\n\u0022 \u002B\n \u0022 \u003Cmml:mi mathcolor=\\\u0022#000000\\\u0022\u003EP\u003C/mml:mi\u003E\\r\\n\u0022 \u002B\n \u0022 \u003Cmml:mfenced\u003E\\r\\n\u0022 \u002B\n \u0022 \u003Cmml:mrow\u003E\\r\\n\u0022 \u002B\n \u0022 \u003Cmml:mi mathcolor=\\\u0022#000000\\\u0022\u003EA\u003C/mml:mi\u003E\\r\\n\u0022 \u002B\n \u0022 \u003C/mml:mrow\u003E\\r\\n\u0022 \u002B\n \u0022 \u003C/mml:mfenced\u003E\\r\\n\u0022 \u002B\n \u0022 \u003Cmml:mo mathcolor=\\\u0022#000000\\\u0022\u003E\\u2194\u003C/mml:mo\u003E\\r\\n\u0022 \u002B\n \u0022 \u003Cmml:mi mathcolor=\\\u0022#000000\\\u0022\u003Ex\u003C/mml:mi\u003E\\r\\n\u0022 \u002B\n \u0022 \u003Cmml:mo mathcolor=\\\u0022#000000\\\u0022\u003E\\u2286\u003C/mml:mo\u003E\\r\\n\u0022 \u002B\n \u0022 \u003Cmml:mi mathcolor=\\\u0022#000000\\\u0022\u003EA\u003C/mml:mi\u003E\\r\\n\u0022 \u002B\n \u0022\u003C/mml:math\u003E\u0022;\n\n // Adjusts text color based on the current app theme\n if(mathEditor2.ActualTheme == ElementTheme.Dark)\n {\n // If in dark mode, set text color to white\n mathEditor2.Document.SetMathML(formulaMathML.Replace(\u0022mathcolor=\\\u0022#000000\\\u0022\u0022, \u0022mathcolor=\\\u0022#FFFFFF\\\u0022\u0022));\n }\n else\n {\n // If in light mode, set text color to black\n mathEditor2.Document.SetMathML(formulaMathML.Replace(\u0022mathcolor=\\\u0022#FFFFFF\\\u0022\u0022, \u0022mathcolor=\\\u0022#000000\\\u0022\u0022));\n }\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A rich text editing control that supports formatted text, hyperlinks, and other rich content.","relatedControls":["NumberBox","TextBox","RichTextBlock","TextBlock"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"RichEditBox - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.richeditbox"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/text-controls"}]},{"id":"richtextblock-1","controlId":"richtextblock","controlName":"RichTextBlock","headerText":"A simple RichTextBlock.","xaml":"\u003CRichTextBlock\u003E\n \u003CParagraph\u003EI am a RichTextBlock.\u003C/Paragraph\u003E\n\u003C/RichTextBlock\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A control that displays formatted text, hyperlinks, inline images, and other rich content.","relatedControls":["NumberBox","TextBlock","TextBox","PasswordBox","RichEditBox"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"RichTextBlock - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.richtextblock"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/text-controls"}]},{"id":"richtextblock-2","controlId":"richtextblock","controlName":"RichTextBlock","headerText":"A RichTextBlock with a custom selection highlight color.","xaml":"\u003CRichTextBlock SelectionHighlightColor=\u0022Green\u0022\u003E\n \u003CParagraph\u003ERichTextBlock provides a rich text display container that supports\n \u003CRun FontStyle=\u0022Italic\u0022 FontWeight=\u0022Bold\u0022\u003Eformatted text\u003C/Run\u003E,\n \u003CHyperlink NavigateUri=\u0022https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Documents.Hyperlink\u0022\u003Ehyperlinks\u003C/Hyperlink\u003E, inline images, and other rich content.\u003C/Paragraph\u003E\n \u003CParagraph\u003ERichTextBlock also supports a built-in overflow model.\u003C/Paragraph\u003E\n\u003C/RichTextBlock\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A control that displays formatted text, hyperlinks, inline images, and other rich content.","relatedControls":["NumberBox","TextBlock","TextBox","PasswordBox","RichEditBox"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"RichTextBlock - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.richtextblock"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/text-controls"}]},{"id":"richtextblock-3","controlId":"richtextblock","controlName":"RichTextBlock","headerText":"A RichTextBlock with overflow.","xaml":"\u003CGrid\u003E\n \u003CGrid.ColumnDefinitions\u003E\n \u003CColumnDefinition/\u003E\n \u003CColumnDefinition/\u003E\n \u003CColumnDefinition/\u003E\n \u003CGrid.ColumnDefinitions\u003E\n \u003CRichTextBlock Grid.Column=\u00220\u0022 OverflowContentTarget=\u0022{x:Bind firstOverflowContainer}\u0022 TextAlignment=\u0022Justify\u0022 Margin=\u002212,0\u0022\u003E\n \u003CParagraph\u003E\n Linked text containers allow text which does not fit in one element to overflow into a different element on the page.\n Creative use of linked text containers enables basic multicolumn support and other advanced page layouts.\n \u003C/Paragraph\u003E\n \u003C!-- Additional content not shown. --\u003E\n \u003C/RichTextBlock\u003E\n \u003CRichTextBlockOverflow x:Name=\u0022firstOverflowContainer\u0022 OverflowContentTarget=\u0022{x:Bind secondOverflowContainer}\u0022 Grid.Column=\u00221\u0022 Margin=\u002212,0\u0022/\u003E\n \u003CRichTextBlockOverflow x:Name=\u0022secondOverflowContainer\u0022 Grid.Column=\u00222\u0022 Margin=\u002212,0\u0022/\u003E\n\u003C/Grid\u003E\u003C/Grid.ColumnDefinitions\u003E\u003C/Grid.ColumnDefinitions\u003E\u003C/Grid\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A control that displays formatted text, hyperlinks, inline images, and other rich content.","relatedControls":["NumberBox","TextBlock","TextBox","PasswordBox","RichEditBox"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"RichTextBlock - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.richtextblock"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/text-controls"}]},{"id":"richtextblock-4","controlId":"richtextblock","controlName":"RichTextBlock","headerText":"RichTextBlock with custom TextHighlighting","xaml":"\u003CRichTextBlock x:Name=\u0022TextHighlightingRichTextBlock\u0022\u003E\n \u003CParagraph\u003E\n Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua\n \u003C/Paragraph\u003E\n\u003C/RichTextBlock\u003E","csharp":"private void HighlightColorCombobox_SelectionChanged(object sender, SelectionChangedEventArgs e)\n{\n // Get color to use\n var selectedItem = (sender as ComboBox).SelectedItem as ComboBoxItem;\n var color = Colors.Yellow;\n switch (selectedItem.Content as string)\n {\n case \u0022Yellow\u0022:\n color = Colors.Yellow;\n break;\n case \u0022Red\u0022:\n color = Colors.Red;\n break;\n case \u0022Blue\u0022:\n color = Colors.Blue;\n break;\n }\n\n // Get text range and highlighter\n TextRange textRange = new TextRange()\n {\n StartIndex = 28,\n Length = 11\n };\n TextHighlighter highlighter = new TextHighlighter()\n {\n Background = new SolidColorBrush(color),\n Ranges = { textRange }\n };\n\n // Switch texthighlighter\n TextHighlightingRichTextBlock.TextHighlighters.Clear();\n TextHighlightingRichTextBlock.TextHighlighters.Add(highlighter);\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A control that displays formatted text, hyperlinks, inline images, and other rich content.","relatedControls":["NumberBox","TextBlock","TextBox","PasswordBox","RichEditBox"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"RichTextBlock - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.richtextblock"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/text-controls"}]},{"id":"textblock-1","controlId":"textblock","controlName":"TextBlock","headerText":"A simple TextBlock.","xaml":"\u003CTextBlock Text=\u0022I am a TextBlock\u0022/\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A lightweight control for displaying small amounts of text.","relatedControls":["NumberBox","TextBox","RichTextBlock","PasswordBox","RichEditBox"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"TextBlock - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textblock"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/text-controls"}]},{"id":"textblock-2","controlId":"textblock","controlName":"TextBlock","headerText":"A TextBlock with a style applied.","xaml":"\u003CPage.Resources\u003E\n \u003CStyle TargetType=\u0022TextBlock\u0022 x:Key=\u0022CustomTextBlockStyle\u0022\u003E\n \u003CSetter Property=\u0022FontFamily\u0022 Value=\u0022Comic Sans MS\u0022/\u003E\n \u003CSetter Property=\u0022FontStyle\u0022 Value=\u0022Italic\u0022/\u003E\n \u003C/Style\u003E\n\u003CPage.Resources\u003E\n\n\u003CTextBlock Text=\u0022I am a styled TextBlock\u0022 Style=\u0022{StaticResource CustomTextBlockStyle}\u0022/\u003E\u003C/Page.Resources\u003E\u003C/Page.Resources\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A lightweight control for displaying small amounts of text.","relatedControls":["NumberBox","TextBox","RichTextBlock","PasswordBox","RichEditBox"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"TextBlock - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textblock"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/text-controls"}]},{"id":"textblock-3","controlId":"textblock","controlName":"TextBlock","headerText":"A TextBlock with various properties set.","xaml":"\u003CTextBlock Text=\u0022I am super excited to be here!\u0022 FontFamily=\u0022Arial\u0022\n FontSize=\u002224\u0022 FontStyle=\u0022Italic\u0022 TextWrapping=\u0022WrapWholeWords\u0022\n CharacterSpacing=\u0022200\u0022 Foreground=\u0022CornflowerBlue\u0022 /\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A lightweight control for displaying small amounts of text.","relatedControls":["NumberBox","TextBox","RichTextBlock","PasswordBox","RichEditBox"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"TextBlock - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textblock"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/text-controls"}]},{"id":"textblock-4","controlId":"textblock","controlName":"TextBlock","headerText":"A TextBlock with inline text elements.","xaml":"\u003CTextBlock\u003E\n \u003CRun FontFamily=\u0022Times New Roman\u0022 Foreground=\u0022DarkGray\u0022\u003EText in a TextBlock doesn\u0027t have to be a simple string.\u003C/Run\u003E\n \u003CLineBreak /\u003E\n \u003CSpan\u003E\n Text can be \u003CBold\u003Ebold\u003C/Bold\u003E, \u003CItalic\u003Eitalic\u003C/Italic\u003E, or \u003CUnderline\u003Eunderlined\u003C/Underline\u003E.\n \u003C/Span\u003E\n\u003C/TextBlock\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A lightweight control for displaying small amounts of text.","relatedControls":["NumberBox","TextBox","RichTextBlock","PasswordBox","RichEditBox"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"TextBlock - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textblock"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/text-controls"}]},{"id":"textblock-5","controlId":"textblock","controlName":"TextBlock","headerText":"A selectable TextBlock","xaml":"\u003CTextBlock IsTextSelectionEnabled=\u0022...\u0022\n Text=\u0022I am a selectable TextBlock with custom SelectionHighlightColor.\u0022\n SelectionHighlightColor=\u0022DarkOrange\u0022\u003E\u003C/TextBlock\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A lightweight control for displaying small amounts of text.","relatedControls":["NumberBox","TextBox","RichTextBlock","PasswordBox","RichEditBox"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"TextBlock - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textblock"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/text-controls"}]},{"id":"textbox-1","controlId":"textbox","controlName":"TextBox","headerText":"A simple TextBox.","xaml":"\u003CTextBox AutomationProperties.Name=\u0022simple TextBox\u0022/\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A single-line or multi-line plain text field.","relatedControls":["NumberBox","TextBlock","RichTextBlock","PasswordBox","RichEditBox","AutoSuggestBox"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"TextBox - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/text-controls"}]},{"id":"textbox-2","controlId":"textbox","controlName":"TextBox","headerText":"A TextBox with a header and placeholder text.","xaml":"\u003CTextBox Header=\u0022Enter your name:\u0022 PlaceholderText=\u0022Name\u0022 /\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A single-line or multi-line plain text field.","relatedControls":["NumberBox","TextBlock","RichTextBlock","PasswordBox","RichEditBox","AutoSuggestBox"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"TextBox - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/text-controls"}]},{"id":"textbox-3","controlId":"textbox","controlName":"TextBox","headerText":"A read-only TextBox with various properties set.","xaml":"\u003CTextBox Text=\u0022I am super excited to be here!\u0022\n AutomationProperties.Name=\u0022customized TextBox\u0022 IsReadOnly=\u0022True\u0022\n FontFamily=\u0022Arial\u0022 FontSize=\u002224\u0022 FontStyle=\u0022Italic\u0022\n CharacterSpacing=\u0022200\u0022 Foreground=\u0022#5178BE\u0022 /\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A single-line or multi-line plain text field.","relatedControls":["NumberBox","TextBlock","RichTextBlock","PasswordBox","RichEditBox","AutoSuggestBox"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"TextBox - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/text-controls"}]},{"id":"textbox-4","controlId":"textbox","controlName":"TextBox","headerText":"A multi-line TextBox with spell checking and custom selection highlight color.","xaml":"\u003CTextBox AutomationProperties.Name=\u0022multi-line TextBox\u0022\n TextWrapping=\u0022Wrap\u0022 AcceptsReturn=\u0022True\u0022 IsSpellCheckEnabled=\u0022True\u0022\n SelectionHighlightColor=\u0022Green\u0022 MinWidth=\u0022400\u0022 /\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A single-line or multi-line plain text field.","relatedControls":["NumberBox","TextBlock","RichTextBlock","PasswordBox","RichEditBox","AutoSuggestBox"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"TextBox - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/controls/text-controls"}]},{"id":"xamlcompinterop-1","controlId":"xamlcompinterop","controlName":"Animation interop","headerText":"Use a natural motion composition animation on a UIElement","xaml":null,"csharp":"Compositor _compositor = Microsoft.UI.Xaml.Media.CompositionTarget.GetCompositorForCurrentThread();\nSpringVector3NaturalMotionAnimation? _springAnimation;\n\nprivate void CreateOrUpdateSpringAnimation(float finalValue)\n{\n if (_springAnimation == null)\n {\n _springAnimation = _compositor.CreateSpringVector3Animation();\n _springAnimation.Target = \u0022Scale\u0022;\n }\n\n _springAnimation.FinalValue = new Vector3(finalValue);\n}\n\nprivate void element_PointerEntered(object sender, PointerRoutedEventArgs e)\n{\n // Scale up to 1.5\n CreateOrUpdateSpringAnimation(1.5f);\n\n (sender as UIElement)?.StartAnimation(_springAnimation);\n}\n\nprivate void element_PointerExited(object sender, PointerRoutedEventArgs e)\n{\n // Scale back down to 1.0\n CreateOrUpdateSpringAnimation(1.0f);\n\n (sender as UIElement)?.StartAnimation(_springAnimation);\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"XAML and Composition interop allows you to animate elements using expressions, natural animations, and more.","relatedControls":["EasingFunction"],"apiNamespace":null,"docs":[{"title":"Quickstart: Motion","uri":"https://learn.microsoft.com/windows/apps/design/motion"},{"title":"Composition Animation - API","uri":"https://learn.microsoft.com/windows/apps/windows-app-sdk/composition"},{"title":"Guidelines - Xaml Property Animations","uri":"https://learn.microsoft.com/windows/apps/design/motion/xaml-property-animations"}]},{"id":"xamlcompinterop-2","controlId":"xamlcompinterop","controlName":"Animation interop","headerText":"ExpressionAnimation on an Ellipse element","xaml":"\u003CStackPanel Height=\u0022200\u0022\u003E\n \u003CGrid VerticalAlignment=\u0022Top\u0022\u003E\n \u003CGrid.ColumnDefinitions\u003E\n \u003CColumnDefinition Width=\u0022*\u0022 /\u003E\n \u003CColumnDefinition Width=\u0022*\u0022 /\u003E\n \u003C/Grid.ColumnDefinitions\u003E\n \u003CRectangle x:Name=\u0022rectangle\u0022 Width=\u002250\u0022 Height=\u002250\u0022 Fill=\u0022{ThemeResource SystemAccentColor}\u0022 PointerEntered=\u0022element_PointerEntered\u0022 PointerExited=\u0022element_PointerExited\u0022 /\u003E\n \u003CEllipse x:Name=\u0022ellipse\u0022 Grid.Column=\u00221\u0022 Width=\u002250\u0022 Height=\u002250\u0022 Margin=\u002255,0\u0022 Fill=\u0022{ThemeResource SystemAccentColor}\u0022/\u003E\n \u003C/Grid\u003E\n\u003C/StackPanel\u003E","csharp":"// NOTE: The rectangle scales up and down using the same element_PointerEntered/Exited events as the prior sample.\n\nCompositor _compositor = Microsoft.UI.Xaml.Media.CompositionTarget.GetCompositorForCurrentThread();\n\n// Set up the relationship between the rectangle and the ellipse.\nprivate void ExpressionSample_Loaded(object sender, RoutedEventArgs e)\n{\n var expressionAnim = _compositor.CreateExpressionAnimation();\n\n // The ellipse\u0027s scale is inversely proportional to the rectangle\u0027s scale\n expressionAnim.Expression = \u0022Vector3(1/scaleElement.Scale.X, 1/scaleElement.Scale.Y, 1)\u0022;\n expressionAnim.Target = \u0022Scale\u0022;\n\n // Use SetExpressionReferenceParameter to alias a UIElement into the expression string\n expressionAnim.SetExpressionReferenceParameter(\u0022scaleElement\u0022, rectangle);\n\n // Start the animation on the ellipse\n ellipse.StartAnimation(expressionAnim);\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"XAML and Composition interop allows you to animate elements using expressions, natural animations, and more.","relatedControls":["EasingFunction"],"apiNamespace":null,"docs":[{"title":"Quickstart: Motion","uri":"https://learn.microsoft.com/windows/apps/design/motion"},{"title":"Composition Animation - API","uri":"https://learn.microsoft.com/windows/apps/windows-app-sdk/composition"},{"title":"Guidelines - Xaml Property Animations","uri":"https://learn.microsoft.com/windows/apps/design/motion/xaml-property-animations"}]},{"id":"xamlcompinterop-3","controlId":"xamlcompinterop","controlName":"Animation interop","headerText":"Driving several related animations together using ExpressionAnimation","xaml":null,"csharp":"// NOTE: Each of the buttons scale up and down using the same element_PointerEntered/Exited events as the prior samples.\n\nprivate void StackedButtonsExample_Loaded(object sender, RoutedEventArgs e)\n{\n // Animate the translation of each button relative to the scale and translation of the button above.\n var anim = _compositor.CreateExpressionAnimation();\n anim.Expression = \u0022(above.Scale.Y - 1) * 50 \u002B above.Translation.Y % (50 * index)\u0022;\n anim.Target = \u0022Translation.Y\u0022;\n\n // Animate the second button relative to the first.\n anim.SetExpressionReferenceParameter(\u0022above\u0022, ExpressionButton1);\n anim.SetScalarParameter(\u0022index\u0022, 1);\n ExpressionButton2.StartAnimation(anim);\n\n // Animate the third button relative to the second.\n anim.SetExpressionReferenceParameter(\u0022above\u0022, ExpressionButton2);\n anim.SetScalarParameter(\u0022index\u0022, 2);\n ExpressionButton3.StartAnimation(anim);\n\n // Animate the fourth button relative to the third.\n anim.SetExpressionReferenceParameter(\u0022above\u0022, ExpressionButton3);\n anim.SetScalarParameter(\u0022index\u0022, 3);\n ExpressionButton4.StartAnimation(anim);\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"XAML and Composition interop allows you to animate elements using expressions, natural animations, and more.","relatedControls":["EasingFunction"],"apiNamespace":null,"docs":[{"title":"Quickstart: Motion","uri":"https://learn.microsoft.com/windows/apps/design/motion"},{"title":"Composition Animation - API","uri":"https://learn.microsoft.com/windows/apps/windows-app-sdk/composition"},{"title":"Guidelines - Xaml Property Animations","uri":"https://learn.microsoft.com/windows/apps/design/motion/xaml-property-animations"}]},{"id":"xamlcompinterop-4","controlId":"xamlcompinterop","controlName":"Animation interop","headerText":"Reference ActualSize in ExpressionAnimations to make novel layouts based on size","xaml":null,"csharp":"private void ActualSizeExample_Loaded(object sender, RoutedEventArgs e)\n{\n // We will lay out some buttons in a circle.\n // The formulas we will use are:\n // X = radius * cos(theta) \u002B xOffset\n // Y = radius * sin(theta) \u002B yOffset\n // radius = 1/2 the width and height of the parent container\n // theta = the angle for each element. The starting value of theta depends on both the number of elements and the relative index of each element.\n // xOffset = The starting horizontal offset for the element. \n // yOffset = The starting vertical offset for the element.\n\n String radius = \u0022(source.ActualSize.X / 2)\u0022; // Since the layout is a circle, width and height are equivalent meaning we could use X or Y. We\u0027ll use X.\n String theta = \u0022.02 * \u0022 \u002B radius \u002B \u0022 \u002B ((2 * Pi)/total)*index\u0022; // The first value is the rate of angular change based on radius. The last value spaces the buttons equally.\n String xOffset = radius; // We offset x by radius because the buttons naturally layout along the left edge. We need to move them to center of the circle first.\n String yOffset = \u00220\u0022; // We don\u0027t need to offset y because the buttons naturally layout vertically centered.\n\n // We combine X, Y, and Z subchannels into a single animation because we can only start a single animation on Translation.\n String expression = String.Format(\u0022Vector3({0}*cos({1})\u002B{2}, {0}*sin({1})\u002B{3},0)\u0022, radius, theta, xOffset, yOffset);\n\n int totalElements = 8;\n for (int i = 0; i \u003C totalElements; i\u002B\u002B)\n {\n Button element = new Button() { Content = \u0022Button\u0022 \u002B i };\n LayoutPanel.Children.Add(element);\n\n var anim = _compositor.CreateExpressionAnimation();\n\n anim.Expression = expression;\n anim.SetScalarParameter(\u0022index\u0022, i \u002B 1);\n anim.SetScalarParameter(\u0022total\u0022, totalElements);\n anim.Target = \u0022Translation\u0022;\n anim.SetExpressionReferenceParameter(\u0022source\u0022, LayoutPanel);\n\n element.StartAnimation(anim);\n }\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"XAML and Composition interop allows you to animate elements using expressions, natural animations, and more.","relatedControls":["EasingFunction"],"apiNamespace":null,"docs":[{"title":"Quickstart: Motion","uri":"https://learn.microsoft.com/windows/apps/design/motion"},{"title":"Composition Animation - API","uri":"https://learn.microsoft.com/windows/apps/windows-app-sdk/composition"},{"title":"Guidelines - Xaml Property Animations","uri":"https://learn.microsoft.com/windows/apps/design/motion/xaml-property-animations"}]},{"id":"xamlcompinterop-5","controlId":"xamlcompinterop","controlName":"Animation interop","headerText":"Reference ActualOffset and ActualSize in ExpressionAnimations to position elements relative to each other","xaml":"\u003CGrid HorizontalAlignment=\u0022Left\u0022 Margin=\u00220,12,0,0\u0022\u003E\n \u003CTextBlock x:Name=\u0022PopupTarget\u0022 \n TextWrapping=\u0022WrapWholeWords\u0022 \n Margin=\u0022{x:Bind MarginSlider.Value, Converter={StaticResource doubleToThicknessConverter}, Mode=OneWay}\u0022 \n FontSize=\u0022{x:Bind FontSizeSlider.Value, Mode=OneWay}\u0022 \n Text=\u0022... lorem ipsum ...\u0022 /\u003E\n\n \u003C!-- Notice that the popup is a sibling to the target, not an ancestor. --\u003E\n \u003CPopup x:Name=\u0022Popup\u0022 Margin=\u00225\u0022\u003E\n \u003CGrid MinWidth=\u002250\u0022 MaxWidth=\u0022200\u0022 MinHeight=\u002250\u0022 BorderBrush=\u0022LightGray\u0022 BorderThickness=\u00222\u0022 Background=\u0022{ThemeResource FlyoutBackgroundThemeBrush}\u0022\u003E\n \u003CTextBlock Text=\u0022I am always right aligned center to the target.\u0022 TextWrapping=\u0022WrapWholeWords\u0022 Margin=\u00226\u0022 FontSize=\u002212\u0022 VerticalAlignment=\u0022Center\u0022 /\u003E\n \u003C/Grid\u003E\n \u003C/Popup\u003E\n\u003C/Grid\u003E","csharp":"private void ActualOffsetExample_Loaded(object sender, RoutedEventArgs e)\n{\n // This sample positions a popup relative to a block of text that has variable layout size based on font size.\n var anim = _compositor.CreateExpressionAnimation();\n\n anim.Expression = \u0022Vector3(source.ActualOffset.X \u002B source.ActualSize.X, source.ActualOffset.Y \u002B source.ActualSize.Y / 2 - 25, 0)\u0022;\n anim.Target = \u0022Translation\u0022;\n anim.SetExpressionReferenceParameter(\u0022source\u0022, PopupTarget);\n\n Popup.StartAnimation(anim);\n\n Popup.IsOpen = true;\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"XAML and Composition interop allows you to animate elements using expressions, natural animations, and more.","relatedControls":["EasingFunction"],"apiNamespace":null,"docs":[{"title":"Quickstart: Motion","uri":"https://learn.microsoft.com/windows/apps/design/motion"},{"title":"Composition Animation - API","uri":"https://learn.microsoft.com/windows/apps/windows-app-sdk/composition"},{"title":"Guidelines - Xaml Property Animations","uri":"https://learn.microsoft.com/windows/apps/design/motion/xaml-property-animations"}]},{"id":"connectedanimation-1","controlId":"connectedanimation","controlName":"Connected Animation","headerText":"A connected animation between a list page and a detail page","xaml":"\u003C!-- COLLECTION PAGE BELOW--\u003E\n\u003CListView x:Name=\u0022collection\u0022\n IsItemClickEnabled=\u0022True\u0022\n SelectionMode=\u0022None\u0022\n ItemClick=\u0022collection_ItemClick\u0022\n Grid.Row=\u00222\u0022 \u003E\n \u003CListView.ItemTemplate\u003E\n \u003CDataTemplate x:DataType=\u0022local:CustomDataObject\u0022\u003E\n \u003CGrid Margin=\u00220,12,0,12\u0022 AutomationProperties.Name=\u0022{x:Bind Title}\u0022\u003E\n \u003CGrid.ColumnDefinitions\u003E\n \u003CColumnDefinition Width=\u0022Auto\u0022 MinWidth=\u0022150\u0022/\u003E\n \u003CColumnDefinition Width=\u0022*\u0022 /\u003E\n \u003C/Grid.ColumnDefinitions\u003E\n\n \u003C!-- The image to connect between pages. --\u003E\n \u003CImage x:Name=\u0022connectedElement\u0022 Source=\u0022{x:Bind ImageLocation}\u0022 MaxHeight=\u0022100\u0022 Stretch=\u0022Fill\u0022/\u003E\n\n \u003CStackPanel Margin=\u002212,0,0,0\u0022 Grid.Column=\u00221\u0022 \u003E\n \u003CTextBlock Text=\u0022{x:Bind Title}\u0022 Style=\u0022{ThemeResource SubtitleTextBlockStyle}\u0022 HorizontalAlignment=\u0022Left\u0022 Margin=\u00220,0,0,6\u0022/\u003E\n \u003CStackPanel Orientation=\u0022Horizontal\u0022\u003E\n \u003CTextBlock Text=\u0022Views: \u0022 Style=\u0022{ThemeResource CaptionTextBlockStyle}\u0022 FontWeight=\u0022Bold\u0022/\u003E\n \u003CTextBlock Text=\u0022{x:Bind Views}\u0022 Style=\u0022{ThemeResource CaptionTextBlockStyle}\u0022 Margin=\u00225,0,0,0\u0022/\u003E\n \u003C/StackPanel\u003E\n \u003CStackPanel Orientation=\u0022Horizontal\u0022\u003E\n \u003CTextBlock Text=\u0022Likes: \u0022 Style=\u0022{ThemeResource CaptionTextBlockStyle}\u0022 FontWeight=\u0022Bold\u0022/\u003E\n \u003CTextBlock Text=\u0022{x:Bind Likes}\u0022 Style=\u0022{ThemeResource CaptionTextBlockStyle}\u0022 Margin=\u00225,0,0,0\u0022/\u003E\n \u003C/StackPanel\u003E\n \u003CStackPanel Orientation=\u0022Horizontal\u0022\u003E\n \u003CTextBlock Text=\u0022{x:Bind Description}\u0022 Style=\u0022{ThemeResource BodyTextBlockStyle}\u0022 FontStyle=\u0022Italic\u0022 Margin=\u00220,12,0,0\u0022 TextTrimming=\u0022CharacterEllipsis\u0022 MaxWidth=\u0022500\u0022 MaxLines=\u00221\u0022/\u003E\n \u003C/StackPanel\u003E\n\n \u003C/StackPanel\u003E\n \u003C/Grid\u003E\n \u003C/DataTemplate\u003E\u003C/ListView.ItemTemplate\u003E\u003C/ListView\u003E\n\u003C!-- ...truncated --\u003E","csharp":"// To see the source code: \n// https://github.com/microsoft/WinUI-Gallery/blob/main/WinUIGallery/ConnectedAnimationPages/CollectionPage.xaml.cs\n// https://github.com/microsoft/WinUI-Gallery/blob/main/WinUIGallery/ConnectedAnimationPages/DetailedInfoPage.xaml.cs\n\n// COLLECTION PAGE\npublic sealed partial class CollectionPage : Page\n{\n CustomDataObject? _storeditem;\n\n public CollectionPage()\n {\n this.InitializeComponent();\n\n // Ensure that the MainPage is only created once, and cached during navigation.\n this.NavigationCacheMode = NavigationCacheMode.Enabled;\n\n collection.ItemsSource = WinUIGallery.ControlPages.CustomDataObject.GetDataObjects();\n }\n\n private async void collection_Loaded(object sender, RoutedEventArgs e)\n {\n if (_storeditem != null)\n {\n // If the connected item appears outside the viewport, scroll it into view.\n collection.ScrollIntoView(_storeditem, ScrollIntoViewAlignment.Default);\n collection.UpdateLayout();\n\n // Play the second connected animation. \n ConnectedAnimation animation = ConnectedAnimationService.GetForCurrentView().GetAnimation(\u0022BackConnectedAnimation\u0022);\n if (animation != null)\n {\n // Setup the \u0022back\u0022 configuration if the API is present. \n if (ApiInformation.IsApiContractPresent(\u0022Windows.Foundation.UniversalApiContract\u0022, 7))\n {\n animation.Configuration = new DirectConnectedAnimationConfiguration();\n }\n\n await collection.TryStartConnectedAnimationAsync(animation, _storeditem, \u0022connectedElement\u0022);\n }\n\n // Set focus on the list\n collection.Focus(FocusState.Programmatic);\n }\n }\n\n private void collection_ItemClick(object sender, ItemClickEventArgs e)\n {\n // Get the collection item corresponding to the clicked item.\n if (collection.ContainerFromItem(e.ClickedItem) is ListViewItem container)\n {\n // Stash the clicked item for use later. We\u0027ll need it when we connect back from the detailpage.\n _storeditem = container.Content as CustomDataObject;\n\n // Prepare the connected animation.\n // Notice that the stored item is passed in, as well as the name of the connected element. \n // The animation will actually start on the Detailed info page.\n collection.PrepareConnectedAnimation(\u0022ForwardConnectedAnimation\u0022, _storeditem, \u0022connectedElement\u0022);\n }\n\n // Navigate to the DetailedInfoPage.\n // Note that we suppress the default animation.\n}}\n// NOTE: snippet truncated \u2014 refer to full sample for additional code","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Connected animations continue elements during page navigation and help the user maintain their context between views.","relatedControls":["PageTransition","ThemeTransition"],"apiNamespace":"Microsoft.UI.Xaml.Media.Animation","docs":[{"title":"ConnectedAnimation - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.animation.connectedanimation"},{"title":"ConnectedAnimationService - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.animation.connectedanimationservice"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/motion/connected-animation"},{"title":"Quickstart: Motion","uri":"https://learn.microsoft.com/windows/apps/design/motion"}]},{"id":"connectedanimation-2","controlId":"connectedanimation","controlName":"Connected Animation","headerText":"A connected animation between elements on the same page","xaml":"\u003CGridView x:Name=\u0022collection\u0022 IsItemClickEnabled=\u0022True\u0022 ItemClick=\u0022TipsGrid_ItemClick\u0022\n HorizontalAlignment=\u0022Center\u0022 MaxWidth=\u00221400\u0022\u003E\n \u003CGridView.ItemContainerStyle\u003E\n \u003CStyle BasedOn=\u0022{StaticResource GridViewItemRevealStyle}\u0022 TargetType=\u0022GridViewItem\u0022\u003E\n \u003CStyle.Setters\u003E\n \u003CSetter Property=\u0022Margin\u0022 Value=\u00224\u0022 /\u003E\n \u003C/Style.Setters\u003E\n \u003C/Style\u003E\n \u003C/GridView.ItemContainerStyle\u003E\n \u003CGridView.ItemTemplate\u003E\n \u003CDataTemplate\u003E\n \u003CGrid x:Name=\u0022connectedElement\u0022 Width=\u0022150\u0022 Height=\u0022110\u0022\n AutomationProperties.Name=\u0022{Binding Title}\u0022 CornerRadius=\u00224\u0022\u003E\n \u003CImage Source=\u0022{Binding ImageLocation}\u0022 Stretch=\u0022UniformToFill\u0022 /\u003E\n \u003CBorder Padding=\u00228,4\u0022 VerticalAlignment=\u0022Bottom\u0022\n Background=\u0022{ThemeResource AcrylicBackgroundFillColorBaseBrush}\u0022\u003E\n \u003CTextBlock Style=\u0022{ThemeResource CaptionTextBlockStyle}\u0022 Text=\u0022{Binding Title}\u0022 /\u003E\n \u003C/Border\u003E\n \u003C/Grid\u003E\n \u003C/DataTemplate\u003E\n \u003C/GridView.ItemTemplate\u003E\n\u003C/GridView\u003E\n\n\u003CGrid x:Name=\u0022SmokeGrid\u0022 HorizontalAlignment=\u0022Stretch\u0022 VerticalAlignment=\u0022Stretch\u0022\n Background=\u0022{ThemeResource SmokeFillColorDefaultBrush}\u0022 Visibility=\u0022Collapsed\u0022\u003E\n \u003CGrid x:Name=\u0022destinationElement\u0022 Width=\u0022400\u0022 Height=\u0022320\u0022\n HorizontalAlignment=\u0022Center\u0022 VerticalAlignment=\u0022Center\u0022\n BorderBrush=\u0022{ThemeResource CardStrokeColorDefaultBrush}\u0022 BorderThickness=\u00221\u0022\n CornerRadius=\u00228\u0022\u003E\n \u003CGrid.RowDefinitions\u003E\n \u003CRowDefinition Height=\u0022*\u0022 /\u003E\n \u003CRowDefinition Height=\u0022Auto\u0022 /\u003E\n \u003C/Grid.RowDefinitions\u003E\n \u003CImage x:Name=\u0022detailImage\u0022 Grid.Row=\u00220\u0022 Stretch=\u0022UniformToFill\u0022 /\u003E\n \u003CButton Width=\u002236\u0022 Height=\u002236\u0022 Margin=\u00228\u0022\n HorizontalAlignment=\u0022Right\u0022 VerticalAlignment=\u0022Top\u0022\n AutomationProperties.Name=\u0022Close\u0022 Click=\u0022BackButton_Click\u0022\n ToolTipService.ToolTip=\u0022Close\u0022\u003E\n \u003CButton.Content\u003E\u003C/Button.Content\u003E\u003C/Button\u003E\u003C/Grid\u003E\u003C/Grid\u003E\n\u003C!-- ...truncated --\u003E","csharp":"public sealed partial class CardPage : Page\n{\n CustomDataObject? _storedItem;\n\n public CardPage()\n {\n this.InitializeComponent();\n collection.ItemsSource = CustomDataObject.GetDataObjects(includeAllItems: true);\n }\n\n private async void BackButton_Click(object sender, RoutedEventArgs e)\n {\n ConnectedAnimation animation = ConnectedAnimationService.GetForCurrentView()\n .PrepareToAnimate(\u0022backwardsAnimation\u0022, destinationElement);\n SmokeGrid.Children.Remove(destinationElement);\n\n // Collapse the smoke when the animation completes.\n animation.Completed \u002B= Animation_Completed;\n\n // If the connected item appears outside the viewport, scroll it into view.\n collection.ScrollIntoView(_storedItem, ScrollIntoViewAlignment.Default);\n collection.UpdateLayout();\n\n animation.Configuration = new DirectConnectedAnimationConfiguration();\n\n // Play the connected animation back to the collection.\n await collection.TryStartConnectedAnimationAsync(animation, _storedItem, \u0022connectedElement\u0022);\n }\n\n private void Animation_Completed(ConnectedAnimation sender, object args)\n {\n SmokeGrid.Visibility = Visibility.Collapsed;\n SmokeGrid.Children.Add(destinationElement);\n }\n\n private void TipsGrid_ItemClick(object sender, ItemClickEventArgs e)\n {\n ConnectedAnimation? animation = null;\n\n if (collection.ContainerFromItem(e.ClickedItem) is GridViewItem container)\n {\n _storedItem = container.Content as CustomDataObject;\n animation = collection.PrepareConnectedAnimation(\u0022forwardAnimation\u0022, _storedItem, \u0022connectedElement\u0022);\n }\n\n // Update the detail view with the clicked item\u0027s data.\n if (_storedItem != null)\n {\n detailImage.Source = new BitmapImage(new Uri(\u0022ms-appx://\u0022 \u002B _storedItem.ImageLocation));\n detailTitle.Text = _storedItem.Title;\n detailDescription.Text = _storedItem.Description;\n }\n\n SmokeGrid.Visibility = Visibility.Visible;\n animation?.TryStart(destinationElement);\n }\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Connected animations continue elements during page navigation and help the user maintain their context between views.","relatedControls":["PageTransition","ThemeTransition"],"apiNamespace":"Microsoft.UI.Xaml.Media.Animation","docs":[{"title":"ConnectedAnimation - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.animation.connectedanimation"},{"title":"ConnectedAnimationService - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.animation.connectedanimationservice"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/motion/connected-animation"},{"title":"Quickstart: Motion","uri":"https://learn.microsoft.com/windows/apps/design/motion"}]},{"id":"connectedanimation-3","controlId":"connectedanimation","controlName":"Connected Animation","headerText":"A simple connected animation","xaml":null,"csharp":"// Prepare animation on Source page\nprivate void NavigateButton_Click(object sender, RoutedEventArgs e)\n{\n ConnectedAnimationService.GetForCurrentView().PrepareToAnimate(\u0022ForwardConnectedAnimation\u0022, SourceElement);\n Frame.Navigate(typeof(DestinationPage), null, new SuppressNavigationTransitionInfo());\n}\n\n// Start animation on Destination page\nprotected override void OnNavigatedTo(NavigationEventArgs e)\n{\n base.OnNavigatedTo(e);\n\n var anim = ConnectedAnimationService.GetForCurrentView().GetAnimation(\u0022ForwardConnectedAnimation\u0022);\n if (anim != null)\n {\n anim.TryStart(DestinationElement);\n }\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Connected animations continue elements during page navigation and help the user maintain their context between views.","relatedControls":["PageTransition","ThemeTransition"],"apiNamespace":"Microsoft.UI.Xaml.Media.Animation","docs":[{"title":"ConnectedAnimation - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.animation.connectedanimation"},{"title":"ConnectedAnimationService - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.animation.connectedanimationservice"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/motion/connected-animation"},{"title":"Quickstart: Motion","uri":"https://learn.microsoft.com/windows/apps/design/motion"}]},{"id":"connectedanimation-4","controlId":"connectedanimation","controlName":"Connected Animation","headerText":"Connected animation with ItemsRepeater","xaml":"\u003C!-- Unlike ListView/GridView, ItemsRepeater does not have built-in\n ConnectedAnimation methods. Use ConnectedAnimationService directly. --\u003E\n\n\u003CScrollViewer x:Name=\u0022scrollViewer\u0022\u003E\n \u003CItemsRepeater\n x:Name=\u0022repeater\u0022\n ItemsSource=\u0022{x:Bind Items}\u0022\u003E\n \u003CItemsRepeater.Layout\u003E\n \u003CUniformGridLayout\n MinColumnSpacing=\u00228\u0022\n MinItemHeight=\u0022120\u0022\n MinItemWidth=\u0022150\u0022\n MinRowSpacing=\u00228\u0022 /\u003E\n \u003C/ItemsRepeater.Layout\u003E\n \u003CItemsRepeater.ItemTemplate\u003E\n \u003CDataTemplate x:DataType=\u0022local:CustomDataObject\u0022\u003E\n \u003CGrid CornerRadius=\u00224\u0022\u003E\n \u003C!-- The element named \u0022connectedElement\u0022 will be animated --\u003E\n \u003CImage x:Name=\u0022connectedElement\u0022\n Source=\u0022{x:Bind ImageLocation}\u0022\n Stretch=\u0022UniformToFill\u0022 /\u003E\n \u003CBorder VerticalAlignment=\u0022Bottom\u0022\n Background=\u0022{ThemeResource AcrylicBackgroundFillColorBaseBrush}\u0022\n Padding=\u00228,4\u0022\u003E\n \u003CTextBlock Text=\u0022{x:Bind Title}\u0022\n Style=\u0022{ThemeResource CaptionTextBlockStyle}\u0022 /\u003E\n \u003C/Border\u003E\n \u003C/Grid\u003E\n \u003C/DataTemplate\u003E\n \u003C/ItemsRepeater.ItemTemplate\u003E\n \u003C/ItemsRepeater\u003E\n\u003C/ScrollViewer\u003E","csharp":"// ItemsRepeater does not have PrepareConnectedAnimation() or\n// TryStartConnectedAnimationAsync() like ListView/GridView.\n// Use ConnectedAnimationService.PrepareToAnimate() directly instead.\n\nprivate CustomDataObject _storedItem;\nprivate double _persistedScrollPosition;\n\nprivate void Repeater_ElementPrepared(ItemsRepeater sender, ItemsRepeaterElementPreparedEventArgs args)\n{\n // Attach a Tapped handler to each item container.\n args.Element.Tapped -= Item_Tapped;\n args.Element.Tapped \u002B= Item_Tapped;\n}\n\nprivate void Item_Tapped(object sender, TappedRoutedEventArgs e)\n{\n var element = sender as FrameworkElement;\n _storedItem = repeater.ItemsSourceView.GetAt(\n repeater.GetElementIndex(element)) as CustomDataObject;\n\n // Find the named element in the DataTemplate and prepare the animation.\n if (FindChildByName(element, \u0022connectedElement\u0022) is UIElement source)\n {\n ConnectedAnimationService.GetForCurrentView()\n .PrepareToAnimate(\u0022ForwardConnectedAnimation\u0022, source);\n }\n\n // Save scroll position for back navigation.\n _persistedScrollPosition = scrollViewer.VerticalOffset;\n\n Frame.Navigate(typeof(DetailPage), _storedItem,\n new SuppressNavigationTransitionInfo());\n}\n\nprotected override void OnNavigatedTo(NavigationEventArgs e)\n{\n base.OnNavigatedTo(e);\n if (_storedItem == null) return;\n\n // Restore scroll position so the target element is visible.\n scrollViewer.ChangeView(null, _persistedScrollPosition, null, true);\n UpdateLayout();\n\n var animation = ConnectedAnimationService.GetForCurrentView()\n .GetAnimation(\u0022BackConnectedAnimation\u0022);\n if (animation != null)\n {\n animation.Configuration = new DirectConnectedAnimationConfiguration();\n\n int index = repeater.ItemsSourceView.IndexOf(_storedItem);\n if (repeater.TryGetElement(index) is FrameworkElement container\n \u0026\u0026 FindChildByName(container, \u0022connectedElement\u0022) is UIElement target)\n {\n animation.TryStart(target);\n }\n }\n}\n\n// Helper to find a named element within a DataTemplate.\nprivate static UIElement FindChildByName(DependencyObject parent, string name)\n{\n for (int i = 0; i \u003C VisualTreeHelper.GetChildrenCount(parent); i\u002B\u002B)\n {\n var child = VisualTreeHelper.GetChild(parent, i);\n if (child is FrameworkElement fe \u0026\u0026 fe.Name == name)\n return fe;\n var result = FindChildByName(child, name);\n if (result != null)\n return result;\n }\n return null;\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Connected animations continue elements during page navigation and help the user maintain their context between views.","relatedControls":["PageTransition","ThemeTransition"],"apiNamespace":"Microsoft.UI.Xaml.Media.Animation","docs":[{"title":"ConnectedAnimation - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.animation.connectedanimation"},{"title":"ConnectedAnimationService - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.animation.connectedanimationservice"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/motion/connected-animation"},{"title":"Quickstart: Motion","uri":"https://learn.microsoft.com/windows/apps/design/motion"}]},{"id":"easingfunction-1","controlId":"easingfunction","controlName":"Easing Functions","headerText":"Standard Easing Function","xaml":"\u003CStoryboard x:Name=\u0022Storyboard1\u0022\u003E\n \u003CDoubleAnimation Storyboard.TargetName=\u0022Translation\u0022 Storyboard.TargetProperty=\u0022X\u0022 From=\u00220\u0022 To=\u0022200\u0022 \u003E\n \u003CDoubleAnimation.EasingFunction\u003E\n \u003CCircleEase EasingMode=\u0022EaseInOut\u0022 /\u003E\n \u003C/DoubleAnimation.EasingFunction\u003E\n \u003C/DoubleAnimation\u003E\n\u003C/Storyboard\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Easing is a way to manipulate the velocity of an object as it animates.","relatedControls":["ConnectedAnimation","PageTransition","ThemeTransition"],"apiNamespace":"Microsoft.UI.Xaml.Media.Animation","docs":[{"title":"EasingFunctionBase - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.animation.easingfunctionbase"},{"title":"Timing and Easing","uri":"https://learn.microsoft.com/windows/apps/design/motion/timing-and-easing"},{"title":"Quickstart: Motion","uri":"https://learn.microsoft.com/windows/apps/design/motion"}]},{"id":"easingfunction-2","controlId":"easingfunction","controlName":"Easing Functions","headerText":"Accelerate Easing Function","xaml":"\u003CStoryboard x:Name=\u0022Storyboard2\u0022\u003E\n \u003CDoubleAnimation Storyboard.TargetName=\u0022Translation\u0022 Storyboard.TargetProperty=\u0022X\u0022 From=\u00220\u0022 To=\u0022200\u0022 \u003E\n \u003CDoubleAnimation.EasingFunction\u003E\n \u003CExponentialEase Exponent=\u0022...\u0022 EasingMode=\u0022EaseIn\u0022 /\u003E\n \u003C/DoubleAnimation.EasingFunction\u003E\n \u003C/DoubleAnimation\u003E\n\u003C/Storyboard\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Easing is a way to manipulate the velocity of an object as it animates.","relatedControls":["ConnectedAnimation","PageTransition","ThemeTransition"],"apiNamespace":"Microsoft.UI.Xaml.Media.Animation","docs":[{"title":"EasingFunctionBase - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.animation.easingfunctionbase"},{"title":"Timing and Easing","uri":"https://learn.microsoft.com/windows/apps/design/motion/timing-and-easing"},{"title":"Quickstart: Motion","uri":"https://learn.microsoft.com/windows/apps/design/motion"}]},{"id":"easingfunction-3","controlId":"easingfunction","controlName":"Easing Functions","headerText":"Decelerate Easing Function","xaml":"\u003CStoryboard x:Name=\u0022Storyboard3\u0022\u003E\n \u003CDoubleAnimation Storyboard.TargetName=\u0022Translation\u0022 Storyboard.TargetProperty=\u0022X\u0022 From=\u00220\u0022 To=\u0022200\u0022 \u003E\n \u003CDoubleAnimation.EasingFunction\u003E\n \u003CExponentialEase Exponent=\u0022...\u0022 EasingMode=\u0022EaseOut\u0022 /\u003E\n \u003C/DoubleAnimation.EasingFunction\u003E\n \u003C/DoubleAnimation\u003E\n\u003C/Storyboard\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Easing is a way to manipulate the velocity of an object as it animates.","relatedControls":["ConnectedAnimation","PageTransition","ThemeTransition"],"apiNamespace":"Microsoft.UI.Xaml.Media.Animation","docs":[{"title":"EasingFunctionBase - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.animation.easingfunctionbase"},{"title":"Timing and Easing","uri":"https://learn.microsoft.com/windows/apps/design/motion/timing-and-easing"},{"title":"Quickstart: Motion","uri":"https://learn.microsoft.com/windows/apps/design/motion"}]},{"id":"easingfunction-4","controlId":"easingfunction","controlName":"Easing Functions","headerText":"Other XAML Easing Functions","xaml":"\u003CStoryboard x:Name=\u0022Storyboard3\u0022\u003E\n \u003CDoubleAnimation Storyboard.TargetName=\u0022Translation\u0022 Storyboard.TargetProperty=\u0022X\u0022 From=\u00220\u0022 To=\u0022200\u0022 \u003E\n \u003CDoubleAnimation.EasingFunction\u003E\n \u003C.../\u003E\n \u003C/DoubleAnimation.EasingFunction\u003E\n \u003C/DoubleAnimation\u003E\n\u003C/Storyboard\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Easing is a way to manipulate the velocity of an object as it animates.","relatedControls":["ConnectedAnimation","PageTransition","ThemeTransition"],"apiNamespace":"Microsoft.UI.Xaml.Media.Animation","docs":[{"title":"EasingFunctionBase - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.animation.easingfunctionbase"},{"title":"Timing and Easing","uri":"https://learn.microsoft.com/windows/apps/design/motion/timing-and-easing"},{"title":"Quickstart: Motion","uri":"https://learn.microsoft.com/windows/apps/design/motion"}]},{"id":"implicittransition-1","controlId":"implicittransition","controlName":"Implicit Transitions","headerText":"Automatically animate changes to Opacity","xaml":"\u003C!-- Automatically animate changes to Opacity --\u003E\n\u003CRectangle x:Name=\u0022rectangle\u0022 Width=\u002250\u0022 Height=\u002250\u0022 Opacity=\u00220.5\u0022\u003E\n \u003CRectangle.OpacityTransition\u003E\n \u003CScalarTransition /\u003E\n \u003C/Rectangle.OpacityTransition\u003E\n\u003C/Rectangle\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Use Implicit Transitions to automatically animate changes to properties.","relatedControls":["PageTransition","ThemeTransition"],"apiNamespace":"Microsoft.UI.Xaml","docs":[{"title":"Transitions - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.transitions#Windows_UI_Xaml_UIElement_Transitions"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/motion/motion-in-practice#implicit-animations"},{"title":"Quickstart: Motion","uri":"https://learn.microsoft.com/windows/apps/design/motion"}]},{"id":"implicittransition-2","controlId":"implicittransition","controlName":"Implicit Transitions","headerText":"Automatically animate changes to Rotation","xaml":"\u003C!-- Automatically animate changes to Rotation --\u003E\n\u003CRectangle x:Name=\u0022rectangle\u0022 Width=\u002250\u0022 Height=\u002250\u0022 Rotation=\u00220\u0022 \u003E\n \u003CRectangle.RotationTransition\u003E\n \u003CScalarTransition /\u003E\n \u003C/Rectangle.RotationTransition\u003E\n\u003C/Rectangle\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Use Implicit Transitions to automatically animate changes to properties.","relatedControls":["PageTransition","ThemeTransition"],"apiNamespace":"Microsoft.UI.Xaml","docs":[{"title":"Transitions - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.transitions#Windows_UI_Xaml_UIElement_Transitions"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/motion/motion-in-practice#implicit-animations"},{"title":"Quickstart: Motion","uri":"https://learn.microsoft.com/windows/apps/design/motion"}]},{"id":"implicittransition-3","controlId":"implicittransition","controlName":"Implicit Transitions","headerText":"Automatically animate changes to Scale","xaml":"\u003C!-- Automatically animate changes to Scale --\u003E\n\u003CRectangle x:Name=\u0022rectangle\u0022 Width=\u002250\u0022 Height=\u002250\u0022 Scale=\u00221,1,1\u0022 \u003E\n \u003CRectangle.ScaleTransition\u003E\n \u003CVector3Transition /\u003E\n \u003C/Rectangle.ScaleTransition\u003E\n\u003C/Rectangle\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Use Implicit Transitions to automatically animate changes to properties.","relatedControls":["PageTransition","ThemeTransition"],"apiNamespace":"Microsoft.UI.Xaml","docs":[{"title":"Transitions - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.transitions#Windows_UI_Xaml_UIElement_Transitions"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/motion/motion-in-practice#implicit-animations"},{"title":"Quickstart: Motion","uri":"https://learn.microsoft.com/windows/apps/design/motion"}]},{"id":"implicittransition-4","controlId":"implicittransition","controlName":"Implicit Transitions","headerText":"Automatically animate changes to Translation","xaml":"\u003C!-- Automatically animate changes to Translation --\u003E\n\u003CRectangle x:Name=\u0022rectangle\u0022 Width=\u002250\u0022 Height=\u002250\u0022 Translation=\u00220,0,0\u0022 \u003E\n \u003CRectangle.TranslationTransition\u003E\n \u003CVector3Transition /\u003E\n \u003C/Rectangle.TranslationTransition\u003E\n\u003C/Rectangle\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Use Implicit Transitions to automatically animate changes to properties.","relatedControls":["PageTransition","ThemeTransition"],"apiNamespace":"Microsoft.UI.Xaml","docs":[{"title":"Transitions - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.transitions#Windows_UI_Xaml_UIElement_Transitions"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/motion/motion-in-practice#implicit-animations"},{"title":"Quickstart: Motion","uri":"https://learn.microsoft.com/windows/apps/design/motion"}]},{"id":"implicittransition-5","controlId":"implicittransition","controlName":"Implicit Transitions","headerText":"Implicitly animate when the Background changes","xaml":"\u003CContentPresenter x:Name=\u0022BrushPresenter\u0022 Background=\u0022Blue\u0022 Width=\u002250\u0022 Height=\u002250\u0022\u003E\n \u003CContentPresenter.BackgroundTransition\u003E\n \u003CBrushTransition /\u003E\n \u003C/ContentPresenter.BackgroundTransition\u003E\n\u003C/ContentPresenter\u003E","csharp":"private void button_Click(object sender, RoutedEventArgs e)\n{\n // Note that this is a new brush instance, not a new color on the same brush.\n if (HasBlueBackground(BrushPresenter))\n {\n BrushPresenter.Background = new SolidColorBrush(Yellow);\n }\n else\n {\n BrushPresenter.Background = new SolidColorBrush(Blue);\n }\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Use Implicit Transitions to automatically animate changes to properties.","relatedControls":["PageTransition","ThemeTransition"],"apiNamespace":"Microsoft.UI.Xaml","docs":[{"title":"Transitions - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.transitions#Windows_UI_Xaml_UIElement_Transitions"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/motion/motion-in-practice#implicit-animations"},{"title":"Quickstart: Motion","uri":"https://learn.microsoft.com/windows/apps/design/motion"}]},{"id":"implicittransition-6","controlId":"implicittransition","controlName":"Implicit Transitions","headerText":"Implicitly animate when the Grid\u0027s theme changes","xaml":"\u003CGrid x:Name=\u0022ThemeExampleGrid\u0022 Background=\u0022{ThemeResource SolidBackgroundFillColorBaseBrush}\u0022 \u003E\n \u003CGrid.BackgroundTransition\u003E\n \u003CBrushTransition /\u003E\n \u003C/Grid.BackgroundTransition\u003E\n \u003CStackPanel Margin=\u002212\u0022 Spacing=\u00226\u0022\u003E\n \u003CTextBlock Text=\u0022Lorem Ipsum\u0022 Style=\u0022{ThemeResource SubtitleTextBlockStyle}\u0022 /\u003E\n \u003CTextBlock Text=\u0022The background of this grid animates when the theme changes.\u0022 TextWrapping=\u0022WrapWholeWords\u0022 /\u003E\n \u003CButton Content=\u0022Button\u0022 /\u003E\n \u003CCheckBox Content=\u0022CheckBox\u0022 /\u003E\n \u003C/StackPanel\u003E\n\u003C/Grid\u003E","csharp":"private void ThemeButton_Click(object sender, RoutedEventArgs e)\n{\n ThemeExampleGrid.RequestedTheme = ThemeExampleGrid.RequestedTheme == ElementTheme.Dark ? ElementTheme.Light : ElementTheme.Dark;\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Use Implicit Transitions to automatically animate changes to properties.","relatedControls":["PageTransition","ThemeTransition"],"apiNamespace":"Microsoft.UI.Xaml","docs":[{"title":"Transitions - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.transitions#Windows_UI_Xaml_UIElement_Transitions"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/motion/motion-in-practice#implicit-animations"},{"title":"Quickstart: Motion","uri":"https://learn.microsoft.com/windows/apps/design/motion"}]},{"id":"pagetransition-1","controlId":"pagetransition","controlName":"Page Transitions","headerText":"Page transitions","xaml":"\u003CFrame x:Name=\u0022ContentFrame\u0022\u003E\n \u003CFrame.ContentTransitions\u003E\n \u003CTransitionCollection\u003E\n \u003CNavigationThemeTransition /\u003E\n \u003C/TransitionCollection\u003E\n \u003C/Frame.ContentTransitions\u003E\n\u003C/Frame\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Page transitions provide visual feedback about the relationship between pages.","relatedControls":["ConnectedAnimation","ThemeTransition"],"apiNamespace":"Microsoft.UI.Xaml.Media.Animation","docs":[{"title":"NavigationThemeTransition - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Media.Animation.NavigationThemeTransition"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/motion/page-transitions"},{"title":"Quickstart: Motion","uri":"https://learn.microsoft.com/windows/apps/design/motion"}]},{"id":"themetransition-1","controlId":"themetransition","controlName":"Theme Transitions","headerText":"Use the EntranceThemeTransition when adding items to your page.","xaml":"\u003CStackPanel x:Name=\u0022EntranceStackPanel\u0022 Orientation=\u0022Horizontal\u0022\u003E\n \u003CStackPanel.ChildrenTransitions\u003E\n \u003CTransitionCollection\u003E\n \u003CEntranceThemeTransition IsStaggeringEnabled=\u0022True\u0022 /\u003E\n \u003C/TransitionCollection\u003E\n \u003C/StackPanel.ChildrenTransitions\u003E\n \u003CRectangle Width=\u002250\u0022 Height=\u002250\u0022 Margin=\u00225\u0022 Fill=\u0022LightBlue\u0022 /\u003E\n \u003CRectangle Width=\u002250\u0022 Height=\u002250\u0022 Margin=\u00225\u0022 Fill=\u0022LightBlue\u0022 /\u003E\n \u003CRectangle Width=\u002250\u0022 Height=\u002250\u0022 Margin=\u00225\u0022 Fill=\u0022LightBlue\u0022 /\u003E\n \u003CRectangle Width=\u002250\u0022 Height=\u002250\u0022 Margin=\u00225\u0022 Fill=\u0022LightBlue\u0022 /\u003E\n \u003CRectangle Width=\u002250\u0022 Height=\u002250\u0022 Margin=\u00225\u0022 Fill=\u0022LightBlue\u0022 /\u003E\n\u003C/StackPanel\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Theme transitions are pre-packaged, easy-to-apply animations.","relatedControls":["ImplicitTransition","PageTransition"],"apiNamespace":"Microsoft.UI.Xaml","docs":[{"title":"Transitions - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.transitions#Windows_UI_Xaml_UIElement_Transitions"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/motion/xaml-animation#animations-available-in-the-library"},{"title":"Quickstart: Motion","uri":"https://learn.microsoft.com/windows/apps/design/motion"}]},{"id":"themetransition-2","controlId":"themetransition","controlName":"Theme Transitions","headerText":"Use the RepositionThemeTransition to react to layout changes.","xaml":"\u003CRectangle x:Name=\u0022RightRectangle\u0022 Fill=\u0022Blue\u0022 \u003E\n \u003CRectangle.Transitions\u003E\n \u003CTransitionCollection\u003E\n \u003CRepositionThemeTransition /\u003E\n \u003C/TransitionCollection\u003E\n \u003C/Rectangle.Transitions\u003E\n\u003C/Rectangle\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Theme transitions are pre-packaged, easy-to-apply animations.","relatedControls":["ImplicitTransition","PageTransition"],"apiNamespace":"Microsoft.UI.Xaml","docs":[{"title":"Transitions - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.transitions#Windows_UI_Xaml_UIElement_Transitions"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/motion/xaml-animation#animations-available-in-the-library"},{"title":"Quickstart: Motion","uri":"https://learn.microsoft.com/windows/apps/design/motion"}]},{"id":"themetransition-3","controlId":"themetransition","controlName":"Theme Transitions","headerText":"Use ContentThemeTransition to animate content refreshes.","xaml":"\u003CListView\u003E\n \u003CListView.ItemContainerTransitions\u003E\n \u003CTransitionCollection\u003E\n \u003CContentThemeTransition /\u003E\n \u003C/TransitionCollection\u003E\n \u003C/ListView.ItemContainerTransitions\u003E\n\u003C/ListView\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Theme transitions are pre-packaged, easy-to-apply animations.","relatedControls":["ImplicitTransition","PageTransition"],"apiNamespace":"Microsoft.UI.Xaml","docs":[{"title":"Transitions - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.transitions#Windows_UI_Xaml_UIElement_Transitions"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/motion/xaml-animation#animations-available-in-the-library"},{"title":"Quickstart: Motion","uri":"https://learn.microsoft.com/windows/apps/design/motion"}]},{"id":"themetransition-4","controlId":"themetransition","controlName":"Theme Transitions","headerText":"Use AddDeleteThemeTransition to animate adding and removing items from a collection.","xaml":"\u003CListView\u003E\n \u003CListView.ItemContainerTransitions\u003E\n \u003CTransitionCollection\u003E\n \u003CAddDeleteThemeTransition /\u003E\n \u003C/TransitionCollection\u003E\n \u003C/ListView.ItemContainerTransitions\u003E\n\u003C/ListView\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Theme transitions are pre-packaged, easy-to-apply animations.","relatedControls":["ImplicitTransition","PageTransition"],"apiNamespace":"Microsoft.UI.Xaml","docs":[{"title":"Transitions - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.transitions#Windows_UI_Xaml_UIElement_Transitions"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/motion/xaml-animation#animations-available-in-the-library"},{"title":"Quickstart: Motion","uri":"https://learn.microsoft.com/windows/apps/design/motion"}]},{"id":"themetransition-5","controlId":"themetransition","controlName":"Theme Transitions","headerText":"Use PopupThemeTransition to animate opening and closing a popup.","xaml":"\u003CPopup x:Name=\u0022ExamplePopup\u0022\u003E\n \u003CPopup.ChildTransitions\u003E\n \u003CTransitionCollection\u003E\n \u003CPopupThemeTransition /\u003E\n \u003C/TransitionCollection\u003E\n \u003C/Popup.ChildTransitions\u003E\n \u003CBorder Background=\u0022{ThemeResource FlyoutBackgroundThemeBrush}\u0022 BorderThickness=\u00222\u0022 BorderBrush=\u0022{ThemeResource SystemControlForegroundChromeGrayBrush}\u0022\u003E\n \u003CStackPanel Margin=\u002210\u0022\u003E\n \u003CTextBlock Text=\u0022This is a popup using PopupThemeTransition\u0022 /\u003E\n \u003CButton Content=\u0022Close Popup\u0022 Click=\u0022ClosePopupButton_Click\u0022 /\u003E\n \u003C/StackPanel\u003E\n \u003C/Border\u003E\n\u003C/Popup\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Theme transitions are pre-packaged, easy-to-apply animations.","relatedControls":["ImplicitTransition","PageTransition"],"apiNamespace":"Microsoft.UI.Xaml","docs":[{"title":"Transitions - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.transitions#Windows_UI_Xaml_UIElement_Transitions"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/motion/xaml-animation#animations-available-in-the-library"},{"title":"Quickstart: Motion","uri":"https://learn.microsoft.com/windows/apps/design/motion"}]},{"id":"parallaxview-1","controlId":"parallaxview","controlName":"ParallaxView","headerText":"Parallax on a ListView","xaml":"\u003CGrid\u003E\n \u003CParallaxView Source=\u0022{Binding ElementName=listView}\u0022 VerticalShift=\u0022500\u0022\u003E\n \u003CImage Source=\u0022ms-appx:///Assets/YourImage.png\u0022 /\u003E\n \u003C/ParallaxView\u003E\n \u003CListView x:Name=\u0022listView\u0022 ItemsSource=\u0022{x:Bind Items}\u0022\u003E\n \u003CListView.Header\u003E\n \u003CTextBlock Text=\u0022Scroll the list to see parallaxing of image\u0022 /\u003E\n \u003C/ListView.Header\u003E\n \u003C/ListView\u003E\n\u003C/Grid\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A container control that provides the parallax effect when scrolling.","relatedControls":["ScrollView","ScrollViewer"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"ParallaxView - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Controls.Parallaxview"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/motion/parallax"}]},{"id":"parallaxview-2","controlId":"parallaxview","controlName":"ParallaxView","headerText":"Parallax with a ScrollView","xaml":"\u003CGrid\u003E\n \u003CParallaxView Source=\u0022{Binding ElementName=scrollView}\u0022 VerticalShift=\u0022500\u0022\u003E\n \u003CImage Source=\u0022ms-appx:///Assets/YourImage.png\u0022/\u003E\n \u003C/ParallaxView\u003E\n \u003CTextBlock Text=\u0022Scroll the rectangles to see parallaxing of image\u0022 MaxWidth=\u0022280\u0022\n HorizontalAlignment=\u0022Center\u0022 VerticalAlignment=\u0022Top\u0022 Foreground=\u0022White\u0022\n FontSize=\u002228\u0022 TextWrapping=\u0022WrapWholeWords\u0022/\u003E\n \u003CScrollView x:Name=\u0022scrollView\u0022 Width=\u0022150\u0022 HorizontalAlignment=\u0022Left\u0022\u003E\n \u003CStackPanel\u003E\n \u003CRectangle Fill=\u0022AliceBlue\u0022 Height=\u0022150\u0022/\u003E\n \u003C!-- ... --\u003E\n \u003CRectangle Fill=\u0022Cyan\u0022 Height=\u0022150\u0022/\u003E\n \u003C/StackPanel\u003E\n \u003C/ScrollView\u003E\n\u003C/Grid\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A container control that provides the parallax effect when scrolling.","relatedControls":["ScrollView","ScrollViewer"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"ParallaxView - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Controls.Parallaxview"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/apps/design/motion/parallax"}]},{"id":"appwindow-1","controlId":"appwindow","controlName":"AppWindow","headerText":"Creating and customizing an AppWindow from a Window instance","xaml":"\u003CWindow ...\u003E\n \u003CWindow.SystemBackdrop\u003E\n \u003CMicaBackdrop /\u003E\n \u003C/Window.SystemBackdrop\u003E\n\n \u003CStackPanel HorizontalAlignment=\u0022Center\u0022\n VerticalAlignment=\u0022Center\u0022\n Spacing=\u00228\u0022\u003E\n \u003CButton x:Name=\u0022Hide\u0022\n Content=\u0022Hide\u0022\n Click=\u0022Hide_Click\u0022\n Width=\u0022200\u0022\u003E\n \u003CToolTipService.ToolTip\u003E\n \u003CTextBlock Text=\u0022Hides the window from all UX representations in the system but keeps the object alive.\u0022\n TextWrapping=\u0022Wrap\u0022 /\u003E\n \u003C/ToolTipService.ToolTip\u003E\n \u003C/Button\u003E\n \u003CButton x:Name=\u0022Show\u0022\n Click=\u0022Show_Click\u0022\n Width=\u0022200\u0022 \u003E\n \u003CToolTipService.ToolTip\u003E\n \u003CTextBlock Text=\u0022Hides and then shows the window and activates it after 3 seconds.\u0022\n TextWrapping=\u0022Wrap\u0022 /\u003E\n \u003C/ToolTipService.ToolTip\u003E\n \u003CTextBlock Text=\u0022Hide and show the window after 3 seconds\u0022 TextWrapping=\u0022WrapWholeWords\u0022 TextAlignment=\u0022Center\u0022/\u003E\n \u003C/Button\u003E\n \u003CButton x:Name=\u0022Close\u0022\n Click=\u0022Close_Click\u0022\n Margin=\u00220,16,0,0\u0022\u003E\n \u003CStackPanel Orientation=\u0022Horizontal\u0022 VerticalAlignment=\u0022Center\u0022\u003E\n \u003CSymbolIcon Symbol=\u0022Cancel\u0022\n Foreground=\u0022{ThemeResource SystemFillColorCriticalBrush}\u0022\n Margin=\u00220,0,4,0\u0022 /\u003E\n \u003CTextBlock Text=\u0022Close\u0022\n Foreground=\u0022{ThemeResource SystemFillColorCriticalBrush}\u0022 /\u003E\n \u003C/StackPanel\u003E\n \u003CToolTipService.ToolTip\u003E\n \u003CTextBlock Text=\u0022Closes the window and releases all resources.\u0022\n TextWrapping=\u0022Wrap\u0022 /\u003E\n \u003C/ToolTipService.ToolTip\u003E\n \u003C/Button\u003E\n \u003C/StackPanel\u003E\n\u003C/Window\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A flexible, customizable window management system for app development.","relatedControls":["AppWindowTitleBar","TitleBar","CreateMultipleWindows"],"apiNamespace":"Microsoft.UI.Windowing","docs":[{"title":"AppWindow - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.windowing.appwindow"},{"title":"Window - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.window"},{"title":"AppWindowPresenter - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.windowing.appwindowpresenter"},{"title":"OverlappedPresenter - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.windowing.overlappedpresenter"},{"title":"FullScreenPresenter - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.windowing.fullscreenpresenter"},{"title":"CompactOverlayPresenter - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.windowing.compactoverlaypresenter"}]},{"id":"appwindow-2","controlId":"appwindow","controlName":"AppWindow","headerText":"Centering AppWindow on the screen using the available display area","xaml":"\u003CWindow ...\u003E\n \u003CWindow.SystemBackdrop\u003E\n \u003CMicaBackdrop /\u003E\n \u003C/Window.SystemBackdrop\u003E\n\n \u003CStackPanel HorizontalAlignment=\u0022Center\u0022 VerticalAlignment=\u0022Center\u0022 Spacing=\u00228\u0022\u003E\n \u003CTextBlock Text=\u0022This is a centred sample window\u0022 Style=\u0022{ThemeResource TitleTextBlockStyle}\u0022 TextAlignment=\u0022Center\u0022 /\u003E\n \u003C/StackPanel\u003E\n\u003C/Window\u003E","csharp":"using Microsoft.UI.Windowing;\nusing Microsoft.UI.Xaml;\nusing Windows.Graphics;\n\nnamespace YourNamesapace;\n\npublic sealed partial class SampleWindow2 : Window\n{\n public SampleWindow2()\n {\n this.InitializeComponent();\n AppWindow.SetIcon(\u0022Assets/Tiles/GalleryIcon.ico\u0022);\n AppWindow.TitleBar.PreferredTheme = TitleBarTheme.UseDefaultAppMode;\n\n // Center the window on the screen.\n CenterWindow();\n }\n\n // Centers the given AppWindow on the screen based on the available display area.\n private void CenterWindow()\n {\n var area = DisplayArea.GetFromWindowId(AppWindow.Id, DisplayAreaFallback.Nearest)?.WorkArea;\n if (area == null) return;\n AppWindow.Move(new PointInt32((area.Value.Width - AppWindow.Size.Width) / 2, (area.Value.Height - AppWindow.Size.Height) / 2));\n }\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A flexible, customizable window management system for app development.","relatedControls":["AppWindowTitleBar","TitleBar","CreateMultipleWindows"],"apiNamespace":"Microsoft.UI.Windowing","docs":[{"title":"AppWindow - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.windowing.appwindow"},{"title":"Window - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.window"},{"title":"AppWindowPresenter - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.windowing.appwindowpresenter"},{"title":"OverlappedPresenter - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.windowing.overlappedpresenter"},{"title":"FullScreenPresenter - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.windowing.fullscreenpresenter"},{"title":"CompactOverlayPresenter - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.windowing.compactoverlaypresenter"}]},{"id":"appwindow-3","controlId":"appwindow","controlName":"AppWindow","headerText":"AppWindow with OverlapedPresenter","xaml":"\u003CWindow ...\u003E\n \u003CWindow.SystemBackdrop\u003E\n \u003CMicaBackdrop /\u003E\n \u003C/Window.SystemBackdrop\u003E\n\n \u003CStackPanel HorizontalAlignment=\u0022Center\u0022\n VerticalAlignment=\u0022Center\u0022\n Spacing=\u002210\u0022\u003E\n \u003CButton x:Name=\u0022MaximizeBtn\u0022\n Content=\u0022Maximize\u0022\n Click=\u0022MaximizeBtn_Click\u0022\n Width=\u0022200\u0022 /\u003E\n \u003CButton x:Name=\u0022MinimizeBtn\u0022\n Content=\u0022Minimize\u0022\n Click=\u0022MinimizeBtn_Click\u0022\n Width=\u0022200\u0022 /\u003E\n \u003CButton x:Name=\u0022RestoreBtn\u0022\n Click=\u0022RestoreBtn_Click\u0022\n Width=\u0022200\u0022 \u003E\n \u003CTextBlock Text=\u0022Minimize and restore the window after 3 seconds\u0022 TextWrapping=\u0022WrapWholeWords\u0022 TextAlignment=\u0022Center\u0022/\u003E\n \u003C/Button\u003E\n \u003CButton x:Name=\u0022CloseBtn\u0022\n Click=\u0022CloseBtn_Click\u0022\n Margin=\u00220,16,0,0\u0022\u003E\n \u003CStackPanel Orientation=\u0022Horizontal\u0022\n VerticalAlignment=\u0022Center\u0022\u003E\n \u003CSymbolIcon Symbol=\u0022Cancel\u0022\n Margin=\u00220,0,4,0\u0022\n Foreground=\u0022{ThemeResource SystemFillColorCriticalBrush}\u0022 /\u003E\n \u003CTextBlock Text=\u0022Close\u0022\n Foreground=\u0022{ThemeResource SystemFillColorCriticalBrush}\u0022 /\u003E\n \u003C/StackPanel\u003E\n \u003C/Button\u003E\n \u003C/StackPanel\u003E\n\u003C/Window\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A flexible, customizable window management system for app development.","relatedControls":["AppWindowTitleBar","TitleBar","CreateMultipleWindows"],"apiNamespace":"Microsoft.UI.Windowing","docs":[{"title":"AppWindow - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.windowing.appwindow"},{"title":"Window - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.window"},{"title":"AppWindowPresenter - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.windowing.appwindowpresenter"},{"title":"OverlappedPresenter - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.windowing.overlappedpresenter"},{"title":"FullScreenPresenter - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.windowing.fullscreenpresenter"},{"title":"CompactOverlayPresenter - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.windowing.compactoverlaypresenter"}]},{"id":"appwindow-4","controlId":"appwindow","controlName":"AppWindow","headerText":"Setting the minimum and maximum width / height on an AppWindow using OverlappedPresenter","xaml":"\u003CWindow ...\u003E\n \u003CWindow.SystemBackdrop\u003E\n \u003CMicaBackdrop /\u003E\n \u003C/Window.SystemBackdrop\u003E\n\n \u003CStackPanel HorizontalAlignment=\u0022Center\u0022\n VerticalAlignment=\u0022Center\u0022\n Spacing=\u002210\u0022\u003E\n \u003CButton x:Name=\u0022MaximizeBtn\u0022\n Content=\u0022Maximize\u0022\n Click=\u0022MaximizeBtn_Click\u0022\n Width=\u0022200\u0022 /\u003E\n \u003CButton x:Name=\u0022MinimizeBtn\u0022\n Content=\u0022Minimize\u0022\n Click=\u0022MinimizeBtn_Click\u0022\n Width=\u0022200\u0022 /\u003E\n \u003CButton x:Name=\u0022RestoreBtn\u0022\n Click=\u0022RestoreBtn_Click\u0022\n Width=\u0022200\u0022 \u003E\n \u003CTextBlock Text=\u0022Minimize and restore the window after 3 seconds\u0022 TextWrapping=\u0022WrapWholeWords\u0022 TextAlignment=\u0022Center\u0022/\u003E\n \u003C/Button\u003E\n \u003CButton x:Name=\u0022CloseBtn\u0022\n Click=\u0022CloseBtn_Click\u0022\n Margin=\u00220,16,0,0\u0022\u003E\n \u003CStackPanel Orientation=\u0022Horizontal\u0022\n VerticalAlignment=\u0022Center\u0022\u003E\n \u003CSymbolIcon Symbol=\u0022Cancel\u0022\n Margin=\u00220,0,4,0\u0022\n Foreground=\u0022{ThemeResource SystemFillColorCriticalBrush}\u0022 /\u003E\n \u003CTextBlock Text=\u0022Close\u0022\n Foreground=\u0022{ThemeResource SystemFillColorCriticalBrush}\u0022 /\u003E\n \u003C/StackPanel\u003E\n \u003C/Button\u003E\n \u003C/StackPanel\u003E\n\u003C/Window\u003E","csharp":"using Microsoft.UI.Windowing;\nusing Microsoft.UI.Xaml;\nusing System.Threading.Tasks;\n\nnamespace YourApp;\n\npublic sealed partial class SampleWindow4 : Window\n{\n public SampleWindow4(int MinWidth, int MinHeight, int MaxWidth, int MaxHeight)\n {\n this.InitializeComponent();\n\n AppWindow.Resize(new Windows.Graphics.SizeInt32(800, 500));\n AppWindow.SetIcon(\u0022Assets/Tiles/GalleryIcon.ico\u0022);\n AppWindow.TitleBar.PreferredTheme = TitleBarTheme.UseDefaultAppMode;\n\n OverlappedPresenter presenter = OverlappedPresenter.Create();\n presenter.PreferredMinimumWidth = MinWidth;\n presenter.PreferredMinimumHeight = MinHeight;\n presenter.PreferredMaximumWidth = MaxWidth;\n presenter.PreferredMaximumHeight = MaxHeight;\n presenter.IsMaximizable = false;\n\n AppWindow.SetPresenter(presenter);\n }\n\n private void MinimizeBtn_Click(object sender, RoutedEventArgs e)\n {\n OverlappedPresenter presenter = (OverlappedPresenter)AppWindow.Presenter;\n presenter.Minimize();\n }\n\n private void RestoreBtn_Click(object sender, RoutedEventArgs e)\n {\n OverlappedPresenter presenter = (OverlappedPresenter)AppWindow.Presenter;\n presenter.Minimize();\n Task.Delay(3000).ContinueWith(t =\u003E presenter.Restore());\n }\n\n private void CloseBtn_Click(object sender, RoutedEventArgs e)\n {\n this.Close();\n }\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A flexible, customizable window management system for app development.","relatedControls":["AppWindowTitleBar","TitleBar","CreateMultipleWindows"],"apiNamespace":"Microsoft.UI.Windowing","docs":[{"title":"AppWindow - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.windowing.appwindow"},{"title":"Window - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.window"},{"title":"AppWindowPresenter - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.windowing.appwindowpresenter"},{"title":"OverlappedPresenter - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.windowing.overlappedpresenter"},{"title":"FullScreenPresenter - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.windowing.fullscreenpresenter"},{"title":"CompactOverlayPresenter - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.windowing.compactoverlaypresenter"}]},{"id":"appwindow-5","controlId":"appwindow","controlName":"AppWindow","headerText":"Modal window with OverlappedPresenter using AppWindow","xaml":"\u003CWindow ...\u003E\n \u003CWindow.SystemBackdrop\u003E\n \u003CMicaBackdrop /\u003E\n \u003C/Window.SystemBackdrop\u003E\n\n \u003CStackPanel HorizontalAlignment=\u0022Center\u0022 VerticalAlignment=\u0022Center\u0022 Spacing=\u00228\u0022\u003E\n \u003CTextBlock Text=\u0022Modal Window\u0022 Style=\u0022{ThemeResource TitleTextBlockStyle}\u0022 TextAlignment=\u0022Center\u0022 /\u003E\n\n \u003CTextBlock Text=\u0022This is a modal window created using AppWindow with OverlappedPresenter.\u0022 Style=\u0022{ThemeResource BodyTextBlockStyle}\u0022 TextAlignment=\u0022Center\u0022 TextWrapping=\u0022Wrap\u0022 /\u003E\n\n \u003CStackPanel Orientation=\u0022Horizontal\u0022 HorizontalAlignment=\u0022Center\u0022 Spacing=\u00228\u0022\u003E\n \u003CButton Content=\u0022OK\u0022 Width=\u002280\u0022 Click=\u0022OKButton_Click\u0022 /\u003E\n \u003CButton Content=\u0022Cancel\u0022 Width=\u002280\u0022 Click=\u0022CancelButton_Click\u0022 /\u003E\n \u003C/StackPanel\u003E\n \u003C/StackPanel\u003E\n\u003C/Window\u003E","csharp":"using Microsoft.UI;\nusing Microsoft.UI.Windowing;\nusing Microsoft.UI.Xaml;\nusing System;\nusing System.Runtime.InteropServices;\nusing WinRT.Interop;\n\nnamespace YourNamespace;\n\npublic sealed partial class ModalWindow : Window\n{\n public ModalWindow()\n {\n this.InitializeComponent();\n\n var dpi = Windows.Win32.PInvoke.GetDpiForWindow(new Windows.Win32.Foundation.HWND(WinRT.Interop.WindowNative.GetWindowHandle(this)));\n var scalingFactor = (float)dpi / 96;\n\n AppWindow.Resize(new Windows.Graphics.SizeInt32((int)(400.0f * scalingFactor), (int)(300.0f * scalingFactor)));\n AppWindow.SetIcon(\u0022Assets/Tiles/GalleryIcon.ico\u0022);\n AppWindow.TitleBar.PreferredTheme = TitleBarTheme.UseDefaultAppMode;\n\n OverlappedPresenter presenter = OverlappedPresenter.CreateForDialog();\n\n // Set this modal window\u0027s owner (the main application window).\n // The main window can be retrieved from App.xaml.cs if it\u0027s set as a static property.\n SetWindowOwner(owner: App.StartupWindow);\n\n // Make the window modal (blocks interaction with the owner window until closed).\n presenter.IsModal = true;\n\n // Apply the presenter settings to the AppWindow.\n AppWindow.SetPresenter(presenter);\n\n // Show the modal window.\n AppWindow.Show();\n\n Closed \u002B= ModalWindow_Closed;\n }\n\n // Sets the owner window of the modal window.\n private void SetWindowOwner(Window owner)\n {\n // Get the HWND (window handle) of the owner window (main window).\n IntPtr ownerHwnd = WindowNative.GetWindowHandle(owner);\n\n // Get the HWND of the AppWindow (modal window).\n IntPtr ownedHwnd = Win32Interop.GetWindowFromWindowId(AppWindow.Id);\n\n // Set the owner window using SetWindowLongPtr for 64-bit systems\n // or SetWindowLong for 32-bit systems.\n if (IntPtr.Size == 8) // Check if the system is 64-bit\n {\n SetWindowLongPtr(ownedHwnd, -8, ownerHwnd); // -8 = GWLP_HWNDPARENT\n }\n else // 32-bit system\n {\n SetWindowLong(ownedHwnd, -8, ownerHwnd); // -8 = GWL_HWNDPARENT\n }\n }\n\n // Import the Windows API function SetWindowLongPtr for modifying window properties on 64-bit systems.\n [DllImport(\u0022User32.dll\u0022, CharSet = CharSet.Auto, EntryPoint = \u0022SetWindowLongPtr\u0022)]\n public static extern IntPtr SetWindowLongPtr(IntPtr hWnd, int nIndex, IntPtr dwNewLong);\n\n // Import the Windows API function SetWindowLong for modifying window properties on 32-bit systems.\n [DllImport(\u0022User32.dll\u0022, CharSet = CharSet.Auto, EntryPoint = \u0022SetWindowLong\u0022)]\n}\n// NOTE: snippet truncated \u2014 refer to full sample for additional code","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A flexible, customizable window management system for app development.","relatedControls":["AppWindowTitleBar","TitleBar","CreateMultipleWindows"],"apiNamespace":"Microsoft.UI.Windowing","docs":[{"title":"AppWindow - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.windowing.appwindow"},{"title":"Window - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.window"},{"title":"AppWindowPresenter - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.windowing.appwindowpresenter"},{"title":"OverlappedPresenter - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.windowing.overlappedpresenter"},{"title":"FullScreenPresenter - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.windowing.fullscreenpresenter"},{"title":"CompactOverlayPresenter - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.windowing.compactoverlaypresenter"}]},{"id":"appwindow-6","controlId":"appwindow","controlName":"AppWindow","headerText":"AppWindow with FullScreenPresenter","xaml":"\u003CWindow ...\u003E\n \u003CWindow.SystemBackdrop\u003E\n \u003CMicaBackdrop /\u003E\n \u003C/Window.SystemBackdrop\u003E\n\n \u003CStackPanel HorizontalAlignment=\u0022Center\u0022\n VerticalAlignment=\u0022Center\u0022\n Spacing=\u00228\u0022\u003E\n \u003CTextBlock Text=\u0022This window is running in Fullscreen mode\u0022\n Style=\u0022{ThemeResource TitleTextBlockStyle}\u0022\n TextAlignment=\u0022Center\u0022 /\u003E\n \u003CButton x:Name=\u0022Close\u0022\n Click=\u0022Close_Click\u0022\n HorizontalAlignment=\u0022Center\u0022\u003E\n \u003CStackPanel Orientation=\u0022Horizontal\u0022\n VerticalAlignment=\u0022Center\u0022\u003E\n \u003CSymbolIcon Symbol=\u0022Cancel\u0022\n Foreground=\u0022{ThemeResource SystemFillColorCriticalBrush}\u0022\n Margin=\u00220,0,4,0\u0022 /\u003E\n \u003CTextBlock Text=\u0022Close\u0022\n Foreground=\u0022{ThemeResource SystemFillColorCriticalBrush}\u0022 /\u003E\n \u003C/StackPanel\u003E\n \u003C/Button\u003E\n \u003C/StackPanel\u003E\n\u003C/Window\u003E","csharp":"using Microsoft.UI.Windowing;\nusing Microsoft.UI.Xaml;\n\nnamespace YourNamespace;\n\npublic sealed partial class SampleWindow6 : Window\n{\n public SampleWindow6()\n {\n this.InitializeComponent();\n AppWindow.SetIcon(\u0022Assets/Tiles/GalleryIcon.ico\u0022);\n AppWindow.TitleBar.PreferredTheme = TitleBarTheme.UseDefaultAppMode;\n\n // Set the window to Full-Screen mode\n AppWindow.SetPresenter(AppWindowPresenterKind.FullScreen);\n }\n\n private void Close_Click(object sender, RoutedEventArgs e)\n {\n this.Close();\n }\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A flexible, customizable window management system for app development.","relatedControls":["AppWindowTitleBar","TitleBar","CreateMultipleWindows"],"apiNamespace":"Microsoft.UI.Windowing","docs":[{"title":"AppWindow - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.windowing.appwindow"},{"title":"Window - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.window"},{"title":"AppWindowPresenter - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.windowing.appwindowpresenter"},{"title":"OverlappedPresenter - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.windowing.overlappedpresenter"},{"title":"FullScreenPresenter - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.windowing.fullscreenpresenter"},{"title":"CompactOverlayPresenter - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.windowing.compactoverlaypresenter"}]},{"id":"appwindow-7","controlId":"appwindow","controlName":"AppWindow","headerText":"AppWindow with CompactOverlayPresenter","xaml":"\u003CWindow ...\u003E\n \u003CWindow.SystemBackdrop\u003E\n \u003CMicaBackdrop /\u003E\n \u003C/Window.SystemBackdrop\u003E\n\n \u003CStackPanel HorizontalAlignment=\u0022Center\u0022 VerticalAlignment=\u0022Center\u0022 Spacing=\u00228\u0022\u003E\n \u003CTextBlock Text=\u0022This window is set to CompactOverlay (Picture-in-Picture) mode.\u0022 TextAlignment=\u0022Center\u0022 TextWrapping=\u0022Wrap\u0022 /\u003E\n \u003C/StackPanel\u003E\n\u003C/Window\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"A flexible, customizable window management system for app development.","relatedControls":["AppWindowTitleBar","TitleBar","CreateMultipleWindows"],"apiNamespace":"Microsoft.UI.Windowing","docs":[{"title":"AppWindow - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.windowing.appwindow"},{"title":"Window - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.window"},{"title":"AppWindowPresenter - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.windowing.appwindowpresenter"},{"title":"OverlappedPresenter - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.windowing.overlappedpresenter"},{"title":"FullScreenPresenter - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.windowing.fullscreenpresenter"},{"title":"CompactOverlayPresenter - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.windowing.compactoverlaypresenter"}]},{"id":"createmultiplewindows-1","controlId":"createmultiplewindows","controlName":"Multiple windows","headerText":"Create single threaded Multiple Top level Windows(MTW).","xaml":null,"csharp":"// Ensure you close the child window before closing the parent window to avoid application crash.\nvar childWindow = new Window()\n{\n ExtendsContentIntoTitleBar = true,\n SystemBackdrop = new MicaBackdrop(),\n Content = new Page()\n {\n Content = new TextBlock()\n {\n Text = \u0022New child window!\u0022,\n HorizontalAlignment = HorizontalAlignment.Center,\n VerticalAlignment = VerticalAlignment.Center,\n },\n // Get the theme from the parent.\n RequestedTheme = this.ActualTheme,\n }\n};\n\nchildWindow.AppWindow.ResizeClient(new SizeInt32(500, 500));\nchildWindow.Activate();","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"An example showing the creation of single-threaded top level Xaml windows.","relatedControls":["AppWindow","AppWindowTitleBar","TitleBar"],"apiNamespace":"Microsoft.UI.Xaml","docs":[{"title":"MultipleWindow - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.window"},{"title":"Guidelines","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.window"}]},{"id":"titlebar-1","controlId":"titlebar","controlName":"TitleBar","headerText":"TitleBar configuration","xaml":"\u003CTitleBar\n Title=\u0022...\u0022\n Subtitle=\u0022...\u0022\n IsBackButtonVisible=\u0022...\u0022\n IsPaneToggleButtonVisible=\u0022...\u0022\u003E\n \u003CTitleBar.Resources\u003E\n \u003C!-- TitleBar.Content uses Center alignment by default. Override to\n Stretch so the AutoSuggestBox grows with the title bar. --\u003E\n \u003CHorizontalAlignment x:Key=\u0022TitleBarContentHorizontalAlignment\u0022\u003EStretch\u003C/HorizontalAlignment\u003E\n \u003C/TitleBar.Resources\u003E\n \u003CTitleBar.IconSource\u003E\n \u003CImageIconSource ImageSource=\u0022/Assets/Tiles/GalleryIcon.ico\u0022 /\u003E\n \u003C/TitleBar.IconSource\u003E\n \u003CTitleBar.Content\u003E\n \u003CAutoSuggestBox\n HorizontalAlignment=\u0022Stretch\u0022\n VerticalAlignment=\u0022Center\u0022\n PlaceholderText=\u0022Search...\u0022\n QueryIcon=\u0022Find\u0022 /\u003E\n \u003C/TitleBar.Content\u003E\n \u003CTitleBar.RightHeader\u003E\n \u003CPersonPicture\n Initials=\u0022JD\u0022 /\u003E\n \u003C/TitleBar.RightHeader\u003E\n\u003C/TitleBar\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"An example showing how to use the default TitleBar control.","relatedControls":["AppWindow","AppWindowTitleBar"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"Title bar customization","uri":"https://learn.microsoft.com/windows/apps/develop/title-bar"},{"title":"Title bar - design guidelines","uri":"https://learn.microsoft.com/windows/apps/design/basics/titlebar-design"}]},{"id":"titlebar-2","controlId":"titlebar","controlName":"TitleBar","headerText":"TitleBar drag regions","xaml":"\u003C!-- Starting with WindowsAppSDK 2.1, TitleBar walks TitleBar.Content,\n auto-excludes interactive controls from the drag region, and lets\n non-interactive visuals (and empty space) remain draggable.\n\n Use TitleBar.IsDragRegion to override the framework decision:\n True -\u003E always draggable\n False -\u003E always clickable\n unset -\u003E framework decides (default) --\u003E\n\u003CTitleBar x:Name=\u0022titleBar\u0022 Title=\u0022Drag regions\u0022\u003E\n \u003CTitleBar.Resources\u003E\n \u003C!-- TitleBar.Content uses Center alignment by default, so a child\n with HorizontalAlignment=Stretch will not actually grow.\n Override to Stretch to let the search box fill the content area. --\u003E\n \u003CHorizontalAlignment x:Key=\u0022TitleBarContentHorizontalAlignment\u0022\u003EStretch\u003C/HorizontalAlignment\u003E\n \u003C/TitleBar.Resources\u003E\n \u003CTitleBar.Content\u003E\n \u003CGrid ColumnSpacing=\u00228\u0022 HorizontalAlignment=\u0022Stretch\u0022\u003E\n \u003CGrid.ColumnDefinitions\u003E\n \u003CColumnDefinition Width=\u0022*\u0022 /\u003E\n \u003CColumnDefinition Width=\u0022Auto\u0022 /\u003E\n \u003C/Grid.ColumnDefinitions\u003E\n \u003C!-- Interactive: auto-excluded from drag. --\u003E\n \u003CAutoSuggestBox\n HorizontalAlignment=\u0022Stretch\u0022\n VerticalAlignment=\u0022Center\u0022\n PlaceholderText=\u0022Search...\u0022\n QueryIcon=\u0022Find\u0022 /\u003E\n \u003C!-- Interactive Button. Drag behavior is overridden via\n TitleBar.IsDragRegion in code-behind. --\u003E\n \u003CButton\n x:Name=\u0022StatusBadge\u0022\n Grid.Column=\u00221\u0022\n VerticalAlignment=\u0022Center\u0022\n Click=\u0022StatusBadge_Click\u0022\n Content=\u0022Status\u0022\n Style=\u0022{StaticResource AccentButtonStyle}\u0022 /\u003E\n \u003C/Grid\u003E\n \u003C/TitleBar.Content\u003E\n\u003C/TitleBar\u003E","csharp":"// Set TitleBar.IsDragRegion at runtime.\nTitleBar.SetIsDragRegion(StatusBadge, true); // always draggable\nTitleBar.SetIsDragRegion(StatusBadge, false); // always clickable\nStatusBadge.ClearValue(TitleBar.IsDragRegionProperty); // back to default\n\n// After adding or removing elements in TitleBar.Content dynamically,\n// ask the framework to recompute drag regions.\ntitleBar.RecomputeDragRegions();","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"An example showing how to use the default TitleBar control.","relatedControls":["AppWindow","AppWindowTitleBar"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"Title bar customization","uri":"https://learn.microsoft.com/windows/apps/develop/title-bar"},{"title":"Title bar - design guidelines","uri":"https://learn.microsoft.com/windows/apps/design/basics/titlebar-design"}]},{"id":"titlebar-3","controlId":"titlebar","controlName":"TitleBar","headerText":"End to end TitleBar sample","xaml":"\u003CGrid\u003E\n \u003CGrid.RowDefinitions\u003E\n \u003CRowDefinition Height=\u0022Auto\u0022 /\u003E\n \u003C!-- TitleBar --\u003E\n \u003CRowDefinition Height=\u0022*\u0022 /\u003E\n \u003C!-- NavigationView --\u003E\n \u003C/Grid.RowDefinitions\u003E\n\n \u003CTitleBar\n x:Name=\u0022titleBar\u0022\n BackRequested=\u0022TitleBar_BackRequested\u0022\n IsBackButtonVisible=\u0022{x:Bind navFrame.CanGoBack, Mode=OneWay}\u0022\n IsPaneToggleButtonVisible=\u0022True\u0022\n PaneToggleRequested=\u0022TitleBar_PaneToggleRequested\u0022 /\u003E\n\n \u003CNavigationView\n x:Name=\u0022navView\u0022\n Grid.Row=\u00221\u0022\n IsBackButtonVisible=\u0022Collapsed\u0022\n IsPaneToggleButtonVisible=\u0022False\u0022\u003E\n \u003CNavigationView.MenuItems... /\u003E\n \u003CFrame x:Name=\u0022navFrame\u0022 /\u003E\n \u003C/NavigationView\u003E\n\u003C/Grid\u003E","csharp":"this.ExtendsContentIntoTitleBar = true; // Extend the content into the title bar and hide the default titlebar\n this.SetTitleBar(titleBar); // Set the custom title bar","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"An example showing how to use the default TitleBar control.","relatedControls":["AppWindow","AppWindowTitleBar"],"apiNamespace":"Microsoft.UI.Xaml.Controls","docs":[{"title":"Title bar customization","uri":"https://learn.microsoft.com/windows/apps/develop/title-bar"},{"title":"Title bar - design guidelines","uri":"https://learn.microsoft.com/windows/apps/design/basics/titlebar-design"}]},{"id":"clipboard-1","controlId":"clipboard","controlName":"Clipboard","headerText":"Copy text to the Clipboard","xaml":"\u003CButton Content=\u0022Copy Text to the Clipboard\u0022 Click=\u0022CopyText_Click\u0022/\u003E","csharp":"private void CopyText_Click(object sender, RoutedEventArgs args)\n{\n\tvar package = new DataPackage();\n\tpackage.SetText(\u0022Copy this text\u0022);\n\tClipboard.SetContent(package);\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Copy and paste text, images, and files to and from the system Clipboard.","relatedControls":["StoragePickers"],"apiNamespace":"Windows.ApplicationModel.DataTransfer","docs":[{"title":"Clipboard - API","uri":"https://learn.microsoft.com/uwp/api/windows.applicationmodel.datatransfer.clipboard"},{"title":"ClipboardContentOptions - API","uri":"https://learn.microsoft.com/uwp/api/windows.applicationmodel.datatransfer.clipboardcontentoptions"},{"title":"Copy and paste - Guide","uri":"https://learn.microsoft.com/windows/apps/develop/communication/copy-and-paste"}]},{"id":"clipboard-2","controlId":"clipboard","controlName":"Clipboard","headerText":"Paste text from the Clipboard","xaml":"\u003CButton Content=\u0022Paste Text from the Clipboard\u0022 Click=\u0022PasteText_Click\u0022/\u003E","csharp":"private async void PasteText_Click(object sender, RoutedEventArgs args)\n{\n\tvar package = Clipboard.GetContent();\n\tif (package.Contains(StandardDataFormats.Text))\n\t{\n\t\tvar text = await package.GetTextAsync();\n\t}\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Copy and paste text, images, and files to and from the system Clipboard.","relatedControls":["StoragePickers"],"apiNamespace":"Windows.ApplicationModel.DataTransfer","docs":[{"title":"Clipboard - API","uri":"https://learn.microsoft.com/uwp/api/windows.applicationmodel.datatransfer.clipboard"},{"title":"ClipboardContentOptions - API","uri":"https://learn.microsoft.com/uwp/api/windows.applicationmodel.datatransfer.clipboardcontentoptions"},{"title":"Copy and paste - Guide","uri":"https://learn.microsoft.com/windows/apps/develop/communication/copy-and-paste"}]},{"id":"clipboard-3","controlId":"clipboard","controlName":"Clipboard","headerText":"Copy and paste an image","xaml":null,"csharp":"private void CopyImage_Click(object sender, RoutedEventArgs args)\n{\n var package = new DataPackage();\n var imageUri = new Uri(\u0022ms-appx:///Assets/YourImage.png\u0022);\n package.SetBitmap(RandomAccessStreamReference.CreateFromUri(imageUri));\n Clipboard.SetContent(package);\n}\n\nprivate async void PasteImage_Click(object sender, RoutedEventArgs args)\n{\n var package = Clipboard.GetContent();\n if (package.Contains(StandardDataFormats.Bitmap))\n {\n var imageReference = await package.GetBitmapAsync();\n using (var imageStream = await imageReference.OpenReadAsync())\n {\n var bitmapImage = new BitmapImage();\n bitmapImage.SetSource(imageStream);\n PastedImage.Source = bitmapImage;\n }\n }\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Copy and paste text, images, and files to and from the system Clipboard.","relatedControls":["StoragePickers"],"apiNamespace":"Windows.ApplicationModel.DataTransfer","docs":[{"title":"Clipboard - API","uri":"https://learn.microsoft.com/uwp/api/windows.applicationmodel.datatransfer.clipboard"},{"title":"ClipboardContentOptions - API","uri":"https://learn.microsoft.com/uwp/api/windows.applicationmodel.datatransfer.clipboardcontentoptions"},{"title":"Copy and paste - Guide","uri":"https://learn.microsoft.com/windows/apps/develop/communication/copy-and-paste"}]},{"id":"clipboard-4","controlId":"clipboard","controlName":"Clipboard","headerText":"Copy and paste files","xaml":null,"csharp":"private async void CopyFiles_Click(object sender, RoutedEventArgs args)\n{\n var filePicker = new FileOpenPicker\n {\n ViewMode = PickerViewMode.List,\n FileTypeFilter = { \u0022*\u0022 }\n };\n\n // Initialize the picker with the current window handle (required in WinUI 3)\n var hwnd = WinRT.Interop.WindowNative.GetWindowHandle(App.MainWindow);\n WinRT.Interop.InitializeWithWindow.Initialize(filePicker, hwnd);\n\n var storageItems = await filePicker.PickMultipleFilesAsync();\n if (storageItems.Count \u003E 0)\n {\n var package = new DataPackage();\n package.SetStorageItems(storageItems);\n package.RequestedOperation = DataPackageOperation.Copy;\n Clipboard.SetContent(package);\n }\n}\n\nprivate async void PasteFiles_Click(object sender, RoutedEventArgs args)\n{\n var package = Clipboard.GetContent();\n if (package.Contains(StandardDataFormats.StorageItems))\n {\n var storageItems = await package.GetStorageItemsAsync();\n var operation = package.RequestedOperation;\n // Display the file names and the requested operation\n }\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Copy and paste text, images, and files to and from the system Clipboard.","relatedControls":["StoragePickers"],"apiNamespace":"Windows.ApplicationModel.DataTransfer","docs":[{"title":"Clipboard - API","uri":"https://learn.microsoft.com/uwp/api/windows.applicationmodel.datatransfer.clipboard"},{"title":"ClipboardContentOptions - API","uri":"https://learn.microsoft.com/uwp/api/windows.applicationmodel.datatransfer.clipboardcontentoptions"},{"title":"Copy and paste - Guide","uri":"https://learn.microsoft.com/windows/apps/develop/communication/copy-and-paste"}]},{"id":"clipboard-5","controlId":"clipboard","controlName":"Clipboard","headerText":"Clipboard history and roaming options","xaml":null,"csharp":"private void CopyWithOptions_Click(object sender, RoutedEventArgs args)\n{\n var package = new DataPackage();\n package.SetText(\u0022Text with clipboard options\u0022);\n\n var options = new ClipboardContentOptions();\n options.IsAllowedInHistory = true;\n options.IsRoamable = true;\n\n Clipboard.SetContentWithOptions(package, options);\n}","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Copy and paste text, images, and files to and from the system Clipboard.","relatedControls":["StoragePickers"],"apiNamespace":"Windows.ApplicationModel.DataTransfer","docs":[{"title":"Clipboard - API","uri":"https://learn.microsoft.com/uwp/api/windows.applicationmodel.datatransfer.clipboard"},{"title":"ClipboardContentOptions - API","uri":"https://learn.microsoft.com/uwp/api/windows.applicationmodel.datatransfer.clipboardcontentoptions"},{"title":"Copy and paste - Guide","uri":"https://learn.microsoft.com/windows/apps/develop/communication/copy-and-paste"}]},{"id":"clipboard-6","controlId":"clipboard","controlName":"Clipboard","headerText":"Other clipboard operations","xaml":null,"csharp":"// Show available formats on the clipboard\nvar package = Clipboard.GetContent();\nforeach (var format in package.AvailableFormats)\n{\n // Display each format\n}\n\n// Clear the clipboard\nClipboard.Clear();\n\n// Register for clipboard content changes\nClipboard.ContentChanged \u002B= (s, e) =\u003E\n{\n // Handle clipboard content change\n};","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Copy and paste text, images, and files to and from the system Clipboard.","relatedControls":["StoragePickers"],"apiNamespace":"Windows.ApplicationModel.DataTransfer","docs":[{"title":"Clipboard - API","uri":"https://learn.microsoft.com/uwp/api/windows.applicationmodel.datatransfer.clipboard"},{"title":"ClipboardContentOptions - API","uri":"https://learn.microsoft.com/uwp/api/windows.applicationmodel.datatransfer.clipboardcontentoptions"},{"title":"Copy and paste - Guide","uri":"https://learn.microsoft.com/windows/apps/develop/communication/copy-and-paste"}]},{"id":"storagepickers-1","controlId":"storagepickers","controlName":"Storage pickers","headerText":"Pick single file","xaml":"\u003CStackPanel Spacing=\u00228\u0022\u003E\n \u003CButton x:Name=\u0022PickSingleFileButton\u0022 Content=\u0022Pick a single file\u0022 Click=\u0022PickSingleFileButton_Click\u0022/\u003E\n \u003CTextBlock x:Name=\u0022PickedSingleFileTextBlock\u0022 Text=\u0022No file picked\u0022/\u003E\n\u003C/StackPanel\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Select files and folders with modern system pickers.","relatedControls":["Clipboard"],"apiNamespace":"Microsoft.Windows.Storage.Pickers","docs":[{"title":"FileOpenPicker - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.windows.storage.pickers.fileopenpicker"},{"title":"FileSavePicker - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.windows.storage.pickers.filesavepicker"},{"title":"FolderPicker - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.windows.storage.pickers.folderpicker"}]},{"id":"storagepickers-2","controlId":"storagepickers","controlName":"Storage pickers","headerText":"Pick multiple files","xaml":"\u003CStackPanel Spacing=\u00228\u0022\u003E\n \u003CButton x:Name=\u0022PickMultipleFilesButton\u0022 Content=\u0022Pick multiple files\u0022 Click=\u0022PickMultipleFilesButton_Click\u0022/\u003E\n \u003CTextBlock x:Name=\u0022PickedMultipleFilesTextBlock\u0022 Text=\u0022No files picked\u0022/\u003E\n\u003C/StackPanel\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Select files and folders with modern system pickers.","relatedControls":["Clipboard"],"apiNamespace":"Microsoft.Windows.Storage.Pickers","docs":[{"title":"FileOpenPicker - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.windows.storage.pickers.fileopenpicker"},{"title":"FileSavePicker - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.windows.storage.pickers.filesavepicker"},{"title":"FolderPicker - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.windows.storage.pickers.folderpicker"}]},{"id":"storagepickers-3","controlId":"storagepickers","controlName":"Storage pickers","headerText":"Save file","xaml":"\u003CStackPanel Spacing=\u00228\u0022\u003E\n \u003CTextBox x:Name=\u0022FileContentTextBox\u0022 Header=\u0022File content\u0022 TextWrapping=\u0022Wrap\u0022 AcceptsReturn=\u0022True\u0022\n Width=\u0022500\u0022 Height=\u0022200\u0022 Text=\u0022Hello, WinUI!\u0022 IsSpellCheckEnabled=\u0022False\u0022 /\u003E\n \u003CButton x:Name=\u0022SaveFileButton\u0022 Content=\u0022Save a file\u0022 Click=\u0022SaveFileButton_Click\u0022 /\u003E\n \u003CTextBlock x:Name=\u0022SavedFileTextBlock\u0022 Grid.Column=\u00221\u0022 Text=\u0022No file saved\u0022 /\u003E\n\u003C/StackPanel\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Select files and folders with modern system pickers.","relatedControls":["Clipboard"],"apiNamespace":"Microsoft.Windows.Storage.Pickers","docs":[{"title":"FileOpenPicker - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.windows.storage.pickers.fileopenpicker"},{"title":"FileSavePicker - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.windows.storage.pickers.filesavepicker"},{"title":"FolderPicker - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.windows.storage.pickers.folderpicker"}]},{"id":"storagepickers-4","controlId":"storagepickers","controlName":"Storage pickers","headerText":"Pick folder","xaml":"\u003CStackPanel Spacing=\u00228\u0022\u003E\n \u003CButton x:Name=\u0022PickFolderButton\u0022 Content=\u0022Pick a folder\u0022 Click=\u0022PickFolderButton_Click\u0022 /\u003E\n \u003CTextBlock x:Name=\u0022PickedFolderTextBlock\u0022 Text=\u0022No folder picked\u0022 /\u003E\n\u003C/StackPanel\u003E","csharp":null,"source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Select files and folders with modern system pickers.","relatedControls":["Clipboard"],"apiNamespace":"Microsoft.Windows.Storage.Pickers","docs":[{"title":"FileOpenPicker - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.windows.storage.pickers.fileopenpicker"},{"title":"FileSavePicker - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.windows.storage.pickers.filesavepicker"},{"title":"FolderPicker - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.windows.storage.pickers.folderpicker"}]},{"id":"storagepickers-5","controlId":"storagepickers","controlName":"Storage pickers","headerText":"Pick a file and display its thumbnail","xaml":"\u003CStackPanel Spacing=\u00228\u0022 Orientation=\u0022Horizontal\u0022\u003E\n \u003CStackPanel Spacing=\u00228\u0022\u003E\n \u003CButton x:Name=\u0022PickFileForThumbnailButton\u0022 Content=\u0022Pick a file\u0022 Click=\u0022PickFileForThumbnailButton_Click\u0022/\u003E\n \u003CTextBlock x:Name=\u0022ThumbnailDetailsTextBlock\u0022 Text=\u0022No file picked\u0022 TextWrapping=\u0022Wrap\u0022/\u003E\n \u003C/StackPanel\u003E\n \u003CBorder Width=\u0022160\u0022 Height=\u0022160\u0022 Background=\u0022{ThemeResource SubtleFillColorTertiaryBrush}\u0022\n CornerRadius=\u00224\u0022 HorizontalAlignment=\u0022Left\u0022\u003E\n \u003CImage x:Name=\u0022ThumbnailImage\u0022 Stretch=\u0022Uniform\u0022 AutomationProperties.Name=\u0022File thumbnail\u0022/\u003E\n \u003C/Border\u003E\n\u003C/StackPanel\u003E","csharp":"private async void PickFileForThumbnailButton_Click(object sender, RoutedEventArgs e)\n{\n if (sender is Button button)\n {\n button.IsEnabled = false;\n\n // 1) Pick a file using the new WinAppSDK Microsoft.Windows.Storage.Pickers API.\n var picker = new FileOpenPicker(button.XamlRoot.ContentIslandEnvironment.AppWindowId);\n picker.FileTypeFilter.Add(\u0022*\u0022);\n\n var pickResult = await picker.PickSingleFileAsync();\n if (pickResult == null)\n {\n ThumbnailDetailsTextBlock.Text = \u0022No file selected.\u0022;\n ThumbnailImage.Source = null;\n button.IsEnabled = true;\n return;\n }\n\n // 2) The new picker returns a path string; bridge to a StorageFile to access\n // thumbnail APIs (Windows.Storage.FileProperties has no WinAppSDK replacement).\n var file = await Windows.Storage.StorageFile.GetFileFromPathAsync(pickResult.Path);\n\n var thumbnailMode = (Windows.Storage.FileProperties.ThumbnailMode)ThumbnailModeComboBox.SelectedItem;\n\n // NumberBox.Value is NaN when the user clears the field; fall back to a sane default.\n double rawSize = ThumbnailSizeNumberBox.Value;\n uint size = double.IsNaN(rawSize) || rawSize \u003C= 0 ? 200u : (uint)rawSize;\n\n // 3) Request the thumbnail. ThumbnailMode hints how the system should render it\n // (e.g. PicturesView for photos, MusicView for album art, DocumentsView for icons).\n // Some modes throw for incompatible file types (e.g. PicturesView on a .txt file),\n // so wrap the call and report the failure to the user.\n try\n {\n using var thumbnail = await file.GetThumbnailAsync(\n thumbnailMode, size, Windows.Storage.FileProperties.ThumbnailOptions.UseCurrentScale);\n if (thumbnail != null)\n {\n var bitmap = new Microsoft.UI.Xaml.Media.Imaging.BitmapImage();\n await bitmap.SetSourceAsync(thumbnail);\n ThumbnailImage.Source = bitmap;\n\n ThumbnailDetailsTextBlock.Text =\n $\u0022File: {file.Name}\\n\u0022 \u002B\n $\u0022Mode: ThumbnailMode.{thumbnailMode}\\n\u0022 \u002B\n $\u0022Requested size: {size}\\n\u0022 \u002B\n $\u0022Returned size: {thumbnail.OriginalWidth} x {thumbnail.OriginalHeight}\u0022;\n }\n else\n {\n ThumbnailImage.Source = null;\n ThumbnailDetailsTextBlock.Text = \u0022No thumbnail available for the selected file.\u0022;\n }\n }\n catch (Exception ex)\n {\n ThumbnailImage.Source = null;\n ThumbnailDetailsTextBlock.Text =\n}}}\n// NOTE: snippet truncated \u2014 refer to full sample for additional code","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Select files and folders with modern system pickers.","relatedControls":["Clipboard"],"apiNamespace":"Microsoft.Windows.Storage.Pickers","docs":[{"title":"FileOpenPicker - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.windows.storage.pickers.fileopenpicker"},{"title":"FileSavePicker - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.windows.storage.pickers.filesavepicker"},{"title":"FolderPicker - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.windows.storage.pickers.folderpicker"}]},{"id":"appnotification-1","controlId":"appnotification","controlName":"App notifications","headerText":"Basic notification","xaml":null,"csharp":"AppNotification notification = new AppNotificationBuilder()\n .AddText(\u0022Welcome to WinUI 3 Gallery\u0022)\n .AddText(\u0022Explore interactive samples and discover the power of modern Windows UI.\u0022)\n .BuildNotification();\n\nAppNotificationManager.Default.Show(notification);","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Send notifications that appear in the Action Center and as toast popups.","relatedControls":["BadgeNotificationManager"],"apiNamespace":"Microsoft.Windows.Notifications","docs":[{"title":"AppNotification - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.windows.appnotifications.appnotification"},{"title":"AppNotificationManager - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.windows.appnotifications.appnotificationmanager"},{"title":"AppNotificationBuilder - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.windows.appnotifications.builder.appnotificationbuilder"},{"title":"Toast notifications","uri":"https://learn.microsoft.com/windows/apps/design/shell/tiles-and-notifications/toast-notifications-overview"}]},{"id":"appnotification-2","controlId":"appnotification","controlName":"App notifications","headerText":"Visual notification with hero image and attribution","xaml":null,"csharp":"AppNotification notification = new AppNotificationBuilder()\n .AddText(\u0022Harbor Scene with Boats\u0022)\n .AddText(\u0022A quiet harbor with boats gently anchored in view.\u0022)\n .SetHeroImage(new Uri(\u0022ms-appx:///Assets/YourImage.png\u0022))\n .SetAttributionText(\u0022WinUI gallery assets\u0022)\n .BuildNotification();\n\nAppNotificationManager.Default.Show(notification);","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Send notifications that appear in the Action Center and as toast popups.","relatedControls":["BadgeNotificationManager"],"apiNamespace":"Microsoft.Windows.Notifications","docs":[{"title":"AppNotification - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.windows.appnotifications.appnotification"},{"title":"AppNotificationManager - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.windows.appnotifications.appnotificationmanager"},{"title":"AppNotificationBuilder - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.windows.appnotifications.builder.appnotificationbuilder"},{"title":"Toast notifications","uri":"https://learn.microsoft.com/windows/apps/design/shell/tiles-and-notifications/toast-notifications-overview"}]},{"id":"appnotification-3","controlId":"appnotification","controlName":"App notifications","headerText":"Notification with AppNotification controls","xaml":null,"csharp":"AppNotification notification = new AppNotificationBuilder()\n .AddText(\u0022Survey\u0022)\n .AddText(\u0022Please select your satisfaction level and leave a comment.\u0022)\n .AddComboBox(new AppNotificationComboBox(\u0022satisfaction\u0022)\n .AddItem(\u00221\u0022, \u0022Very Bad\u0022)\n .AddItem(\u00222\u0022, \u0022Bad\u0022)\n .AddItem(\u00223\u0022, \u0022Neutral\u0022)\n .AddItem(\u00224\u0022, \u0022Good\u0022)\n .AddItem(\u00225\u0022, \u0022Excellent\u0022)\n .SetSelectedItem(\u00223\u0022))\n .AddTextBox(\u0022comment\u0022, \u0022Leave a comment here...\u0022,\u0022\u0022)\n .AddButton(new AppNotificationButton(\u0022Submit\u0022)\n .AddArgument(\u0022action\u0022, \u0022submit_survey\u0022))\n .BuildNotification();\n\nAppNotificationManager.Default.Show(notification);","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Send notifications that appear in the Action Center and as toast popups.","relatedControls":["BadgeNotificationManager"],"apiNamespace":"Microsoft.Windows.Notifications","docs":[{"title":"AppNotification - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.windows.appnotifications.appnotification"},{"title":"AppNotificationManager - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.windows.appnotifications.appnotificationmanager"},{"title":"AppNotificationBuilder - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.windows.appnotifications.builder.appnotificationbuilder"},{"title":"Toast notifications","uri":"https://learn.microsoft.com/windows/apps/design/shell/tiles-and-notifications/toast-notifications-overview"}]},{"id":"appnotification-4","controlId":"appnotification","controlName":"App notifications","headerText":"Notification with ProgressBar","xaml":null,"csharp":"AppNotification notification = new AppNotificationBuilder()\n .AddText(\u0022Progress Bar Example\u0022)\n .AddText(\u0022This is a sample notification showing how to use a progress bar.\u0022)\n .AddProgressBar(new AppNotificationProgressBar()\n {\n Title = \u0022Demo Progress\u0022,\n Value = 0.6, // 60%\n ValueStringOverride = \u002260%\u0022,\n Status = \u0022In progress...\u0022\n })\n .BuildNotification();\n\nAppNotificationManager.Default.Show(notification);","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Send notifications that appear in the Action Center and as toast popups.","relatedControls":["BadgeNotificationManager"],"apiNamespace":"Microsoft.Windows.Notifications","docs":[{"title":"AppNotification - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.windows.appnotifications.appnotification"},{"title":"AppNotificationManager - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.windows.appnotifications.appnotificationmanager"},{"title":"AppNotificationBuilder - API","uri":"https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.windows.appnotifications.builder.appnotificationbuilder"},{"title":"Toast notifications","uri":"https://learn.microsoft.com/windows/apps/design/shell/tiles-and-notifications/toast-notifications-overview"}]},{"id":"jumplist-1","controlId":"jumplist","controlName":"JumpList","headerText":"Adding tasks to the jump list","xaml":null,"csharp":"var jumpList = await JumpList.LoadCurrentAsync();\n\nvar task = JumpListItem.CreateWithArguments(\u0022/compose\u0022, \u0022New Message\u0022);\ntask.Description = \u0022Compose a new message\u0022;\ntask.Logo = new Uri(\u0022ms-appx:///Assets/Tiles/AppList.targetsize-48.png\u0022);\n\njumpList.Items.Add(task);\nawait jumpList.SaveAsync();","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Add custom tasks and groups to the app\u0027s taskbar jump list.","relatedControls":[],"apiNamespace":"Windows.UI.StartScreen","docs":[{"title":"JumpList - API","uri":"https://learn.microsoft.com/uwp/api/windows.ui.startscreen.jumplist"},{"title":"JumpListItem - API","uri":"https://learn.microsoft.com/uwp/api/windows.ui.startscreen.jumplistitem"}]},{"id":"jumplist-2","controlId":"jumplist","controlName":"JumpList","headerText":"Adding items to a custom group","xaml":null,"csharp":"var jumpList = await JumpList.LoadCurrentAsync();\n\nvar item = JumpListItem.CreateWithArguments(\u0022/project-alpha\u0022, \u0022Project Alpha\u0022);\nitem.GroupName = \u0022Projects\u0022;\nitem.Description = \u0022Open Project Alpha\u0022;\nitem.Logo = new Uri(\u0022ms-appx:///Assets/Tiles/AppList.targetsize-48.png\u0022);\n\njumpList.Items.Add(item);\nawait jumpList.SaveAsync();","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":null,"controlDescription":"Add custom tasks and groups to the app\u0027s taskbar jump list.","relatedControls":[],"apiNamespace":"Windows.UI.StartScreen","docs":[{"title":"JumpList - API","uri":"https://learn.microsoft.com/uwp/api/windows.ui.startscreen.jumplist"},{"title":"JumpListItem - API","uri":"https://learn.microsoft.com/uwp/api/windows.ui.startscreen.jumplistitem"}]},{"id":"itemsrepeater-7","controlId":"itemsrepeater","controlName":"ItemsRepeater","headerText":"Photo gallery: image grid (UniformGridLayout)","xaml":"\u003C!--\n ItemsRepeater is a layout primitive: it has NO selection and NO scrolling.\n Wrap it in a ScrollView (or ScrollViewer) for scrolling.\n UniformGridLayout sizes every cell uniformly \u2014 set MinItemWidth/Height\n and the layout fills available width with as many columns as fit.\n--\u003E\n\u003CScrollView\u003E\n \u003CItemsRepeater ItemsSource=\u0022{x:Bind ViewModel.Items, Mode=OneWay}\u0022\u003E\n \u003CItemsRepeater.Layout\u003E\n \u003CUniformGridLayout MinItemWidth=\u0022200\u0022\n MinItemHeight=\u0022200\u0022\n MinRowSpacing=\u00228\u0022\n MinColumnSpacing=\u00228\u0022/\u003E\n \u003C/ItemsRepeater.Layout\u003E\n \u003CItemsRepeater.ItemTemplate\u003E\n \u003CDataTemplate x:DataType=\u0022local:PhotoItem\u0022\u003E\n \u003CGrid Width=\u0022200\u0022 Height=\u0022200\u0022\n Background=\u0022{ThemeResource LayerFillColorDefaultBrush}\u0022\n CornerRadius=\u00224\u0022\u003E\n \u003CImage Source=\u0022{x:Bind Thumbnail}\u0022 Stretch=\u0022UniformToFill\u0022/\u003E\n \u003C/Grid\u003E\n \u003C/DataTemplate\u003E\n \u003C/ItemsRepeater.ItemTemplate\u003E\n \u003C/ItemsRepeater\u003E\n\u003C/ScrollView\u003E","csharp":"public sealed partial class PhotoItem\n{\n public string Thumbnail { get; set; } = \u0022\u0022;\n}\n\n// ItemsSource:\n// public ObservableCollection\u003CPhotoItem\u003E Items { get; } = new();","source":"gallery","nugetPackage":null,"xmlnsImports":[],"description":"Canonical pattern for displaying a grid of images/thumbnails: ItemsRepeater \u002B UniformGridLayout, wrapped in a ScrollView for scrolling. Use this instead of GridView\u002BItemsWrapGrid when you want the modern WinUI 3 collection layout.","controlDescription":null,"relatedControls":[],"apiNamespace":null,"docs":[]}] \ No newline at end of file diff --git a/src/tools/winui-search/Data/gallery-tags.json b/src/tools/winui-search/Data/gallery-tags.json deleted file mode 100644 index cfc359be..00000000 --- a/src/tools/winui-search/Data/gallery-tags.json +++ /dev/null @@ -1 +0,0 @@ -{"xamlresources":["xamlresources","reusable","definitions","shared","ensure","consistency","maintainability"],"xamlstyles":["xamlstyles","style","reusable","settings","define","consistent","design"],"binding":["binding","connecting","data","automatic","synchronization","updates"],"templates":["templates","customize","visuals","layouts","data","presentation"],"customusercontrols":["customusercontrols","reusable","components","appearance"],"customxamlconditionals":["customxamlconditionals","conditions","define","evaluated","parse","time","ixaml","condition","conditionally","include","markup","application"],"scratchpad":["scratchpad","scratch","pad","testing","markup"],"color":["color","balanced","design","creates","clarity","aesthetic","harmony"],"geometry":["geometry","clear","geometric","design","ensures","visual","coherence","structure"],"iconography":["iconography","icons","visual","design","language","communicate","information","quickly","effectively"],"spacing":["spacing","thoughtful","design","enhances","readability","flow"],"typography":["typography","design","guides","attention","intuitive","fonts","hierarchy"],"accessibilitycolorcontrast":["accessibilitycolorcontrast","high","contrast","design","ensures","accessibility","users"],"accessibilitykeyboard":["accessibilitykeyboard","keyboard-friendly","design","enables","seamless","interactions"],"accessibilityscreenreader":["accessibilityscreenreader","inclusive","design","ensures","meaningful","assistive","technologies"],"appbarbutton":["appbarbutton","button","styled","commandbar","toolbar"],"appbarseparator":["appbarseparator","separator","divider","toolbar","vertical","line","visually","separate","groups","commands","bar"],"appbartogglebutton":["appbartogglebutton","appbar","toggle","toolbar","button","off","indeterminate","checkbox","styled","bar","other","specialized"],"commandbar":["commandbar","command","toolbar","appbar","action bar","application-specific","commands","handles","resizing","contents","button","buttons","actions","menu"],"commandbarflyout":["commandbarflyout","commandbar","flyout","context","toolbar","mini-toolbar","proactive","commands","optional","menu"],"menubar":["menubar","menu","bar","file menu","edit menu","classic","allowing","menuitems","menuflyoutitems"],"menuflyout":["menuflyout","context menu","right-click","flyout","menu","contextual","list","commands","dropdown"],"swipecontrol":["swipecontrol","swipe","gesture","reveal","action","delete","touch","quick","menu","actions"],"standarduicommand":["standarduicommand","command","standard","delete","copy","paste","built-in","xamluicommand","commonly","save"],"xamluicommand":["xamluicommand","command","keyboard","accelerator","define","feel","given"],"flipview":["flipview","flip","carousel","slideshow","image","swipe","collection","one","time"],"gridview":["gridview","grid","gallery","tile","image gallery","wrap","collection","rows","columns","virtualized"],"itemsrepeater":["itemsrepeater","repeater","custom layout","virtualized","flexible","grid","gallery","image","uniformgridlayout","primitive","data-driven","layouts"],"itemsview":["itemsview","collection","layouts","uniformgridlayout","stacklayout","linedflowlayout","swappable","grid","gallery","image","virtualized","flexible","selection","invocation"],"listview":["listview","list","scroll","select","virtualized","data","collection","vertical","table","columns","column","sort","sorting","editable","datagrid","rows","details"],"pulltorefresh":["pulltorefresh","pull","refresh","swipe down","reload","provides","ability","collection","list","grid","contents"],"treeview":["treeview","tree","hierarchy","folder","node","expand","collapse","navigation","sidebar","lazy","hierarchical","drag","drop","drag and drop","reorder","nodes","nested"],"calendardatepicker":["calendardatepicker","calendar","date","picker","popup","users","datepicker"],"calendarview":["calendarview","calendar","date","month","schedule","choose"],"datepicker":["datepicker","date","picker","day","month","year"],"timepicker":["timepicker","time","picker","hour","minute","clock","configurable"],"button":["button","click","action","press","responds","raises","event"],"dropdownbutton":["dropdownbutton","dropdown","button","menu","split","flyout","choices","clicked"],"hyperlinkbutton":["hyperlinkbutton","hyperlink","link","url","navigate","button","appears","uri","handle","click","event"],"repeatbutton":["repeatbutton","repeat","hold","increment","button","raises","click","event","repeatedly","time","pressed","until","released"],"togglebutton":["togglebutton","toggle","button","off","switched","two","states","checkbox"],"splitbutton":["splitbutton","split","button","dropdown","default action","two-part","flyout","secondary","part","clicked"],"togglesplitbutton":["togglesplitbutton","toggle","split","button","version","splitbutton","activation","target","toggles","off"],"checkbox":["checkbox","check","toggle","boolean","option","select","clear","group","multiple","multiselect"],"colorpicker":["colorpicker","color","picker","palette","hex","rgb","selectable","spectrum"],"combobox":["combobox","combo","dropdown","select","picker","list","drop-down"],"radiobutton":["radiobutton","radio","option","select one","group","select","single"],"ratingcontrol":["ratingcontrol","rating","stars","score","review","rate","something"],"slider":["slider","range","drag","track","select","moving","thumb","along"],"toggleswitch":["toggleswitch","toggle","switch","off","toggled","states"],"infobadge":["infobadge","badge","count","notification","dot","non-intrusive","notifications","bring","focus","area"],"infobar":["infobar","info","warning","error","success","notification","banner","alert","inline","message","app-wide","status","change","information","snackbar","toast"],"progressbar":["progressbar","progress","loading","bar","determinate","indeterminate","apps","task","performing","ongoing","work","doesn","block","interaction"],"progressring":["progressring","progress","loading","spinner","ring","circular","apps","task","performing","ongoing","work","block","interaction"],"tooltip":["tooltip","tip","hover","help","information","pop-up","window"],"contentdialog":["contentdialog","dialog","modal","popup","confirm","alert","save","discard","box","customized"],"flyout":["flyout","popup","lightweight","dismiss","tooltip","contextual","information","enables","interaction"],"popup":["popup","overlay","floating","layer","temporary","existing"],"teachingtip":["teachingtip","teaching","tip","tutorial","onboarding","hint","callout","content-rich","flyout","guiding","users","enabling","moments","popup","snackbar"],"annotatedscrollbar":["annotatedscrollbar","scrollbar","annotated","labels","markers","extends","regular","vertical","navigation","large","collections"],"pipspager":["pipspager","pager","dots","pagination","indicator","navigate","paginated","collection","page","numbers","need","visually","known"],"scrollview":["scrollview","scroll","pan","zoom","container"],"scrollviewer":["scrollviewer","scroll","pan","zoom","classic","container"],"semanticzoom":["semanticzoom","zoom","groups","jump","alphabet","two","different","views","collection","making","easier","navigate","large","collections"],"border":["border","frame","outline","container","draws","boundary","line","background","both","around","card"],"canvas":["canvas","absolute","position","overlay","panel","supports","positioning","child","relative","top","left","corner"],"expander":["expander","expand","collapse","accordion","section","details","container","expanded","body","collapsible","card"],"grid":["grid","rows","columns","table","panel","supports","arranging","child","container"],"relativepanel":["relativepanel","relative","adaptive","responsive","panel","uses","relationships","define"],"splitview":["splitview","split","pane","panel","sidebar","container","areas","multiple","drawer","side panel","hamburger","splitter"],"stackpanel":["stackpanel","stack","vertical","horizontal","panel","arranges","child","single","line","oriented","horizontally","vertically","container"],"variablesizedwrapgrid":["variablesizedwrapgrid","wrap","grid","variable","tile","panel","supports","arranging","child","rows","columns","span","multiple"],"viewbox":["viewbox","scale","stretch","fit","resize","container","scales","specified","size"],"breadcrumbbar":["breadcrumbbar","breadcrumb","path","trail","navigation","folder","taken","current","location"],"navigationview":["navigationview","navigation","nav","sidebar","hamburger","menu","pane","common","vertical","top-level","areas","via","collapsible","drawer"],"pivot":["pivot","tabs","swipe","information","different","sources","tabbed","view"],"selectorbar":["selectorbar","selector","segment","segmented","tab","information","small","different","sources","one","tabs"],"tabview":["tabview","tab","tabs","tabbed","document","documents","closable","add tab","browser","collection","reorderable","draggable"],"animatedvisualplayer":["animatedvisualplayer","animation","lottie","player","render","playback","motion","graphics"],"captureelementpreview":["captureelementpreview","camera","capture","preview","webcam","doing"],"image":["image","picture","photo","bitmap"],"mapcontrol":["mapcontrol","map","location","geography","bing","symbolic","earth"],"mediaplayerelement":["mediaplayerelement","media","video","player","playback","image"],"personpicture":["personpicture","avatar","profile","picture","initials","person","contact"],"sound":["sound","audio","spatial","feedback","code-behind","api","enables","sounds"],"webview2":["webview2","webview","web","html","browser","edge","chromium","javascript","microsoft","hosts"],"acrylic":["acrylic","blur","transparent","material","background","mica","translucent","recommended","panel","backgrounds"],"animatedicon":["animatedicon","animated","icon","lottie","motion","animates","interacts"],"compactsizing":["compactsizing","compact","dense","spacing","small","resource","dictionary","enable","sizing"],"iconelement":["iconelement","icon","symbol","glyph","font icon","different","image"],"line":["line","draw","stroke","shape","draws","straight","two","points"],"shape":["shape","rectangle","ellipse","line","polygon","drawing","draw","shapes","ellipses","rectangles","polygons"],"radialgradientbrush":["radialgradientbrush","gradient","radial","brush","background","gradients"],"systembackdrops":["systembackdrops","mica","acrylic","backdrop","material","transparent","system","backdrops","windows"],"systembackdropelement":["systembackdropelement","system","backdrop","host","materials","applies","mica","acrylic","specific","areas","inside","tree"],"themeshadow":["themeshadow","shadow","elevation","depth","drop shadow","adds","depth-aware","system","lighting"],"autosuggestbox":["autosuggestbox","autosuggest","autocomplete","search","filter","suggestion","suggestions","typing"],"numberbox":["numberbox","number","numeric","spin","increment","decimal","integer","evaluation","algebraic","equations"],"passwordbox":["passwordbox","password","secret","login","credential","entering","passwords"],"richeditbox":["richeditbox","rich text","editor","formatting","bold","italic","rtf","rich","editing","supports","formatted","hyperlinks","other"],"richtextblock":["richtextblock","rich text","formatted","paragraph","hyperlinks","inline","images","other","rich"],"textblock":["textblock","label","typography","lightweight","small","amounts"],"textbox":["textbox","field","edit","placeholder","single-line","multi-line","plain","search","editor"],"xamlcompinterop":["xamlcompinterop","composition","interop","visual","layer","animate","expressions","natural","animations"],"connectedanimation":["connectedanimation","connected","animation","transition","shared element","animations","continue","during","page","navigation","help","context","views"],"easingfunction":["easingfunction","easing","animation","curve","timing","way","manipulate","velocity","animates"],"implicittransition":["implicittransition","implicit","animation","transition","automatic","transitions","automatically","animate"],"pagetransition":["pagetransition","page","transition","navigation","animation","transitions","visual","feedback","relationship","pages"],"themetransition":["themetransition","theme","transition","animation","entrance","transitions","pre-packaged","easy-to-apply","animations"],"parallaxview":["parallaxview","parallax","scroll","depth","container","provides","scrolling"],"appwindow":["appwindow","window","size","position","presenter","fullscreen","compact","flexible","customizable","management","system","development"],"appwindowtitlebar":["appwindowtitlebar","provides","window","title","bar"],"createmultiplewindows":["multiwindow","multiple windows","new window","spawn","showing","creation","single-threaded","top","level","windows"],"titlebar":["titlebar","title bar","drag region","caption","chromeless","showing"],"clipboard":["clipboard","copy","paste","cut","data","images","files","system"],"contentisland":["contentisland","island","interop","hosting","hwnd","contentislands","host","other","frameworks"],"storagepickers":["storagepickers","file","picker","open","save","folder","select","files","folders","system","pickers"],"appnotification":["appnotification","notification","toast","push","alert","send","notifications","appear","action","center","popups"],"badgenotificationmanager":["badgenotificationmanager","badge","notification","tile","count","numeric","icon","badges","taskbar"],"jumplist":["jumplist","add","tasks","groups","taskbar","jump","list"],"listbox":["listbox","list","select","inline"],"wrappanel":["wrappanel","wrap","panel","positions","child","left","right","top","bottom","wrapping","next"],"appbarbuttonpage":["appbarbutton","appbar","button","toolbar","icon"],"jumplist-gallery":["jumplist","taskbar","recent","pin","start"]} \ No newline at end of file diff --git a/src/tools/winui-search/Data/reactor-scenarios.json b/src/tools/winui-search/Data/reactor-scenarios.json deleted file mode 100644 index 8369dbc0..00000000 --- a/src/tools/winui-search/Data/reactor-scenarios.json +++ /dev/null @@ -1 +0,0 @@ -[{"id":"acrylic-1","controlId":"acrylic","controlName":"Acrylic","headerText":"Acrylic Brush","xaml":null,"csharp":"AcrylicBrush(\n global::Windows.UI.Color.FromArgb(255, 100, 100, 200),\n tintOpacity: 0.8)","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A translucent material brush that creates a frosted glass effect.","relatedControls":["Theming"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"animated-icon-1","controlId":"animated-icon","controlName":"AnimatedIcon","headerText":"Built-in animated icons","xaml":null,"csharp":"AnimatedIcon(new AnimatedChevronDownSmallVisualSource()).Size(32, 32)\n// AnimatedIcon plays its transition when the host raises a state change\n// (e.g. an Expander toggling). Supply your own IRichAnimatedVisualSource\n// for custom motion.","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"An icon that transitions between states with a vector animation.","relatedControls":["AnimatedVisualPlayer","Icons"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"animated-visual-player-1","controlId":"animated-visual-player","controlName":"AnimatedVisualPlayer","headerText":"Looping animation","xaml":null,"csharp":"AnimatedVisualPlayer().Size(64, 64).OnMount(el =\u003E\n{\n var p = (AnimatedVisualPlayer)el; // OnMount runs once \u2014 .Set re-applies on every update\n p.Source = new AnimatedGlobalNavigationButtonVisualSource();\n _ = p.PlayAsync(0, 1, loop: true);\n})\n// Point Source at your own IAnimatedVisualSource (e.g. a LottieVisualSource\n// or a codegen class produced by the Lottie/Windows toolchain).","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"Plays vector (Lottie/codegen) animations.","relatedControls":["AnimatedIcon","MediaPlayerElement"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"annotated-scroll-bar-1","controlId":"annotated-scroll-bar","controlName":"AnnotatedScrollBar","headerText":"Standalone control surface","xaml":null,"csharp":"Border(AnnotatedScrollBar().Height(300).Width(40))\n .Padding(12)\n .Background(Theme.CardBackground)\n .WithBorder(Theme.DividerStroke)","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A scrollbar that shows labelled annotations along its track.","relatedControls":["ScrollView"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"auto-suggest-box-1","controlId":"auto-suggest-box","controlName":"AutoSuggestBox","headerText":"Basic AutoSuggestBox","xaml":null,"csharp":"var (query, setQuery) = UseState(\u0022\u0022);\nAutoSuggestBox(query, setQuery)","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A text input that shows suggestions as the user types.","relatedControls":["TextBox","ComboBox"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"border-1","controlId":"border","controlName":"Border","headerText":"Basic Border","xaml":null,"csharp":"Border(TextBlock(\u0022Content\u0022).Padding(16))\n .WithBorder(Theme.CardStroke)\n .CornerRadius(8)\n .Background(Theme.SubtleFill)","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A container that draws a border around its child element.","relatedControls":["Card"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"breadcrumb-bar-1","controlId":"breadcrumb-bar","controlName":"BreadcrumbBar","headerText":"Basic BreadcrumbBar","xaml":null,"csharp":"BreadcrumbBar(\n new[] { Breadcrumb(\u0022Home\u0022), Breadcrumb(\u0022Docs\u0022), Breadcrumb(\u0022Reports\u0022) },\n item =\u003E setClicked(item.Label))","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A trail of links showing the user\u0027s navigation path.","relatedControls":["NavigationView"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"button-1","controlId":"button","controlName":"Button","headerText":"Basic Button \u2014 .Click(handler)","xaml":null,"csharp":"Button(\u0022Save\u0022).Click(() =\u003E setOutput(\u0022Saved!\u0022))","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A button that responds to user clicks.","relatedControls":["RepeatButton","ToggleButton","HyperlinkButton","SplitButton"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"calendar-date-picker-1","controlId":"calendar-date-picker","controlName":"CalendarDatePicker","headerText":"Basic CalendarDatePicker","xaml":null,"csharp":"CalendarDatePicker(date, d =\u003E setDate(d))","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A drop-down control that lets a user pick a date from a calendar.","relatedControls":["CalendarView","DatePicker"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"calendar-view-1","controlId":"calendar-view","controlName":"CalendarView","headerText":"Basic CalendarView","xaml":null,"csharp":"CalendarView()","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A calendar display that lets a user select a date.","relatedControls":["CalendarDatePicker","DatePicker"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"canvas-1","controlId":"canvas","controlName":"Canvas","headerText":"Absolute Positioning","xaml":null,"csharp":"Canvas(\n Rectangle().Size(80, 80).Background(\u0022#FF6B6B\u0022).Canvas(left: 10, top: 10),\n Rectangle().Size(80, 80).Background(\u0022#4ECDC4\u0022).Canvas(left: 60, top: 50)\n)","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A layout panel that supports absolute positioning of child elements.","relatedControls":["RelativePanel"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"card-1","controlId":"card","controlName":"Card","headerText":"Override defaults via chained fluents","xaml":null,"csharp":"Card(child).Padding(24).CornerRadius(16)","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A theme-aware preset Border with the WinUI card brushes, corner radius, and padding.","relatedControls":["Border","Expander"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"check-box-1","controlId":"check-box","controlName":"CheckBox","headerText":"Two-State CheckBox","xaml":null,"csharp":"CheckBox(isChecked, v =\u003E setIsChecked(v), \u0022I agree to the terms\u0022)","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A control that a user can select or clear.","relatedControls":["RadioButton","ToggleSwitch"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"color-1","controlId":"color","controlName":"Color","headerText":"Applying Theme Colors","xaml":null,"csharp":"// Foreground\nTextBlock(\u0022Accent text\u0022).Foreground(Theme.Accent)\nTextBlock(\u0022Primary\u0022).Foreground(Theme.PrimaryText)\nTextBlock(\u0022Secondary\u0022).Foreground(Theme.SecondaryText)\nTextBlock(\u0022Hyperlink\u0022).Foreground(Theme.AccentText)\n\n// Background\nBorder(content)\n .Background(Theme.CardBackground)\n .WithBorder(Theme.CardStroke)\n .CornerRadius(6)\n\nBorder(content)\n .Background(Theme.Accent) // accent-filled button\n\n// Border \u0026 Stroke\nBorder(content)\n .WithBorder(Theme.ControlStroke)\n\nBorder(VStack()).Height(1)\n .Background(Theme.DividerStroke) // horizontal divider\n\n// System Signal\nBorder(HStack(icon, message))\n .Background(Theme.SystemSuccessBackground)","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"Guidance on using the WinUI color system and theme resources.","relatedControls":["ColorPicker","Theming","Typography"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"color-picker-1","controlId":"color-picker","controlName":"ColorPicker","headerText":"Basic ColorPicker","xaml":null,"csharp":"ColorPicker(color, c =\u003E setColor(c))","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A control that lets a user pick a color.","relatedControls":["Color"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"combo-box-1","controlId":"combo-box","controlName":"ComboBox","headerText":"Basic ComboBox","xaml":null,"csharp":"ComboBox(colors, selectedIndex, i =\u003E setSelectedIndex(i))","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A drop-down list of items a user can select from.","relatedControls":["ListBox","DropDownButton","AutoSuggestBox"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"command-bar-1","controlId":"command-bar","controlName":"CommandBar","headerText":"Primary Commands","xaml":null,"csharp":"CommandBar(primaryCommands: new AppBarItemBase[] {\n AppBarButton(\u0022Add\u0022, () =\u003E setAction(\u0022Add\u0022), icon: \u0022Add\u0022),\n AppBarButton(\u0022Edit\u0022, () =\u003E setAction(\u0022Edit\u0022), icon: \u0022Edit\u0022),\n AppBarSeparator(),\n AppBarButton(\u0022Delete\u0022, () =\u003E setAction(\u0022Delete\u0022), icon: \u0022Delete\u0022),\n})","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A toolbar for exposing app commands and actions.","relatedControls":["CommandBarFlyout","MenuBar"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"command-bar-flyout-1","controlId":"command-bar-flyout","controlName":"CommandBarFlyout","headerText":"Basic CommandBarFlyout","xaml":null,"csharp":"CommandBarFlyout(\n Button(\u0022Show Commands\u0022),\n primaryCommands: new AppBarItemBase[] {\n AppBarButton(\u0022Cut\u0022, () =\u003E {}, icon: \u0022Cut\u0022),\n AppBarButton(\u0022Copy\u0022, () =\u003E {}, icon: \u0022Copy\u0022),\n AppBarButton(\u0022Paste\u0022, () =\u003E {}, icon: \u0022Paste\u0022),\n })","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A flyout that provides quick access to common commands.","relatedControls":["CommandBar","Flyout","MenuFlyout"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"commands-1","controlId":"commands","controlName":"Commands","headerText":"Sync command","xaml":null,"csharp":"var increment = new Command { Label = \u0022Increment\u0022, Execute = () =\u003E setCount(count \u002B 1) };\nButton(increment) // Label \u002B Execute \u002B IsEnabled all flow from the Command","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"Declarative Command binding with async IsExecuting tracking and debounce.","relatedControls":["Button"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"content-dialog-1","controlId":"content-dialog","controlName":"ContentDialog","headerText":"Basic Dialog","xaml":null,"csharp":"Button(\u0022Show Dialog\u0022, () =\u003E setShow(true)),\nContentDialog(\u0022Welcome\u0022, TextBlock(\u0022Thank you!\u0022), \u0022OK\u0022) with {\n IsOpen = show,\n OnClosed = _ =\u003E setShow(false),\n}","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A modal dialog box that displays content and action buttons.","relatedControls":["Flyout","TeachingTip","Popup"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"data-grid-1","controlId":"data-grid","controlName":"DataGrid","headerText":"Columns, sorting \u0026 selection","xaml":null,"csharp":"using Microsoft.UI.Reactor.Data;\nusing Microsoft.UI.Reactor.Data.Providers;\nusing Microsoft.UI.Reactor.Controls;\n\n// Memoize the source so the grid isn\u0027t remounted on every render\n// (DataGrid keys off source.GetHashCode()).\nvar source = UseMemo(() =\u003E new ListDataSource\u003CProduct\u003E(products, p =\u003E (RowKey)p.Id));\n\nDataGrid(\n source: source,\n columns: new FieldDescriptor[]\n {\n Column\u003CProduct\u003E(\u0022Name\u0022, p =\u003E p.Name, displayName: \u0022Product\u0022, width: 200),\n Column\u003CProduct\u003E(\u0022Price\u0022, p =\u003E p.Price, format: \u0022C2\u0022, width: 100),\n Column\u003CProduct\u003E(\u0022InStock\u0022, p =\u003E p.InStock, displayName: \u0022In stock\u0022, width: 90),\n },\n selectionMode: SelectionMode.Single,\n onSelectionChanged: keys =\u003E setSelectedCount(keys.Count),\n rowHeight: 36)\n// Click a header to sort. Columns can be reordered and resized by dragging.","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A virtualized data grid with sortable columns, selection, and inline editing.","relatedControls":["ListView","PropertyGrid","ItemsView"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"date-picker-1","controlId":"date-picker","controlName":"DatePicker","headerText":"Basic DatePicker","xaml":null,"csharp":"DatePicker(date, d =\u003E setDate(d))","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A control that lets a user pick a date using spinners.","relatedControls":["CalendarDatePicker","TimePicker"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"docking-1","controlId":"docking","controlName":"Docking","headerText":"Two-pane list / detail","xaml":null,"csharp":"using Microsoft.UI.Reactor.Docking;\n\nnew DockManager\n{\n Layout = new DockSplit(Orientation.Horizontal,\n [\n new DockTabGroup([ new DockableContent(\n Title: \u0022Items\u0022, Content: ListBox(Items, selected, setSelected), Key: \u0022items\u0022, CanClose: true) ], Width: 200),\n new DockTabGroup([ new DockableContent(\n Title: \u0022Detail\u0022, Content: detailView, Key: \u0022detail\u0022, CanClose: true) ]),\n ]),\n}.WithKey($\u0022dock-{layoutKey}\u0022).Height(360)\n// Re-key the DockManager to reset the user\u0027s drag-modified layout.","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"Dockable, tearable, and floatable panes with drag-to-rearrange layout.","relatedControls":["TabView","SplitView"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"drop-down-button-1","controlId":"drop-down-button","controlName":"DropDownButton","headerText":"DropDownButton with MenuItems","xaml":null,"csharp":"DropDownButton(\u0022Choose\u0022, MenuItems(\n MenuItem(\u0022Option A\u0022, () =\u003E setSelected(\u0022Option A\u0022)),\n MenuItem(\u0022Option B\u0022, () =\u003E setSelected(\u0022Option B\u0022)),\n MenuItem(\u0022Option C\u0022, () =\u003E setSelected(\u0022Option C\u0022))))","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A button that displays a flyout of choices when clicked.","relatedControls":["SplitButton","MenuFlyout","Button"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"expander-1","controlId":"expander","controlName":"Expander","headerText":"Direction Control","xaml":null,"csharp":"Expander(\u0022Header\u0022, content, true)\n .Direction(ExpandDirection.Up)","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A container that expands and collapses to show or hide content.","relatedControls":["Card"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"flex-1","controlId":"flex","controlName":"Flex","headerText":"Interactive Flex Container","xaml":null,"csharp":"using Microsoft.UI.Reactor.Layout;\n\nnew FlexElement(children)\n{\n Direction = FlexDirection.Row,\n JustifyContent = FlexJustify.SpaceBetween,\n AlignItems = FlexAlign.Center,\n Wrap = FlexWrap.Wrap,\n}","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A flexible layout container inspired by CSS flexbox.","relatedControls":["Grid","StackPanel"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"flip-view-1","controlId":"flip-view","controlName":"FlipView","headerText":"Basic FlipView","xaml":null,"csharp":"FlipView(\n Border(TextBlock(\u0022Item 1\u0022)).Background(\u0022#FF4444\u0022).Size(300, 200),\n Border(TextBlock(\u0022Item 2\u0022)).Background(\u0022#44AA44\u0022).Size(300, 200)\n)","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A control that presents one item at a time with flipping navigation.","relatedControls":["PipsPager","GridView"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"flyout-1","controlId":"flyout","controlName":"Flyout","headerText":"Basic Flyout","xaml":null,"csharp":"Flyout(\n Button(\u0022Show Flyout\u0022),\n TextBlock(\u0022This is flyout content!\u0022).Padding(8))","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A lightweight popup that shows contextual information.","relatedControls":["MenuFlyout","CommandBarFlyout","TeachingTip","Popup"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"frame-1","controlId":"frame","controlName":"Frame","headerText":"Live demo","xaml":null,"csharp":"Frame(target)\n .Navigating(t =\u003E log.Add(\u0022Navigating \u0022 \u002B t.Name))\n .Navigated(t =\u003E log.Add(\u0022Navigated \u0022 \u002B t.Name))\n .NavigationFailed((t, ex) =\u003E log.Add($\u0022Failed {t.Name}: {ex.Message}\u0022))","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A container that hosts Page navigation, raising .Navigated / .Navigating / .NavigationFailed.","relatedControls":["NavigationView"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"geometry-1","controlId":"geometry","controlName":"Geometry","headerText":"Corner Radius Resources","xaml":null,"csharp":"// Resolve at render time\nvar controlRadius = ThemeResource.CornerRadius(\u0022ControlCornerRadius\u0022);\nvar overlayRadius = ThemeResource.CornerRadius(\u0022OverlayCornerRadius\u0022);\n\n// Apply to elements\nBorder(content).CornerRadius(controlRadius.TopLeft)\nBorder(dialog).CornerRadius(overlayRadius.TopLeft)","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"Corner radius resources for consistent rounding on controls and overlays.","relatedControls":["Spacing","Color","Typography"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"grid-1","controlId":"grid","controlName":"Grid","headerText":"Column \u0026 Row Spanning","xaml":null,"csharp":"Border(TextBlock(\u0022Header\u0022)).Grid(row: 0, column: 0, columnSpan: 3)\nBorder(TextBlock(\u0022Center\u0022)).Grid(row: 1, column: 1, columnSpan: 2)","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A layout panel that arranges children in rows and columns.","relatedControls":["StackPanel","RelativePanel","UniformGrid"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"grid-view-1","controlId":"grid-view","controlName":"GridView","headerText":"Basic GridView","xaml":null,"csharp":"GridView(\n items.Select(i =\u003E\n Border(TextBlock($\u0022Item {i}\u0022)).Size(100, 100)\n ).ToArray()\n).SelectionMode(ListViewSelectionMode.Multiple)","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A control that displays items in a horizontally wrapping grid.","relatedControls":["ListView","ItemsView","FlipView"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"hyperlink-button-1","controlId":"hyperlink-button","controlName":"HyperlinkButton","headerText":"Navigate to URI","xaml":null,"csharp":"HyperlinkButton(\u0022Go to Microsoft\u0022, new Uri(\u0022https://www.microsoft.com\u0022))","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A button that appears as a hyperlink and navigates to a URI.","relatedControls":["Button"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"icons-1","controlId":"icons","controlName":"Icons","headerText":"Symbol icons","xaml":null,"csharp":"Icon(Symbol.Home)\nIcon(Symbol.Save)\nIcon(Symbol.Delete)\nIcon(Symbol.Setting)","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"Standalone icon elements from Symbol, Font glyph, or Path sources.","relatedControls":["AnimatedIcon","Shapes"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"image-1","controlId":"image","controlName":"Image","headerText":"Image from URI","xaml":null,"csharp":"Image(\u0022ms-appx:///Assets/Square150x150Logo.scale-200.png\u0022)\n .Width(300).Height(300)","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A control that displays an image from a file or URI.","relatedControls":["PersonPicture"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"info-badge-1","controlId":"info-badge","controlName":"InfoBadge","headerText":"Numeric Badge","xaml":null,"csharp":"InfoBadge(count) // numeric badge\nInfoBadge(42)","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A small indicator that conveys status on another element.","relatedControls":["InfoBar"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"info-bar-1","controlId":"info-bar","controlName":"InfoBar","headerText":"Severity fluents","xaml":null,"csharp":"InfoBar(\u0022Success\u0022, \u0022Completed!\u0022).Success().IsClosable(false)\nInfoBar(\u0022Warning\u0022, \u0022Review...\u0022).Warning().IsClosable(false)\nInfoBar(\u0022Error\u0022, \u0022Failed!\u0022 ).Error() .IsClosable(false)\nInfoBar(\u0022Info\u0022, \u0022FYI\u2026\u0022 ).Informational().IsClosable(false)","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A dismissible bar for displaying essential app-level messages.","relatedControls":["InfoBadge","TeachingTip"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"interspersed-grid-1","controlId":"interspersed-grid","controlName":"InterspersedGrid","headerText":"Horizontal proportions","xaml":null,"csharp":"InterspersedGrid(\n Orientation.Horizontal,\n new Element[] { panelA, panelB, panelC },\n new[] { 1.0, 2.0, 1.0 },\n 8,\n i =\u003E Border(Empty()).Width(2).Background(Theme.DividerStroke))\n .Height(160)","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A grid that places proportionally sized panels with separators between them.","relatedControls":["UniformGrid","Grid"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"items-repeater-1","controlId":"items-repeater","controlName":"ItemsRepeater","headerText":"Scrollable repeated rows","xaml":null,"csharp":"ScrollView(\n ItemsRepeater(items, s =\u003E s, (s, i) =\u003E\n Border(TextBlock($\u0022{i \u002B 1}. {s}\u0022))\n .Padding(8)\n .Margin(0, 0, 0, 4)\n .Background(Theme.SubtleFill)\n .CornerRadius(4))\n).Height(260)","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A lightweight, data-driven panel for laying out custom collections.","relatedControls":["ItemsView","ListView"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"items-view-1","controlId":"items-view","controlName":"ItemsView","headerText":"Basic ItemsView","xaml":null,"csharp":"ItemsView(\n products,\n p =\u003E p.Name,\n (p, i) =\u003E Border(VStack(\n TextBlock(p.Name).Bold(),\n TextBlock($\u0022${p.Price:F2}\u0022)\n ))\n)","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A flexible control for displaying collections of data items.","relatedControls":["ListView","GridView","ItemsRepeater"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"list-box-1","controlId":"list-box","controlName":"ListBox","headerText":"Basic ListBox","xaml":null,"csharp":"var (selected, setSelected) = UseState(0);\nListBox(fruits, selected, setSelected)","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A list of selectable items presented inline.","relatedControls":["ComboBox","ListView"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"list-view-1","controlId":"list-view","controlName":"ListView","headerText":"Data-Driven ListView","xaml":null,"csharp":"ListView(\n items, s =\u003E s,\n (s, i) =\u003E HStack(8,\n Border(TextBlock($\u0022{i \u002B 1}\u0022)).Size(28, 28),\n TextBlock(s)\n )\n)","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A control that displays items in a vertical scrolling list.","relatedControls":["GridView","ItemsView","ItemsRepeater","ListBox"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"map-control-1","controlId":"map-control","controlName":"MapControl","headerText":"Interactive map","xaml":null,"csharp":"MapControl(zoomLevel: 4)\n .Height(320).Width(480)\n// Supply a Bing Maps token to load tiles:\n// MapControl(mapServiceToken: mapKey, zoomLevel: 12)","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"Displays an interactive, pannable, zoomable map.","relatedControls":[],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"markdown-1","controlId":"markdown","controlName":"Markdown","headerText":"Formatted markdown","xaml":null,"csharp":"var markdown = @\u0022# Markdown sample\n\nMarkdown renders **bold** text, *italic* text, and \u0060inline code\u0060.\n\n- Create declarative UI\n- Compose reusable components\n- Keep samples readable\u0022;\n\nBorder(Markdown(markdown))\n .Padding(16)\n .Background(Theme.SubtleFill)\n .CornerRadius(8)","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"Renders a Markdown string as a Reactor element tree.","relatedControls":["RichTextBlock"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"media-player-element-1","controlId":"media-player-element","controlName":"MediaPlayerElement","headerText":"Video with transport controls","xaml":null,"csharp":"MediaPlayerElement(\u0022https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4\u0022)\n .Height(280).Width(480)\n// Transport controls are enabled by default; AutoPlay is opt-in:\n// .Set(mpe =\u003E mpe.AutoPlay = true)","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"Embeds audio and video playback with built-in transport controls.","relatedControls":["AnimatedVisualPlayer"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"menu-bar-1","controlId":"menu-bar","controlName":"MenuBar","headerText":"File/Edit/View Menus","xaml":null,"csharp":"MenuBar(\n Menu(\u0022File\u0022,\n MenuItem(\u0022New\u0022, () =\u003E {}, icon: \u0022Page2\u0022),\n MenuItem(\u0022Open\u0022, () =\u003E {}, icon: \u0022OpenFile\u0022),\n MenuSeparator(),\n MenuItem(\u0022Save\u0022, () =\u003E {}, icon: \u0022Save\u0022)),\n Menu(\u0022Edit\u0022,\n MenuItem(\u0022Undo\u0022, () =\u003E {}, icon: \u0022Undo\u0022),\n MenuItem(\u0022Cut\u0022, () =\u003E {}),\n MenuItem(\u0022Copy\u0022, () =\u003E {})))","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A horizontal bar that hosts a set of drop-down menus.","relatedControls":["CommandBar","MenuFlyout"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"menu-flyout-1","controlId":"menu-flyout","controlName":"MenuFlyout","headerText":"Basic MenuFlyout","xaml":null,"csharp":"MenuFlyout(\n Button(\u0022Open Menu\u0022),\n MenuItem(\u0022Cut\u0022, () =\u003E {}, icon: \u0022Cut\u0022),\n MenuItem(\u0022Copy\u0022, () =\u003E {}, icon: \u0022Copy\u0022),\n MenuItem(\u0022Paste\u0022, () =\u003E {}, icon: \u0022Paste\u0022))","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A flyout that displays a list of menu commands.","relatedControls":["Flyout","CommandBarFlyout","MenuBar"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"navigation-view-1","controlId":"navigation-view","controlName":"NavigationView","headerText":"Left-Pane NavigationView","xaml":null,"csharp":"NavigationView(items, content: TextBlock(\u0022Selected: ...\u0022))\nwith {\n SelectedTag = tag,\n OnSelectedTagChanged = t =\u003E setTag(t),\n PaneTitle = \u0022Nav Demo\u0022,\n}","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A side or top navigation pane for app-level navigation.","relatedControls":["BreadcrumbBar","TabView","Pivot","SplitView"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"number-box-1","controlId":"number-box","controlName":"NumberBox","headerText":"Basic NumberBox","xaml":null,"csharp":"NumberBox(value, v =\u003E setValue(v), \u0022Enter a number\u0022)","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A text control for entering numeric values with validation.","relatedControls":["Slider","TextBox"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"parallax-view-1","controlId":"parallax-view","controlName":"ParallaxView","headerText":"Background parallax behind a scrolling list","xaml":null,"csharp":"var (scroller, setScroller) = UseState\u003CUIElement?\u003E(null);\n\n// \u0060background\u0060 must be TALLER than the viewport and have visible vertical\n// structure (bands/image) \u2014 a solid colour has nothing to visibly shift.\nvar parallax = ParallaxView(background, verticalShift: 150);\nif (scroller is not null) parallax = parallax.Source(scroller);\n\nGrid(columns: [GridSize.Star()], rows: [GridSize.Star()],\n parallax.Grid(row: 0, column: 0),\n ListView(rows)\n .Set(lv =\u003E lv.Background = null) // transparent \u2192 background shows through\n .OnMount(el =\u003E setScroller((UIElement)el)) // bind the scroller\n .Grid(row: 0, column: 0))","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"Shifts a background layer as content scrolls for a depth effect.","relatedControls":["ScrollView"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"password-box-1","controlId":"password-box","controlName":"PasswordBox","headerText":"Basic PasswordBox","xaml":null,"csharp":"PasswordBox(password, p =\u003E setPassword(p), \u0022Enter password\u0022)","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A text input that conceals typed characters for secure entry.","relatedControls":["TextBox"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"person-picture-1","controlId":"person-picture","controlName":"PersonPicture","headerText":"Display Name","xaml":null,"csharp":"PersonPicture().DisplayName(\u0022Jane Doe\u0022).Width(64).Height(64)","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A control that displays a circular avatar for a person.","relatedControls":["Image"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"pips-pager-1","controlId":"pips-pager","controlName":"PipsPager","headerText":"Five-page pager","xaml":null,"csharp":"PipsPager(5, pageIndex, index =\u003E setPageIndex(index))\nTextBlock($\u0022Page {pageIndex \u002B 1} of 5\u0022)\nBorder(TextBlock(pageMessages.ElementAt(pageIndex)).Center())","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A pager that represents pages as a row of selectable dots.","relatedControls":["FlipView"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"pivot-1","controlId":"pivot","controlName":"Pivot","headerText":"Basic Pivot","xaml":null,"csharp":"Pivot(\n PivotItem(\u0022All\u0022, TextBlock(\u0022All items\u0022)),\n PivotItem(\u0022Recent\u0022, TextBlock(\u0022Recent items\u0022)),\n PivotItem(\u0022Favorites\u0022, TextBlock(\u0022Favorite items\u0022)))","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A tabbed interface for switching between content sections.","relatedControls":["TabView","SelectorBar"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"popup-1","controlId":"popup","controlName":"Popup","headerText":"Light-dismiss popup","xaml":null,"csharp":"Button(\u0022Show popup\u0022, () =\u003E setOpen(true))\n\nPopup(\n Border(VStack(8,\n TextBlock(\u0022Hello from a Popup\u0022).SemiBold(),\n Button(\u0022Close\u0022, () =\u003E setOpen(false))))\n .Padding(16)\n .Background(Theme.CardBackground)\n .WithBorder(Theme.DividerStroke)\n .CornerRadius(8),\n open,\n () =\u003E setOpen(false))\n .IsLightDismissEnabled()","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A lightweight overlay that displays arbitrary content over the UI.","relatedControls":["Flyout","ContentDialog"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"progress-bar-1","controlId":"progress-bar","controlName":"ProgressBar","headerText":"Determinate ProgressBar","xaml":null,"csharp":"Progress(value).Width(300)","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A horizontal bar that shows progress of an operation.","relatedControls":["ProgressRing"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"progress-ring-1","controlId":"progress-ring","controlName":"ProgressRing","headerText":"Determinate ProgressRing","xaml":null,"csharp":"ProgressRing(value).Width(60).Height(60)","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A circular indicator that shows ongoing progress.","relatedControls":["ProgressBar"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"property-grid-1","controlId":"property-grid","controlName":"PropertyGrid","headerText":"Reflection-based editor","xaml":null,"csharp":"using Microsoft.UI.Reactor.Controls;\nusing System.ComponentModel;\n\nclass Settings : INotifyPropertyChanged\n{\n [PropertyCategory(\u0022Appearance\u0022)] public string Name { get; set; }\n [PropertyCategory(\u0022Transform\u0022)] [PropertyDisplayName(\u0022X Position\u0022)] public double X { get; set; }\n [PropertyReadOnly] public string Id { get; }\n}\n\nvar settings = UseRef(new Settings());\nUseObservable(settings.Current); // re-render on INPC changes\nvar registry = UseMemo(() =\u003E new TypeRegistry());\nPropertyGrid(settings.Current, registry)","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A reflection-driven editor for an object\u0027s properties.","relatedControls":["DataGrid"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"radio-button-1","controlId":"radio-button","controlName":"RadioButton","headerText":"RadioButtons Group","xaml":null,"csharp":"RadioButtons(options, groupIndex, i =\u003E setGroupIndex(i))","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A button that allows a user to select one option from a group.","relatedControls":["RadioButtons","CheckBox"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"radio-buttons-1","controlId":"radio-buttons","controlName":"RadioButtons","headerText":"Choose a size","xaml":null,"csharp":"var sizes = new[] { \u0022Small\u0022, \u0022Medium\u0022, \u0022Large\u0022 };\n\nRadioButtons(sizes, sizeIndex, index =\u003E setSizeIndex(index))\nTextBlock($\u0022Selected size: {sizes.ElementAt(sizeIndex)}\u0022)","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A group of radio buttons where a user selects a single option.","relatedControls":["RadioButton"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"rating-control-1","controlId":"rating-control","controlName":"RatingControl","headerText":"Basic RatingControl","xaml":null,"csharp":"RatingControl(rating, v =\u003E setRating(v))","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A control that lets users provide a star rating.","relatedControls":["Slider"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"refresh-container-1","controlId":"refresh-container","controlName":"RefreshContainer","headerText":"Pull to refresh list","xaml":null,"csharp":"var (items, setItems) = UseState(initialItems);\n\nRefreshContainer(\n ListView(items.Select(i =\u003E (Element)TextBlock(i).Padding(8)).ToArray())\n .Height(240),\n () =\u003E setItems(new[] { $\u0022Refreshed {DateTime.Now:T}\u0022 }\n .Concat(items)\n .ToList()))","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A pull-to-refresh container for scrollable content.","relatedControls":["ScrollView","ListView"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"relative-panel-1","controlId":"relative-panel","controlName":"RelativePanel","headerText":"Basic RelativePanel","xaml":null,"csharp":"RelativePanel(\n Border(\u0022Top-Left\u0022).RelativePanel(name: \u0022topLeft\u0022,\n alignLeftWithPanel: true, alignTopWithPanel: true),\n Border(\u0022Right\u0022).RelativePanel(name: \u0022r\u0022, rightOf: \u0022topLeft\u0022)\n)","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A panel that positions children relative to each other.","relatedControls":["Grid","Canvas"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"repeat-button-1","controlId":"repeat-button","controlName":"RepeatButton","headerText":"Incrementing Counter","xaml":null,"csharp":"HStack(8,\n RepeatButton(\u0022-\u0022, () =\u003E setCount(count - 1)),\n TextBlock($\u0022{count}\u0022),\n RepeatButton(\u0022\u002B\u0022, () =\u003E setCount(count \u002B 1)))","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A button that raises click events repeatedly while pressed.","relatedControls":["Button"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"rich-edit-box-1","controlId":"rich-edit-box","controlName":"RichEditBox","headerText":"Basic RichEditBox","xaml":null,"csharp":"var (text, setText) = UseState(\u0022Type here...\u0022);\nRichEditBox(text, setText).Width(400).Height(150)","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A rich text editing control with formatting support.","relatedControls":["TextBox","RichTextBlock"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"rich-text-block-1","controlId":"rich-text-block","controlName":"RichTextBlock","headerText":"Basic RichTextBlock","xaml":null,"csharp":"RichTextBlock(\u0022This is a simple rich text block...\u0022)","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A control that displays formatted read-only rich text.","relatedControls":["RichEditBox","Markdown"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"scroll-view-1","controlId":"scroll-view","controlName":"ScrollView","headerText":"Vertical ScrollView (modern)","xaml":null,"csharp":"ScrollView(\n VStack(4, items.Select(i =\u003E\n Border(TextBlock($\u0022Item {i}\u0022)).Padding(8)\n ).ToArray())\n)","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A scrollable container for content that exceeds available space.","relatedControls":["RefreshContainer","AnnotatedScrollBar"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"selector-bar-1","controlId":"selector-bar","controlName":"SelectorBar","headerText":"Basic SelectorBar","xaml":null,"csharp":"SelectorBar(\n new[] {\n SelectorBarItem(\u0022Recent\u0022, icon: \u0022Clock\u0022),\n SelectorBarItem(\u0022Shared\u0022, icon: \u0022People\u0022),\n SelectorBarItem(\u0022Favorites\u0022, icon: \u0022Favorite\u0022),\n },\n selectedIndex: idx,\n onSelectedIndexChanged: i =\u003E setIdx(i))","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A bar that lets users switch between different views or modes.","relatedControls":["Pivot","TabView"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"semantic-zoom-1","controlId":"semantic-zoom","controlName":"SemanticZoom","headerText":"Grid and group views","xaml":null,"csharp":"SemanticZoom(\n GridView(items.Select(item =\u003E\n Border(TextBlock(item).Center()).Padding(12)).ToArray()),\n ListView(groups.Select(group =\u003E\n Border(TextBlock(group).SemiBold()).Padding(12)).ToArray())\n).Height(300)","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A control that switches between a zoomed-in and zoomed-out view of data.","relatedControls":["GridView","ListView"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"shapes-1","controlId":"shapes","controlName":"Shapes","headerText":"Filled shapes","xaml":null,"csharp":"Rectangle().Width(80).Height(56).Fill(accentBrush)\nEllipse().Width(72).Height(56).Fill(purpleBrush)\nRectangle().Width(80).Height(56).Fill(greenBrush)\n .Set(r =\u003E { r.RadiusX = 14; r.RadiusY = 14; }) // shapes round via RadiusX/Y, not .CornerRadius","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"Rectangle, Ellipse, Line, and Path vector primitives.","relatedControls":["Icons"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"slider-1","controlId":"slider","controlName":"Slider","headerText":"Basic Slider","xaml":null,"csharp":"Slider(value, 0, 100, v =\u003E setValue(v)).Header(\u0022Volume\u0022)","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A control that lets the user select from a range of values by moving a thumb.","relatedControls":["NumberBox","RatingControl"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"spacing-1","controlId":"spacing","controlName":"Spacing","headerText":"Margin vs Padding","xaml":null,"csharp":"// Margin \u2014 works on ALL elements\nTextBlock(\u0022Hello\u0022).Margin(8)\nVStack(children).Margin(16)\nBorder(child).Margin(12)\n\n// Padding \u2014 only on Border and Control (Button, TextBox, etc.)\nBorder(child).Padding(16) // \u2713 works\nButton(\u0022Go\u0022).Padding(12) // \u2713 works\n\n// VStack/HStack don\u0027t support Padding \u2014 wrap in Border instead:\nBorder(\n VStack(8, items)\n).Padding(16) // \u2713 padding applied to the Border","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"Margin, padding, and stack spacing for consistent layout rhythm.","relatedControls":["Geometry","Typography"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"split-button-1","controlId":"split-button","controlName":"SplitButton","headerText":"Basic SplitButton","xaml":null,"csharp":"SplitButton(\u0022Send\u0022, () =\u003E setLastAction(\u0022Send clicked\u0022), MenuItems(\n MenuItem(\u0022Send now\u0022, () =\u003E setLastAction(\u0022Send now\u0022)),\n MenuItem(\u0022Schedule\u0022, () =\u003E setLastAction(\u0022Schedule\u0022))))","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A button with two parts: a primary action and a flyout menu.","relatedControls":["DropDownButton","ToggleSplitButton","Button"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"split-view-1","controlId":"split-view","controlName":"SplitView","headerText":"Collapsible pane \u002B content","xaml":null,"csharp":"SplitView(\n pane: VStack(8,\n TextBlock(\u0022Pane\u0022).Bold(),\n TextBlock(\u0022Item 1\u0022),\n TextBlock(\u0022Item 2\u0022)\n ).Padding(12),\n content: VStack(8,\n Button(isOpen ? \u0022Close Pane\u0022 : \u0022Open Pane\u0022, () =\u003E setIsOpen(!isOpen)),\n TextBlock(\u0022Main content area\u0022)\n ).Padding(12)\n) with { IsPaneOpen = isOpen }\n.Set(sv =\u003E sv.DisplayMode = SplitViewDisplayMode.Inline)","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A container with a collapsible pane and a content area.","relatedControls":["NavigationView"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"stack-panel-1","controlId":"stack-panel","controlName":"StackPanel","headerText":"VStack (Vertical)","xaml":null,"csharp":"VStack(8,\n Box(\u0022A\u0022), Box(\u0022B\u0022), Box(\u0022C\u0022), Box(\u0022D\u0022)\n)","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A panel that arranges children in a single horizontal or vertical line.","relatedControls":["Grid","Flex"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"swipe-control-1","controlId":"swipe-control","controlName":"SwipeControl","headerText":"Left and right actions","xaml":null,"csharp":"SwipeControl(\n Border(TextBlock(\u0022Swipe me left or right\u0022))\n .Padding(16)\n .Background(Theme.CardBackground),\n leftItems: new[] { new SwipeItemData(\u0022Archive\u0022, () =\u003E { }) },\n rightItems: new[] { new SwipeItemData(\u0022Delete\u0022, () =\u003E { }) })","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A container that reveals swipe commands on its content.","relatedControls":["ListView"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"tab-view-1","controlId":"tab-view","controlName":"TabView","headerText":"Basic TabView","xaml":null,"csharp":"TabView(\n Tab(\u0022Home\u0022, TextBlock(\u0022Home content\u0022)),\n Tab(\u0022Document\u0022, TextBlock(\u0022Document content\u0022)),\n Tab(\u0022Settings\u0022, TextBlock(\u0022Settings content\u0022))\n) with { SelectedIndex = idx, OnSelectedIndexChanged = i =\u003E setIdx(i) }","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A control that displays a set of closable, rearrangeable tabs.","relatedControls":["Pivot","SelectorBar"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"teaching-tip-1","controlId":"teaching-tip","controlName":"TeachingTip","headerText":"Basic TeachingTip","xaml":null,"csharp":"Button(\u0022Show Tip\u0022, () =\u003E setShow(true)),\nTeachingTip(\u0022Welcome!\u0022, \u0022Helpful guidance text.\u0022) with {\n IsOpen = show,\n OnClosed = () =\u003E setShow(false),\n}","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A notification flyout for guiding users through features.","relatedControls":["Flyout","InfoBar","ToolTip"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"text-box-1","controlId":"text-box","controlName":"TextBox","headerText":"Basic TextBox","xaml":null,"csharp":"TextBox(text, v =\u003E setText(v), \u0022Type here...\u0022)","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A single-line or multi-line plain text input field.","relatedControls":["RichEditBox","AutoSuggestBox","PasswordBox","NumberBox"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"theming-1","controlId":"theming","controlName":"Theming","headerText":"Light / Dark Toggle","xaml":null,"csharp":"var (isDark, setIsDark) = UseState(false);\nBorder(content)\n .Set(b =\u003E b.RequestedTheme = isDark\n ? ElementTheme.Dark : ElementTheme.Light)\n .Background(Theme.SolidBackground)","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"Guidance on applying light, dark, and high-contrast themes.","relatedControls":["Color","Acrylic"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"time-picker-1","controlId":"time-picker","controlName":"TimePicker","headerText":"Basic TimePicker","xaml":null,"csharp":"TimePicker(time, t =\u003E setTime(t))","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A control that lets a user pick a time using spinners.","relatedControls":["DatePicker"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"title-bar-1","controlId":"title-bar","controlName":"TitleBar","headerText":"Basic TitleBar","xaml":null,"csharp":"TitleBar(\u0022My Application\u0022)","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A customizable title bar for the application window.","relatedControls":[],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"toggle-button-1","controlId":"toggle-button","controlName":"ToggleButton","headerText":"Basic ToggleButton","xaml":null,"csharp":"ToggleButton(\u0022Mute\u0022, isChecked, v =\u003E setIsChecked(v))","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A button that can be toggled between two states.","relatedControls":["ToggleSwitch","ToggleSplitButton","Button"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"toggle-split-button-1","controlId":"toggle-split-button","controlName":"ToggleSplitButton","headerText":"Bullets toggle","xaml":null,"csharp":"ToggleSplitButton(\u0022Bullets\u0022, bulletsOn, value =\u003E setBulletsOn(value))\n\nTextBlock(bulletsOn ? \u0022Bullets are on\u0022 : \u0022Bullets are off\u0022)","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A split button whose primary part toggles on and off.","relatedControls":["SplitButton","ToggleButton"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"toggle-switch-1","controlId":"toggle-switch","controlName":"ToggleSwitch","headerText":"Basic ToggleSwitch","xaml":null,"csharp":"ToggleSwitch(isOn, v =\u003E setIsOn(v))","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A switch that toggles between two mutually exclusive states.","relatedControls":["CheckBox","ToggleButton"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"tool-tip-1","controlId":"tool-tip","controlName":"ToolTip","headerText":"Text ToolTip","xaml":null,"csharp":"Button(\u0022Hover Me\u0022).ToolTip(\u0022This is a simple tooltip\u0022)\nButton(\u0022Save\u0022).ToolTip(\u0022Save document (Ctrl\u002BS)\u0022)","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A popup that displays helpful text when hovering over an element.","relatedControls":["TeachingTip","Flyout"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"tree-view-1","controlId":"tree-view","controlName":"TreeView","headerText":"Deeply Nested TreeView","xaml":null,"csharp":"TreeView(\n TreeNode(\u0022Root\u0022,\n TreeNode(\u0022Level 1A\u0022,\n TreeNode(\u0022Level 2A\u0022,\n TreeNode(\u0022Level 3A\u0022))))\n)","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A hierarchical list with expanding and collapsing nodes.","relatedControls":["ListView"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"type-ramp-1","controlId":"type-ramp","controlName":"Type ramp","headerText":"Type ramp factories \u2014 Title / Subtitle / Body","xaml":null,"csharp":"Title(\u0022Title \u2014 28px Semibold\u0022)\nSubtitle(\u0022Subtitle \u2014 20px Semibold\u0022)\nBodyLarge(\u0022BodyLarge \u2014 18px regular\u0022)\nBodyStrong(\u0022BodyStrong \u2014 14px Semibold\u0022)\nBody(\u0022Body \u2014 14px regular body text\u0022)","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"WinUI 3 type ramp factories \u2014 Title, Subtitle, Body, BodyStrong, BodyLarge.","relatedControls":["Typography","RichTextBlock"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"typography-1","controlId":"typography","controlName":"Typography","headerText":"Text Hierarchy Helpers","xaml":null,"csharp":"Heading(\u0022Heading\u0022) // 28px Bold\nSubHeading(\u0022SubHeading\u0022) // 20px SemiBold\nTextBlock(\u0022Body Text\u0022) // 14px Normal\nCaption(\u0022Caption\u0022) // 12px Normal","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"Guidance on typographic styles, font ramps, and text hierarchy.","relatedControls":["Type ramp","Spacing","Color"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"uniform-grid-1","controlId":"uniform-grid","controlName":"UniformGrid","headerText":"Horizontal fill","xaml":null,"csharp":"UniformGrid(\n Orientation.Horizontal,\n Enumerable.Range(1, 9).Select(i =\u003E\n Border(TextBlock($\u0022{i}\u0022).Center().Foreground(\u0022#FFFFFF\u0022))\n .Background(Theme.Accent)\n .Size(60, 60)\n .Margin(4)\n .CornerRadius(4)).ToArray())","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A panel that arranges children in evenly sized cells.","relatedControls":["WrapGrid","Grid"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"viewbox-1","controlId":"viewbox","controlName":"Viewbox","headerText":"Scaling Content","xaml":null,"csharp":"Viewbox(\n VStack(4, TextBlock(\u0022Hello\u0022).Bold(), TextBlock(\u0022Scaled\u0022))\n)","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A container that scales its child to fill available space.","relatedControls":[],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"web-view-2-1","controlId":"web-view-2","controlName":"WebView2","headerText":"Load URL","xaml":null,"csharp":"WebView2(new Uri(\u0022https://learn.microsoft.com\u0022))\n .Width(600).Height(400)","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A control that hosts web content using the Edge rendering engine.","relatedControls":[],"apiNamespace":"Microsoft.UI.Reactor","docs":[]},{"id":"wrap-grid-1","controlId":"wrap-grid","controlName":"WrapGrid","headerText":"Basic WrapGrid","xaml":null,"csharp":"WrapGrid(\n items.Select(i =\u003E\n Border(TextBlock($\u0022{i}\u0022)).Size(70, 70).Margin(4)\n ).ToArray()\n)","source":"reactor","nugetPackage":"Microsoft.UI.Reactor","xmlnsImports":[],"description":null,"controlDescription":"A grid that wraps items to the next row or column automatically.","relatedControls":["UniformGrid","Grid"],"apiNamespace":"Microsoft.UI.Reactor","docs":[]}] \ No newline at end of file diff --git a/src/tools/winui-search/Data/reactor-tags.json b/src/tools/winui-search/Data/reactor-tags.json deleted file mode 100644 index ef967f13..00000000 --- a/src/tools/winui-search/Data/reactor-tags.json +++ /dev/null @@ -1 +0,0 @@ -{"acrylic":["frosted glass","blur","translucent","material","backdrop"],"animated-icon":["lottie","vector animation","state transition","micro-interaction","animated glyph"],"animated-visual-player":["lottie","vector animation","codegen","playback","composition"],"annotated-scroll-bar":["labelled scrollbar","scroll annotations","track markers","minimap","jump to section"],"auto-suggest-box":["autocomplete","typeahead","suggestions","search box","combobox input"],"border":["container","frame","outline","rounded corners","background wrapper"],"breadcrumb-bar":["breadcrumbs","navigation trail","path bar","hierarchy nav","back navigation"],"button":["click","command","submit","primary action","accent"],"calendar-date-picker":["date input","date dropdown","pick a date","calendar dropdown"],"calendar-view":["calendar","month view","date selection","schedule","multi-date"],"canvas":["absolute positioning","free layout","x y coordinates","overlay positioning"],"card":["surface","tile","elevated container","content card","panel"],"check-box":["tick","boolean","multi-select","select","opt in","tri-state","state"],"color":["theme colors","brushes","accent","palette","system colors"],"color-picker":["color selection","rgb","hex","hue","eyedropper","swatch"],"combo-box":["dropdown","select","picker","options list","single select"],"command-bar":["toolbar","app bar","command buttons","action bar","overflow menu"],"command-bar-flyout":["context menu","quick commands","selection menu","contextual toolbar"],"commands":["command binding","icommand","async execute","can execute","debounce"],"content-dialog":["modal","dialog box","confirm","alert","prompt","popup window"],"data-grid":["table","spreadsheet","rows and columns","sortable","virtualized grid","inline edit","select"],"date-picker":["date input","spinner","pick a date","calendar picker"],"docking":["dock panes","tearable","floating windows","rearrange layout","tool windows","ide layout"],"drop-down-button":["dropdown menu","flyout button","choices","split options"],"expander":["collapsible","accordion","show hide","disclosure","fold"],"flex":["flexbox","css layout","flex row column","justify align","wrap","responsive layout"],"flip-view":["carousel","image gallery","swipe pages","slideshow","paged view"],"flyout":["popup","contextual","attached popup","lightweight dialog","callout"],"frame":["page navigation","navigate","back forward","content host","routing"],"geometry":["corner radius","rounding","shape language","control radius","overlay radius"],"grid":["rows and columns","layout grid","cells","table layout","spanning"],"grid-view":["tile view","thumbnail grid","wrapping items","gallery","card grid","select"],"hyperlink-button":["link","hyperlink","navigate url","web link","anchor"],"icons":["glyph","symbol icon","font icon","path icon","vector icon"],"image":["picture","bitmap","photo","img","asset","uri source"],"info-badge":["notification dot","count badge","status indicator","unread count","dot"],"info-bar":["notification bar","banner","inline message","alert bar","status message","dismissible"],"interspersed-grid":["proportional panels","separators","weighted layout","split panels"],"items-repeater":["virtualized list","custom layout","data template","repeater","bind collection"],"items-view":["collection view","selectable items","select","data list","flexible items"],"list-box":["inline list","selectable list","select","options","multi-select list"],"list-view":["scrolling list","data list","rows","selection","select","virtualized list"],"map-control":["maps","geolocation","pan zoom","markers","interactive map"],"markdown":["md","rich text render","commonmark","formatted text"],"media-player-element":["video","audio","playback","transport controls","player"],"menu-bar":["menus","top menu","file edit view","application menu","menu strip"],"menu-flyout":["context menu","right click menu","dropdown menu","command list"],"navigation-view":["side navigation","hamburger menu","app shell","nav pane","left nav"],"number-box":["numeric input","spinner","stepper","number field","increment decrement"],"parallax-view":["parallax","depth scroll","background shift","scrolling effect"],"password-box":["password","secure input","masked text","credentials","hidden characters"],"person-picture":["avatar","profile picture","contact photo","initials","user image"],"pips-pager":["dots pager","page dots","carousel indicator","pagination dots"],"pivot":["tabs","tabbed view","sections","swipe tabs","headers"],"popup":["overlay","floating content","custom popup","light-dismiss","dismiss","layer"],"progress-bar":["loading bar","progress indicator","percent complete","determinate","linear progress"],"progress-ring":["spinner","loading spinner","busy indicator","circular progress","activity"],"property-grid":["property editor","inspector","reflection editor","settings editor","object properties"],"radio-button":["single choice","option","radio","exclusive select","one of"],"radio-buttons":["radio group","single choice group","option list","exclusive options"],"rating-control":["star rating","rate","review stars","score","five stars"],"refresh-container":["pull to refresh","swipe refresh","reload","pull down"],"relative-panel":["relative layout","align relative","constraints","anchor elements"],"repeat-button":["press and hold","auto repeat","hold to increment","continuous click"],"rich-edit-box":["rich text editor","formatting","rtf","bold italic","word processor"],"rich-text-block":["formatted text","read-only rich text","runs","inline formatting","styled text"],"scroll-view":["scrollable","scroll container","overflow","pan zoom","viewport"],"selector-bar":["segmented control","view switcher","mode toggle","tab bar","filter chips"],"semantic-zoom":["zoom in out","grouped view","jump list","overview detail","pinch zoom"],"shapes":["rectangle ellipse line path","vector shapes","drawing","primitives","geometry shapes"],"slider":["range","drag thumb","volume","seek","value picker"],"spacing":["margin padding","gaps","layout rhythm","whitespace","4px grid"],"split-button":["primary plus menu","action with options","dropdown action","default action"],"split-view":["pane","master detail","collapsible sidebar","navigation pane","drawer"],"stack-panel":["vertical stack","horizontal stack","vstack hstack","linear layout","stack children"],"swipe-control":["swipe actions","swipe to delete","reveal commands","gesture actions"],"tab-view":["tabs","closable tabs","browser tabs","reorderable tabs","document tabs"],"teaching-tip":["coach mark","callout","feature highlight","onboarding","tip popup"],"text-box":["text input","textfield","single line","multiline","form field"],"theming":["light dark","dark mode","high contrast","theme switch","requested theme"],"time-picker":["time input","pick a time","clock spinner","hour minute"],"title-bar":["window title","caption bar","custom titlebar","window chrome","draggable region"],"toggle-button":["press state","on off button","sticky button","toggle","pressed"],"toggle-split-button":["toggle with menu","on off plus options","split toggle"],"toggle-switch":["switch","on off","boolean","enable disable"],"tool-tip":["hover hint","hover text","help popup","hint"],"tree-view":["tree","hierarchy","expandable nodes","folder tree","nested list"],"type-ramp":["text styles","font sizes","title subtitle body","heading","typography ramp"],"typography":["text styles","font hierarchy","headings","type scale","text ramp"],"uniform-grid":["equal cells","grid of equal size","tiles","matrix layout"],"viewbox":["scale to fit","stretch content","zoom fit","proportional scaling"],"web-view-2":["web view","embedded browser","html content","edge webview","browser control"],"wrap-grid":["wrapping layout","flow layout","wrap items","tag cloud","reflow"]} \ No newline at end of file diff --git a/src/tools/winui-search/Data/toolkit-keywords.json b/src/tools/winui-search/Data/toolkit-keywords.json deleted file mode 100644 index d3ac712f..00000000 --- a/src/tools/winui-search/Data/toolkit-keywords.json +++ /dev/null @@ -1 +0,0 @@ -{"advancedcollectionview":["advancedcollectionview","collectionviewsource","data","sorting","filtering","collections"],"incrementalloadingcollection":["incrementalloadingcollection","data","incremental","loading","collections"],"colorpicker":["colorpicker"],"headeredcontentcontrol":["headeredcontentcontrol","headered"],"headereditemscontrol":["headereditemscontrol"],"headeredtreeview":["headeredtreeview","treeview"],"imagecropper":["imagecropper"],"metadatacontrol":["metadatacontrol","metadata"],"constrainedbox":["viewbox","content decorator","constrainedbox"],"dockpanel":["dockpanel"],"staggeredlayout":["staggeredpanel","staggeredlayout"],"staggeredpanel":["staggeredpanel","staggeredlayout"],"switchpresenter":["switch","logic","switchpresenter","contentpresenter","visibility","triggers","converters"],"uniformgrid":["uniformgrid","grid","responsive"],"wraplayout":["wraplayout"],"wrappanel":["wrappanel"],"radialgauge":["radialgauge"],"rangeselector":["rangeselector","double slider","slider rangeslider"],"richsuggestbox":["richsuggestbox"],"segmented":["segmentedcontrol","segmented"],"settingscard":["settingscard","settings"],"settingsexpander":["settingscard","settingsexpander","expander","settings"],"contentsizer":["contentsizer","sizerbase","expander","splitter"],"gridsplitter":["contentsizer","sizerbase","expander"],"propertysizer":["propertysizer","sizerbase","navigationview","splitter"],"tabbedcommandbar":["tabbedcommandbar","commandbar","ribbon"],"tokenizingtextbox":["tokenizingtextbox","tokens"],"colorpickerbutton":["colorpicker"]} \ No newline at end of file diff --git a/src/tools/winui-search/Data/toolkit-scenarios.json b/src/tools/winui-search/Data/toolkit-scenarios.json deleted file mode 100644 index 69465151..00000000 --- a/src/tools/winui-search/Data/toolkit-scenarios.json +++ /dev/null @@ -1 +0,0 @@ -[{"id":"advancedcollectionview-1","controlId":"advancedcollectionview","controlName":"AdvancedCollectionView","headerText":"Basic usage","xaml":"\u003CGrid ColumnSpacing=\u002212\u0022\n RowSpacing=\u00228\u0022\u003E\n \u003CGrid.ColumnDefinitions\u003E\n \u003CColumnDefinition /\u003E\n \u003CColumnDefinition /\u003E\n \u003C/Grid.ColumnDefinitions\u003E\n \u003CGrid.RowDefinitions\u003E\n \u003CRowDefinition Height=\u0022Auto\u0022 /\u003E\n \u003CRowDefinition Height=\u0022Auto\u0022 /\u003E\n \u003CRowDefinition /\u003E\n \u003C/Grid.RowDefinitions\u003E\n \u003CStackPanel Grid.Column=\u00220\u0022\n Grid.ColumnSpan=\u00222\u0022\n Orientation=\u0022Horizontal\u0022\u003E\n \u003CTextBox\n PlaceholderText=\u0022Add new item\u0022 /\u003E\n \u003CButton\n VerticalAlignment=\u0022Bottom\u0022\n Click=\u0022Add_Click\u0022\n Content=\u0022Add\u0022\n Style=\u0022{StaticResource AccentButtonStyle}\u0022 /\u003E\n \u003C/StackPanel\u003E\n \u003CTextBlock Grid.Row=\u00221\u0022\n Text=\u0022Original list\u0022 /\u003E\n \u003CGrid Grid.Row=\u00222\u0022\u003E\u003C/Grid\u003E\u003C/Grid\u003E\n\u003C!-- ...truncated --\u003E","csharp":"using CommunityToolkit.WinUI.Collections;\nusing System.Diagnostics.CodeAnalysis;\n\nnamespace YourApp;\n\npublic sealed partial class YourPage : Page\n{\n public ObservableCollection\u003CEmployee\u003E EmployeeCollection { get; private set; }\n\n public AdvancedCollectionView CollectionView { get; private set; }\n\n public YourPage()\n {\n this.InitializeComponent();\n Setup();\n }\n\n [MemberNotNull(nameof(EmployeeCollection))]\n [MemberNotNull(nameof(CollectionView))]\n private void Setup()\n {\n // left list\n EmployeeCollection = new()\n {\n new() { Name = \u0022Staff\u0022 },\n new() { Name = \u002242\u0022 },\n new() { Name = \u0022Swan\u0022 },\n new() { Name = \u0022Orchid\u0022 },\n new() { Name = \u002215\u0022 },\n new() { Name = \u0022Flame\u0022 },\n new() { Name = \u002216\u0022 },\n new() { Name = \u0022Arrow\u0022 },\n new() { Name = \u0022Tempest\u0022 },\n new() { Name = \u002223\u0022 },\n new() { Name = \u0022Pearl\u0022 },\n new() { Name = \u0022Hydra\u0022 },\n new() { Name = \u0022Lamp Post\u0022 },\n new() { Name = \u00224\u0022 },\n new() { Name = \u0022Looking Glass\u0022 },\n new() { Name = \u00228\u0022 },\n };\n\n // right list\n AdvancedCollectionView acv = new(EmployeeCollection);\n acv.Filter = x =\u003E !int.TryParse(((Employee)x).Name, out _);\n acv.SortDescriptions.Add(new SortDescription\u003CEmployee\u003E(nameof(Employee.Name), SortDirection.Ascending));\n\n CollectionView = acv;\n }\n\n private void Add_Click(object sender, RoutedEventArgs e)\n {\n if (!string.IsNullOrWhiteSpace(NewItemBox.Text))\n {\n EmployeeCollection.Insert(0, new Employee { Name = NewItemBox.Text });\n NewItemBox.Text = \u0022\u0022;\n }\n }\n}\n\n/// \u003Csummary\u003E\n/// A sample class used to show how to use the \u003Csee cref=\u0022AdvancedCollectionView\u0022/\u003E class.\n/// \u003C/summary\u003E\npublic partial class Employee\n{\n /// \u003Csummary\u003E\n /// Gets or sets the name of the person.\n /// \u003C/summary\u003E\n public string? Name { get; set; }\n}","source":"toolkit","nugetPackage":"CommunityToolkit.WinUI.Collections","xmlnsImports":["xmlns:controls=\u0022using:CommunityToolkit.WinUI.Controls\u0022"],"description":"The following is a complete example of how to perform ...","controlDescription":"The AdvancedCollectionView is a collection view implementation that support filtering, sorting and incremental loading. It\u0027s meant to be used in a view or viewmodel.","relatedControls":[],"apiNamespace":null,"docs":[]},{"id":"incrementalloadingcollection-1","controlId":"incrementalloadingcollection","controlName":"IncrementalLoadingCollection","headerText":"Basic usage","xaml":"\u003CGrid\u003E\n \u003CGrid.RowDefinitions\u003E\n \u003CRowDefinition Height=\u0022Auto\u0022 /\u003E\n \u003CRowDefinition Height=\u0022Auto\u0022 /\u003E\n \u003CRowDefinition Height=\u0022*\u0022 /\u003E\n \u003C/Grid.RowDefinitions\u003E\n \u003CStackPanel\u003E\n \u003CButton\n Click=\u0022{x:Bind PeopleSource.RefreshAsync}\u0022\n Content=\u0022Refresh collection\u0022\n Style=\u0022{StaticResource AccentButtonStyle}\u0022 /\u003E\n \u003C/StackPanel\u003E\n \u003CGrid Grid.Row=\u00222\u0022\u003E\n \u003CListView\n ItemsSource=\u0022{x:Bind PeopleSource, Mode=OneWay}\u0022\u003E\n \u003CListView.ItemTemplate\u003E\n \u003CDataTemplate x:DataType=\u0022local:Person\u0022\u003E\n \u003CGrid\u003E\n \u003CGrid.ColumnDefinitions\u003E\n \u003CColumnDefinition Width=\u0022Auto\u0022 /\u003E\n \u003CColumnDefinition /\u003E\n \u003C/Grid.ColumnDefinitions\u003E\u003C/Grid\u003E\u003C/DataTemplate\u003E\u003C/ListView.ItemTemplate\u003E\u003C/ListView\u003E\u003C/Grid\u003E\u003C/Grid\u003E\n\u003C!-- ...truncated --\u003E","csharp":"using CommunityToolkit.WinUI.Collections;\n\nnamespace YourApp;\n\npublic sealed partial class YourPage : Page\n{\n // IncrementalLoadingCollection can be bound to a GridView or a ListView. In this case it is a ListView called PeopleListView.\n public IncrementalLoadingCollection\u003CPeopleSource, Person\u003E PeopleSource { get; set; } = new(new PeopleSource());\n\n public YourPage()\n {\n this.InitializeComponent();\n }\n}\n\n/// \u003Csummary\u003E\n/// A sample implementation of the \u003Csee cref=\u0022IIncrementalSource{TSource}\u0022/\u003E interface.\n/// \u003C/summary\u003E\n/// \u003Cseealso cref=\u0022IIncrementalSource{TSource}\u0022/\u003E\npublic partial class PeopleSource : IIncrementalSource\u003CPerson\u003E\n{\n private readonly List\u003CPerson\u003E _people;\n\n /// \u003Csummary\u003E\n /// Initializes a new instance of the \u003Csee cref=\u0022PeopleSource\u0022/\u003E class.\n /// \u003C/summary\u003E\n public PeopleSource()\n {\n // Creates an example collection.\n _people = new List\u003CPerson\u003E();\n\n for (int i = 1; i \u003C= 200; i\u002B\u002B)\n {\n var p = new Person { Name = \u0022Person \u0022 \u002B i };\n _people.Add(p);\n }\n }\n\n /// \u003Csummary\u003E\n /// Retrieves items based on \u003Cparamref name=\u0022pageIndex\u0022/\u003E and \u003Cparamref name=\u0022pageSize\u0022/\u003E arguments.\n /// \u003C/summary\u003E\n /// \u003Cparam name=\u0022pageIndex\u0022\u003E\n /// The zero-based index of the page that corresponds to the items to retrieve.\n /// \u003C/param\u003E\n /// \u003Cparam name=\u0022pageSize\u0022\u003E\n /// The number of \u003Csee cref=\u0022Person\u0022/\u003E items to retrieve for the specified \u003Cparamref name=\u0022pageIndex\u0022/\u003E.\n /// \u003C/param\u003E\n /// \u003Cparam name=\u0022cancellationToken\u0022\u003E\n /// Used to propagate notification that operation should be canceled.\n /// \u003C/param\u003E\n /// \u003Creturns\u003E\n /// Returns a collection of \u003Csee cref=\u0022Person\u0022/\u003E.\n /// \u003C/returns\u003E\n public async Task\u003CIEnumerable\u003CPerson\u003E\u003E GetPagedItemsAsync(int pageIndex, int pageSize, CancellationToken cancellationToken = default(CancellationToken))\n {\n // Gets items from the collection according to pageIndex and pageSize parameters.\n var result = (from p in _people\n select p).Skip(pageIndex * pageSize).Take(pageSize);\n\n // Simulates a longer request...\n // Make sure the list is still in order after a refresh,\n // even if the first page takes longer to load\n if (pageIndex == 0)\n {\n await Task.Delay(2000);\n }\n else\n {\n await Task.Delay(1000);\n }\n\n return result;\n }\n}\n\n/// \u003Csummary\u003E\n// ...truncated","source":"toolkit","nugetPackage":"CommunityToolkit.WinUI.Collections","xmlnsImports":["xmlns:controls=\u0022using:CommunityToolkit.WinUI.Controls\u0022"],"description":null,"controlDescription":"The IncrementalLoadingCollection helpers greatly simplify the definition and usage of collections whose items can be loaded incrementally only when needed by the view (such as a ScrollViewer).","relatedControls":[],"apiNamespace":null,"docs":[]},{"id":"colorpickerbutton-1","controlId":"colorpickerbutton","controlName":"ColorPickerButton","headerText":"Basic usage","xaml":"\u003CGrid\u003E\n \u003Ccontrols:ColorPickerButton\n SelectedColor=\u0022LightBlue\u0022 /\u003E\n \u003C/Grid\u003E","csharp":"using ColorSpectrumShape = Microsoft.UI.Xaml.Controls.ColorSpectrumShape;\n\nnamespace YourApp;\n\npublic sealed partial class YourPage : Page\n{\n public YourPage()\n {\n this.InitializeComponent();\n }\n}","source":"toolkit","nugetPackage":"CommunityToolkit.WinUI.Controls.ColorPicker","xmlnsImports":["xmlns:controls=\u0022using:CommunityToolkit.WinUI.Controls\u0022"],"description":null,"controlDescription":"An extended color picker control that lets a user pick a color using a color spectrum, sliders, or text input.","relatedControls":[],"apiNamespace":null,"docs":[]},{"id":"colorpicker-1","controlId":"colorpicker","controlName":"ColorPicker","headerText":"Basic usage","xaml":"\u003CGrid\u003E\n \u003Ccontrols:ColorPicker\n ColorSpectrumShape=\u0022{x:Bind local:ColorPickerSample.ConvertStringToColorSpectrumShape(SpectrumShape), Mode=OneWay}\u0022\n IsAlphaEnabled=\u0022{x:Bind AlphaEnabled, Mode=OneWay}\u0022\n IsAlphaSliderVisible=\u0022{x:Bind AlphaSlider, Mode=OneWay}\u0022\n IsColorChannelTextInputVisible=\u0022{x:Bind ColorChannel, Mode=OneWay}\u0022\n IsColorPaletteVisible=\u0022{x:Bind ColorPalette, Mode=OneWay}\u0022\n IsColorSliderVisible=\u0022{x:Bind ColorSlider, Mode=OneWay}\u0022\n IsColorSpectrumVisible=\u0022{x:Bind SpectrumVisible, Mode=OneWay}\u0022\n ShowAccentColors=\u0022{x:Bind AccentColors, Mode=OneWay}\u0022\n Color=\u0022LightBlue\u0022 /\u003E\n \u003C/Grid\u003E","csharp":"using ColorSpectrumShape = Microsoft.UI.Xaml.Controls.ColorSpectrumShape;\n\nnamespace YourApp;\n\npublic sealed partial class YourPage : Page\n{\n public YourPage()\n {\n this.InitializeComponent();\n }\n\n // TODO: See https://github.com/CommunityToolkit/Labs-Windows/issues/149\n \n}","source":"toolkit","nugetPackage":"CommunityToolkit.WinUI.Controls.ColorPicker","xmlnsImports":["xmlns:controls=\u0022using:CommunityToolkit.WinUI.Controls\u0022"],"description":"The ColorPicker control lets a user pick a color using a color spectrum, palette, sliders, or text input.","controlDescription":"An extended color picker control that lets a user pick a color using a color spectrum, sliders, or text input.","relatedControls":[],"apiNamespace":null,"docs":[]},{"id":"headeredcontentcontrol-1","controlId":"headeredcontentcontrol","controlName":"HeaderedContentControl","headerText":"Complex","xaml":"\u003Ccontrols:HeaderedContentControl\n Header=\u0022Complex content\u0022\u003E\n \u003CRelativePanel\u003E\n \u003CImage\n Source=\u0022ms-appx:///Assets/Sunny.png\u0022 /\u003E\n \u003CStackPanel\n RelativePanel.RightOf=\u0022Icon\u0022\u003E\n \u003CTextBlock Text=\u002265\u0022 /\u003E\n \u003C/StackPanel\u003E\n \u003CTextBlock FontSize=\u002212\u0022\n Foreground=\u0022{ThemeResource TextFillColorSecondaryBrush}\u0022\n RelativePanel.AlignLeftWith=\u0022Temp\u0022\n RelativePanel.Below=\u0022Temp\u0022\n Text=\u0022Rainy\u0022 /\u003E\n \u003C/RelativePanel\u003E\n \u003C/controls:HeaderedContentControl\u003E","csharp":"using CommunityToolkit.WinUI.Controls;\n\nnamespace YourApp;\n\npublic sealed partial class YourPage : Page\n{\n public YourPage()\n {\n this.InitializeComponent();\n }\n}","source":"toolkit","nugetPackage":"CommunityToolkit.WinUI.Controls.HeaderedControls","xmlnsImports":["xmlns:controls=\u0022using:CommunityToolkit.WinUI.Controls\u0022"],"description":null,"controlDescription":"The HeaderedContentControl allows content to be displayed with a specified header.","relatedControls":[],"apiNamespace":null,"docs":[]},{"id":"headeredcontentcontrol-2","controlId":"headeredcontentcontrol","controlName":"HeaderedContentControl","headerText":"Image","xaml":"\u003Ccontrols:HeaderedContentControl Grid.Row=\u00221\u0022\n Grid.Column=\u00220\u0022\n Header=\u0022Image content\u0022\u003E\n \u003CImage Source=\u0022ms-appx:///Assets/BisonBadlandsChillin.jpg\u0022 /\u003E\n \u003C/controls:HeaderedContentControl\u003E","csharp":"using CommunityToolkit.WinUI.Controls;\n\nnamespace YourApp;\n\npublic sealed partial class YourPage : Page\n{\n public YourPage()\n {\n this.InitializeComponent();\n }\n}","source":"toolkit","nugetPackage":"CommunityToolkit.WinUI.Controls.HeaderedControls","xmlnsImports":["xmlns:controls=\u0022using:CommunityToolkit.WinUI.Controls\u0022"],"description":null,"controlDescription":"The HeaderedContentControl allows content to be displayed with a specified header.","relatedControls":[],"apiNamespace":null,"docs":[]},{"id":"headeredcontentcontrol-3","controlId":"headeredcontentcontrol","controlName":"HeaderedContentControl","headerText":"Basic usage","xaml":"\u003Ccontrols:HeaderedContentControl\n HorizontalContentAlignment=\u0022Stretch\u0022\n VerticalContentAlignment=\u0022Stretch\u0022\n Header=\u0022Rectangle content\u0022\u003E\n \u003CRectangle\n Fill=\u0022{ThemeResource AccentFillColorDefaultBrush}\u0022 /\u003E\n \u003C/controls:HeaderedContentControl\u003E","csharp":"using CommunityToolkit.WinUI.Controls;\n\nnamespace YourApp;\n\npublic sealed partial class YourPage : Page\n{\n public YourPage()\n {\n this.InitializeComponent();\n }\n}","source":"toolkit","nugetPackage":"CommunityToolkit.WinUI.Controls.HeaderedControls","xmlnsImports":["xmlns:controls=\u0022using:CommunityToolkit.WinUI.Controls\u0022"],"description":"The Header property can be any object and you can use the HeaderTemplate to specify a custom look to the header.","controlDescription":"The HeaderedContentControl allows content to be displayed with a specified header.","relatedControls":[],"apiNamespace":null,"docs":[]},{"id":"headeredcontentcontrol-4","controlId":"headeredcontentcontrol","controlName":"HeaderedContentControl","headerText":"Text","xaml":"\u003Ccontrols:HeaderedContentControl\n Header=\u0022TextBlock content header\u0022\u003E\n \u003CTextBlock FontSize=\u002212\u0022\n Foreground=\u0022{ThemeResource TextFillColorSecondaryBrush}\u0022\n Text=\u0022Some more text about this content\u0022\n TextWrapping=\u0022Wrap\u0022 /\u003E\n \u003C/controls:HeaderedContentControl\u003E","csharp":"using CommunityToolkit.WinUI.Controls;\n\nnamespace YourApp;\n\npublic sealed partial class YourPage : Page\n{\n public YourPage()\n {\n this.InitializeComponent();\n }\n}","source":"toolkit","nugetPackage":"CommunityToolkit.WinUI.Controls.HeaderedControls","xmlnsImports":["xmlns:controls=\u0022using:CommunityToolkit.WinUI.Controls\u0022"],"description":null,"controlDescription":"The HeaderedContentControl allows content to be displayed with a specified header.","relatedControls":[],"apiNamespace":null,"docs":[]},{"id":"headereditemscontrol-1","controlId":"headereditemscontrol","controlName":"HeaderedItemsControl","headerText":"Basic usage","xaml":"\u003CGrid\u003E\n \u003CGrid.ColumnDefinitions\u003E\n \u003CColumnDefinition /\u003E\n \u003CColumnDefinition /\u003E\n \u003C/Grid.ColumnDefinitions\u003E\n \u003Ccontrols:HeaderedItemsControl Footer=\u0022Footer 1\u0022\n Header=\u0022Header 1\u0022\n ItemsSource=\u0022{x:Bind Items, Mode=OneWay}\u0022 /\u003E\n \u003Ccontrols:HeaderedItemsControl Grid.Column=\u00221\u0022\n Footer=\u0022Footer 2\u0022\n Header=\u0022Header 2\u0022\n ItemsSource=\u0022{x:Bind Items, Mode=OneWay}\u0022\u003E\n \u003Ccontrols:HeaderedItemsControl.HeaderTemplate\u003E\n \u003CDataTemplate\u003E\n \u003CTextBlock FontWeight=\u0022SemiBold\u0022\n Text=\u0022{Binding}\u0022 /\u003E\n \u003C/DataTemplate\u003E\n \u003C/controls:HeaderedItemsControl.HeaderTemplate\u003E\n \u003Ccontrols:HeaderedItemsControl.FooterTemplate\u003E\n \u003CDataTemplate\u003E\u003C/DataTemplate\u003E\u003C/controls:HeaderedItemsControl.FooterTemplate\u003E\u003C/controls:HeaderedItemsControl\u003E\u003C/Grid\u003E\n\u003C!-- ...truncated --\u003E","csharp":"using CommunityToolkit.WinUI.Controls;\n\nnamespace YourApp;\n\npublic sealed partial class YourPage : Page\n{\n public YourPage()\n {\n this.InitializeComponent();\n Items = \u0022The quick brown fox jumped over the lazy river\u0022.Split(\u0027 \u0027);\n }\n public IEnumerable\u003Cstring\u003E Items { get; }\n}","source":"toolkit","nugetPackage":"CommunityToolkit.WinUI.Controls.HeaderedControls","xmlnsImports":["xmlns:controls=\u0022using:CommunityToolkit.WinUI.Controls\u0022"],"description":"The Header property can be any object and you can use the HeaderTemplate to specify a custom look to the header. Similar objects can be set for the Footer and FooterTemplate.","controlDescription":"The HeaderedItemsControl allows items to be displayed with a specified header.","relatedControls":[],"apiNamespace":null,"docs":[]},{"id":"headeredtreeview-1","controlId":"headeredtreeview","controlName":"HeaderedTreeView","headerText":"Basic usage","xaml":"\u003CGrid\u003E\n \u003Ccontrols:HeaderedTreeView Footer=\u0022Footer\u0022\n Header=\u0022Header\u0022\n ItemsSource=\u0022{x:Bind Items, Mode=OneWay}\u0022\u003E\n \u003Ccontrols:HeaderedTreeView.HeaderTemplate\u003E\n \u003CDataTemplate\u003E\n \u003CTextBlock FontWeight=\u0022SemiBold\u0022\n Text=\u0022{Binding}\u0022 /\u003E\n \u003C/DataTemplate\u003E\n \u003C/controls:HeaderedTreeView.HeaderTemplate\u003E\n \u003Ccontrols:HeaderedTreeView.FooterTemplate\u003E\n \u003CDataTemplate\u003E\n \u003CTextBlock FontWeight=\u0022SemiBold\u0022\n Text=\u0022{Binding}\u0022 /\u003E\n \u003C/DataTemplate\u003E\n \u003C/controls:HeaderedTreeView.FooterTemplate\u003E\n \u003Ccontrols:HeaderedTreeView.ItemTemplate\u003E\n \u003CDataTemplate x:DataType=\u0022local:ExplorerItem\u0022\u003E\u003C/DataTemplate\u003E\u003C/controls:HeaderedTreeView.ItemTemplate\u003E\u003C/controls:HeaderedTreeView\u003E\u003C/Grid\u003E\n\u003C!-- ...truncated --\u003E","csharp":"using CommunityToolkit.WinUI.Controls;\n\nnamespace YourApp;\n\npublic sealed partial class YourPage : Page\n{\n public YourPage()\n {\n this.InitializeComponent();\n Items = GetData();\n }\n public ObservableCollection\u003CExplorerItem\u003E Items { get; }\n\n private ObservableCollection\u003CExplorerItem\u003E GetData()\n {\n var list = new ObservableCollection\u003CExplorerItem\u003E();\n ExplorerItem folder1 = new ExplorerItem()\n {\n Name = \u0022Work Documents\u0022,\n Children =\n {\n new ExplorerItem()\n {\n Name = \u0022Functional Specifications\u0022,\n Children =\n {\n new ExplorerItem()\n {\n Name = \u0022TreeView spec\u0022,\n }\n }\n },\n new ExplorerItem()\n {\n Name = \u0022Feature Schedule\u0022,\n },\n new ExplorerItem()\n {\n Name = \u0022Overall Project Plan\u0022,\n },\n new ExplorerItem()\n {\n Name = \u0022Feature Resources Allocation\u0022,\n }\n }\n };\n ExplorerItem folder2 = new ExplorerItem()\n {\n Name = \u0022Personal Folder\u0022,\n Children =\n {\n new ExplorerItem()\n {\n Name = \u0022Home Remodel Folder\u0022,\n Children =\n {\n new ExplorerItem()\n {\n Name = \u0022Contractor Contact Info\u0022,\n },\n new ExplorerItem()\n {\n Name = \u0022Paint Color Scheme\u0022,\n },\n new ExplorerItem()\n {\n Name = \u0022Flooring Woodgrain type\u0022,\n },\n new ExplorerItem()\n {\n// ...truncated","source":"toolkit","nugetPackage":"CommunityToolkit.WinUI.Controls.HeaderedControls","xmlnsImports":["xmlns:controls=\u0022using:CommunityToolkit.WinUI.Controls\u0022"],"description":"The Header property can be any object and you can use the HeaderTemplate to specify a custom look to the header. Similar objects can be set for the Footer and FooterTemplate.","controlDescription":"The HeaderedTreeView allows a treeview to be displayed with a specified header.","relatedControls":[],"apiNamespace":null,"docs":[]},{"id":"imagecropper-1","controlId":"imagecropper","controlName":"ImageCropper","headerText":"Overlay","xaml":"\u003CGrid\u003E\n \u003Ccontrols:ImageCropper\n AspectRatio=\u0022{x:Bind local:ImageCropperSample.ConvertStringToAspectRatio(AspectRatioSetting), Mode=OneWay}\u0022\n CropShape=\u0022{x:Bind local:ImageCropperSample.ConvertStringToCropShape(CropShapeSetting), Mode=OneWay}\u0022\n ThumbPlacement=\u0022{x:Bind local:ImageCropperSample.ConvertStringToThumbPlacement(ThumbPlacementSetting), Mode=OneWay}\u0022\u003E\n \u003Ccontrols:ImageCropper.Overlay\u003E\n \u003Cmedia:RadialGradientBrush\u003E\n \u003CGradientStop Offset=\u00220.75\u0022 Color=\u0022Transparent\u0022 /\u003E\n \u003CGradientStop Offset=\u00221\u0022 Color=\u0022DimGray\u0022 /\u003E\n \u003C/media:RadialGradientBrush\u003E\n \u003C/controls:ImageCropper.Overlay\u003E\n \u003C/controls:ImageCropper\u003E\n \u003C/Grid\u003E","csharp":"using Windows.Storage;\n\nnamespace YourApp;\n\npublic sealed partial class YourPage : Page\n{\n public YourPage()\n {\n this.InitializeComponent();\n\n _ = Load();\n }\n\n private async Task Load()\n {\n var file = await StorageFile.GetFileFromApplicationUriAsync(new Uri(\u0022ms-appx:///Assets/Owl.jpg\u0022));\n await ImageCropper.LoadImageFromFile(file);\n }\n}","source":"toolkit","nugetPackage":"CommunityToolkit.WinUI.Controls.ImageCropper","xmlnsImports":["xmlns:controls=\u0022using:CommunityToolkit.WinUI.Controls\u0022"],"description":"The crop area can be overlaid with a brush. Here we use a RadialGradientBrush, but you can use any brush; backdrop Media brushes, Geometry brushes, bitmap and image brushes, and so on.","controlDescription":"Control to crop rectangular and circular images.","relatedControls":[],"apiNamespace":null,"docs":[]},{"id":"imagecropper-2","controlId":"imagecropper","controlName":"ImageCropper","headerText":"Basic usage","xaml":"\u003Ccontrols:ImageCropper\n AspectRatio=\u0022{x:Bind local:ImageCropperSample.ConvertStringToAspectRatio(AspectRatioSetting), Mode=OneWay}\u0022\n CropShape=\u0022{x:Bind local:ImageCropperSample.ConvertStringToCropShape(CropShapeSetting), Mode=OneWay}\u0022\n ThumbPlacement=\u0022{x:Bind local:ImageCropperSample.ConvertStringToThumbPlacement(ThumbPlacementSetting), Mode=OneWay}\u0022 /\u003E","csharp":"using CommunityToolkit.WinUI.Controls;\nusing Windows.Storage;\nusing Windows.Storage.Pickers;\n\nnamespace YourApp;\n\npublic sealed partial class YourPage : Page\n{\n public YourPage()\n {\n this.InitializeComponent();\n _ = Load();\n }\n\n private async Task Load()\n {\n var file = await StorageFile.GetFileFromApplicationUriAsync(new Uri(\u0022ms-appx:///Assets/Owl.jpg\u0022));\n await imageCropper.LoadImageFromFile(file);\n }\n\n private async Task PickImage()\n {\n var filePicker = new FileOpenPicker\n {\n ViewMode = PickerViewMode.Thumbnail,\n SuggestedStartLocation = PickerLocationId.PicturesLibrary,\n FileTypeFilter =\n {\n \u0022.png\u0022, \u0022.jpg\u0022, \u0022.jpeg\u0022\n }\n };\n var file = await filePicker.PickSingleFileAsync();\n if (file != null \u0026\u0026 imageCropper != null)\n {\n await imageCropper.LoadImageFromFile(file);\n }\n }\n\n private async Task SaveCroppedImage()\n {\n var savePicker = new FileSavePicker\n {\n SuggestedStartLocation = PickerLocationId.PicturesLibrary,\n SuggestedFileName = \u0022Cropped_Image\u0022,\n FileTypeChoices =\n {\n { \u0022PNG Picture\u0022, new List\u003Cstring\u003E { \u0022.png\u0022 } },\n { \u0022JPEG Picture\u0022, new List\u003Cstring\u003E { \u0022.jpg\u0022 } }\n }\n };\n var imageFile = await savePicker.PickSaveFileAsync();\n if (imageFile != null)\n {\n BitmapFileFormat bitmapFileFormat;\n switch (imageFile.FileType.ToLower())\n {\n case \u0022.png\u0022:\n bitmapFileFormat = BitmapFileFormat.Png;\n break;\n case \u0022.jpg\u0022:\n bitmapFileFormat = BitmapFileFormat.Jpeg;\n break;\n default:\n bitmapFileFormat = BitmapFileFormat.Png;\n break;\n }\n\n using (var fileStream = await imageFile.OpenAsync(FileAccessMode.ReadWrite, StorageOpenOptions.None))\n {\n await imageCropper.SaveAsync(fileStream, bitmapFileFormat);\n }\n }\n }\n\n private async void PickButton_Click(object sender, RoutedEventArgs e)\n {\n await PickImage();\n }\n\n private async void SaveButton_Click(object sender, RoutedEventArgs e)\n {\n await SaveCroppedImage();\n }\n// ...truncated","source":"toolkit","nugetPackage":"CommunityToolkit.WinUI.Controls.ImageCropper","xmlnsImports":["xmlns:controls=\u0022using:CommunityToolkit.WinUI.Controls\u0022"],"description":"The ImageCropper Control allows user to freely crop an image.","controlDescription":"Control to crop rectangular and circular images.","relatedControls":[],"apiNamespace":null,"docs":[]},{"id":"metadatacontrol-1","controlId":"metadatacontrol","controlName":"MetadataControl","headerText":"Basic usage","xaml":"\u003CGrid\u003E\n \u003CGrid.RowDefinitions\u003E\n \u003CRowDefinition Height=\u0022*\u0022 /\u003E\n \u003CRowDefinition Height=\u0022Auto\u0022 /\u003E\n \u003CRowDefinition Height=\u0022Auto\u0022 /\u003E\n \u003C/Grid.RowDefinitions\u003E\n \u003Ccontrols:MetadataControl\n AccessibleSeparator=\u0022{x:Bind AccessibleSeparator, Mode=OneWay}\u0022\n Separator=\u0022{x:Bind Separator, Mode=OneWay}\u0022 /\u003E\n \u003CTextBlock\n Grid.Row=\u00221\u0022\n FontWeight=\u0022SemiBold\u0022 /\u003E\n \u003CStackPanel Grid.Row=\u00222\u0022\n Orientation=\u0022Horizontal\u0022\u003E\n \u003CButton Click=\u0022AddLabel_Click\u0022\n Content=\u0022Add label\u0022 /\u003E\n \u003CButton Click=\u0022AddCommand_Click\u0022\n Content=\u0022Add command\u0022 /\u003E\n \u003CButton Click=\u0022Clear_Click\u0022\n Content=\u0022Clear\u0022 /\u003E\n \u003C/StackPanel\u003E\n \u003C/Grid\u003E","csharp":"using CommunityToolkit.WinUI.Controls;\nusing System.Windows.Input;\n\nnamespace YourApp;\n\n/// \u003Csummary\u003E\n/// An example sample page of a custom control inheriting from Panel.\n/// \u003C/summary\u003E\npublic sealed partial class YourPage : Page\n{\n private static readonly string[] Labels = \u0022Lorem ipsum dolor sit amet consectetur adipiscing elit\u0022.Split(\u0027 \u0027);\n\n private readonly Random _random;\n private readonly ObservableCollection\u003CMetadataItem\u003E _units;\n private readonly DelegateCommand\u003Cobject\u003E _command;\n\n public YourPage()\n {\n this.InitializeComponent();\n _random = new Random();\n _units = new ObservableCollection\u003CMetadataItem\u003E\n {\n new MetadataItem { Label = GetRandomLabel() },\n new MetadataItem { Label = GetRandomLabel() }\n };\n _command = new DelegateCommand\u003Cobject\u003E(OnExecuteCommand);\n metadataControl.Items = _units;\n }\n\n private string GetRandomLabel() =\u003E Labels[_random!.Next(Labels.Length)];\n\n private void OnExecuteCommand(object obj)\n {\n OutputTxt.Text = $\u0022Command invoked - parameter: {obj}\u0022;\n }\n\n private void AddLabel_Click(object sender, RoutedEventArgs e)\n {\n if (_units != null)\n {\n _units.Add(new MetadataItem { Label = GetRandomLabel() });\n }\n }\n\n private void AddCommand_Click(object sender, RoutedEventArgs e)\n {\n if (_units != null)\n {\n var label = GetRandomLabel();\n _units.Add(new MetadataItem\n {\n Label = label,\n Command = _command!,\n CommandParameter = label,\n });\n }\n }\n\n private void Clear_Click(object sender, RoutedEventArgs e)\n {\n if (_units != null)\n {\n OutputTxt.Text = \u0022\u0022;\n _units.Clear();\n }\n }\n}","source":"toolkit","nugetPackage":"CommunityToolkit.WinUI.Controls.MetadataControl","xmlnsImports":["xmlns:controls=\u0022using:CommunityToolkit.WinUI.Controls\u0022"],"description":"The bullet separator can be customized using the Separator property. AccessibleSeparator is used as a replacement for Separator to generate the accessible string.","controlDescription":"The MetadataControl control displays a list of labels and hyper-links separated by a bullet.","relatedControls":[],"apiNamespace":null,"docs":[]},{"id":"dockpanel-1","controlId":"dockpanel","controlName":"DockPanel","headerText":"Basic usage","xaml":"\u003Ccontrols:DockPanel\n Grid.Column=\u00221\u0022\n HorizontalSpacing=\u00225\u0022\n LastChildFill=\u0022False\u0022\n VerticalSpacing=\u00225\u0022\u003E\n \u003CStackPanel\n controls:DockPanel.Dock=\u0022Top\u0022\n Background=\u0022Black\u0022 /\u003E\n \u003CStackPanel\n controls:DockPanel.Dock=\u0022Left\u0022\n Background=\u0022Red\u0022 /\u003E\n \u003CStackPanel\n controls:DockPanel.Dock=\u0022Bottom\u0022\n Background=\u0022Green\u0022 /\u003E\n \u003CStackPanel\n controls:DockPanel.Dock=\u0022Right\u0022\n Background=\u0022Blue\u0022 /\u003E\n \u003C/controls:DockPanel\u003E","csharp":"using CommunityToolkit.WinUI.Controls;\nusing Windows.UI;\n\nnamespace YourApp;\n\npublic sealed partial class YourPage : Page\n{\n private static readonly Random Rand = new Random();\n\n public YourPage()\n {\n this.InitializeComponent();\n }\n\n private void ClearAllDock(object sender, RoutedEventArgs e)\n {\n SampleDockPanel.Children.Clear();\n SampleDockPanel.LastChildFill = false;\n }\n\n private void AddStretchDock(object sender, RoutedEventArgs e)\n {\n AddChild(Dock.Bottom, false, false);\n SampleDockPanel.LastChildFill = true;\n }\n\n private void AddBottomDock(object sender, RoutedEventArgs e)\n {\n AddChild(Dock.Bottom, false, true);\n }\n\n private void AddTopDock(object sender, RoutedEventArgs e)\n {\n AddChild(Dock.Top, false, true);\n }\n\n private void AddLeftDock(object sender, RoutedEventArgs e)\n {\n AddChild(Dock.Left, true, false);\n }\n\n private void AddRightDock(object sender, RoutedEventArgs e)\n {\n AddChild(Dock.Right, true, false);\n }\n\n private void AddChild(Dock dock, bool setWidth = false, bool setHeight = false)\n {\n if (SampleDockPanel.LastChildFill)\n {\n return;\n }\n\n const int maxColor = 255;\n var childStackPanel = new StackPanel\n {\n Background = new SolidColorBrush(Color.FromArgb(\n (byte)Rand.Next(0, maxColor),\n (byte)Rand.Next(0, maxColor),\n (byte)Rand.Next(0, maxColor),\n 1))\n };\n\n if (setHeight)\n {\n childStackPanel.Height = Rand.Next(50, 80);\n }\n\n if (setWidth)\n {\n childStackPanel.Width = Rand.Next(50, 80);\n }\n\n childStackPanel.SetValue(DockPanel.DockProperty, dock);\n childStackPanel.PointerPressed \u002B= this.ChildStackPanel_PointerPressed;\n SampleDockPanel.Children.Add(childStackPanel);\n }\n\n private void ChildStackPanel_PointerPressed(object sender, PointerRoutedEventArgs e)\n {\n SampleDockPanel.Children.Remove((StackPanel)sender);\n }\n}","source":"toolkit","nugetPackage":"CommunityToolkit.WinUI.Controls.Primitives","xmlnsImports":["xmlns:controls=\u0022using:CommunityToolkit.WinUI.Controls\u0022"],"description":"The DockPanel position child controls based on the child Dock property, you have 4 options to Dock, left (Default), right, top, bottom.","controlDescription":"Defines an area where you can arrange child elements either horizontally or vertically, relative to each other.","relatedControls":[],"apiNamespace":null,"docs":[]},{"id":"staggeredlayout-1","controlId":"staggeredlayout","controlName":"StaggeredLayout","headerText":"Basic usage","xaml":"\u003CGrid\u003E\n \u003CScrollViewer\u003E\n \u003Cmuxc:ItemsRepeater\n ItemTemplate=\u0022{StaticResource StaggeredTemplate}\u0022\n ItemsSource=\u0022{x:Bind ColorsCollection, Mode=OneWay}\u0022\u003E\n \u003Cmuxc:ItemsRepeater.Layout\u003E\n \u003Ccontrols:StaggeredLayout ColumnSpacing=\u0022{x:Bind ColumnSpacing, Mode=OneWay}\u0022\n DesiredColumnWidth=\u0022{x:Bind DesiredColumnWidth, Mode=OneWay}\u0022\n ItemsStretch=\u0022{x:Bind local:StaggeredLayoutSample.ConvertStringToStaggeredLayoutItemsStretch(ItemsStretchProperty), Mode=OneWay}\u0022\n RowSpacing=\u0022{x:Bind RowSpacing, Mode=OneWay}\u0022 /\u003E\n \u003C/muxc:ItemsRepeater.Layout\u003E\n \u003C/muxc:ItemsRepeater\u003E\n \u003C/ScrollViewer\u003E\n \u003C/Grid\u003E","csharp":"using CommunityToolkit.WinUI.Controls;\nusing Windows.UI;\n\nnamespace YourApp;\n\npublic sealed partial class YourPage : Page\n{\n public ObservableCollection\u003CColorItem\u003E ColorsCollection = new();\n public Random random;\n\n public YourPage()\n {\n this.InitializeComponent();\n\n random = new Random(DateTime.Now.Millisecond);\n for (int i = 0; i \u003C random.Next(100, 200); i\u002B\u002B)\n {\n var item = new ColorItem { Index = i, Height = random.Next(50, 250), Color = Color.FromArgb(255, (byte)random.Next(0, 255), (byte)random.Next(0, 255), (byte)random.Next(0, 255)) };\n ColorsCollection.Add(item);\n }\n }\n\n}\n\npublic class ColorItem\n{\n public int Index { get; internal set; }\n\n public int Width { get; internal set; }\n\n public int Height { get; internal set; }\n\n public Color Color { get; internal set; }\n}","source":"toolkit","nugetPackage":"CommunityToolkit.WinUI.Controls.Primitives","xmlnsImports":["xmlns:controls=\u0022using:CommunityToolkit.WinUI.Controls\u0022"],"description":"The StaggeredLayout allows for layout of items in a column approach where an item will be added to whichever column has used the least amount of space.","controlDescription":"The StaggeredLayout displays items in a column approach where an item will be added to whichever column has used the least amount of space.","relatedControls":[],"apiNamespace":null,"docs":[]},{"id":"staggeredpanel-1","controlId":"staggeredpanel","controlName":"StaggeredPanel","headerText":"Basic usage","xaml":"\u003CGrid\u003E\n \u003CGridView Name=\u0022GridView\u0022\n ItemTemplate=\u0022{StaticResource StaggeredTemplate}\u0022\n ItemsSource=\u0022{x:Bind ColorsCollection, Mode=OneWay}\u0022\u003E\n \u003CGridView.ItemsPanel\u003E\n \u003CItemsPanelTemplate\u003E\n \u003Ccontrols:StaggeredPanel ColumnSpacing=\u0022{Binding ColumnSpacing, ElementName=ThisSamplePage, Mode=OneWay}\u0022\n DesiredColumnWidth=\u0022{Binding DesiredColumnWidth, ElementName=ThisSamplePage, Mode=OneWay}\u0022\n RowSpacing=\u0022{Binding RowSpacing, ElementName=ThisSamplePage, Mode=OneWay}\u0022 /\u003E\n \u003C/ItemsPanelTemplate\u003E\n \u003C/GridView.ItemsPanel\u003E\n \u003C/GridView\u003E\n \u003C/Grid\u003E","csharp":"using CommunityToolkit.WinUI.Controls;\nusing Windows.UI;\n\nnamespace YourApp;\n\npublic sealed partial class YourPage : Page\n{\n public ObservableCollection\u003CColorItem\u003E ColorsCollection = new();\n public Random random;\n\n public YourPage()\n {\n this.InitializeComponent();\n random = new Random(DateTime.Now.Millisecond);\n for (int i = 0; i \u003C random.Next(100, 200); i\u002B\u002B)\n {\n var item = new ColorItem { Index = i, Width = random.Next(50, 250), Height = random.Next(50, 250), Color = Color.FromArgb(255, (byte)random.Next(0, 255), (byte)random.Next(0, 255), (byte)random.Next(0, 255)) };\n ColorsCollection.Add(item);\n }\n }\n}","source":"toolkit","nugetPackage":"CommunityToolkit.WinUI.Controls.Primitives","xmlnsImports":["xmlns:controls=\u0022using:CommunityToolkit.WinUI.Controls\u0022"],"description":"The StaggeredPanel allows for layout of items in a column approach where an item will be added to whichever column has used the least amount of space.","controlDescription":"The StaggeredPanel displays items in a column approach where an item will be added to whichever column has used the least amount of space.","relatedControls":[],"apiNamespace":null,"docs":[]},{"id":"uniformgrid-1","controlId":"uniformgrid","controlName":"UniformGrid","headerText":"Basic usage","xaml":"\u003CGrid\u003E\n \u003Ccontrols:UniformGrid Columns=\u0022{x:Bind (x:Int32)Columns, Mode=OneWay}\u0022\n FirstColumn=\u0022{x:Bind (x:Int32)FirstColumn, Mode=OneWay}\u0022\n Orientation=\u0022{x:Bind local:UniformGridSample.ConvertStringToOrientation(OrientationProperty), Mode=OneWay}\u0022\n Rows=\u0022{x:Bind (x:Int32)Rows, Mode=OneWay}\u0022\u003E\n \u003CBorder Grid.Row=\u00221\u0022\n Grid.RowSpan=\u0022{x:Bind (x:Int32)Item1RowSpan, Mode=OneWay}\u0022\n Grid.Column=\u00221\u0022\n Grid.ColumnSpan=\u0022{x:Bind (x:Int32)Item1ColumnSpan, Mode=OneWay}\u0022\n Background=\u0022AliceBlue\u0022\u003E\n \u003CTextBlock Text=\u00221\u0022 /\u003E\n \u003C/Border\u003E\n \u003CBorder Background=\u0022Cornsilk\u0022\u003E\n \u003CTextBlock Text=\u00222\u0022 /\u003E\n \u003C/Border\u003E\n \u003CBorder Background=\u0022DarkSalmon\u0022\u003E\n \u003CTextBlock Text=\u00223\u0022 /\u003E\n \u003C/Border\u003E\n \u003CBorder Background=\u0022Gainsboro\u0022\u003E\u003C/Border\u003E\u003C/controls:UniformGrid\u003E\u003C/Grid\u003E\n\u003C!-- ...truncated --\u003E","csharp":"using CommunityToolkit.WinUI.Controls;\n\nnamespace YourApp;\n\npublic sealed partial class YourPage : Page\n{\n public YourPage()\n {\n this.InitializeComponent();\n }\n\n}","source":"toolkit","nugetPackage":"CommunityToolkit.WinUI.Controls.Primitives","xmlnsImports":["xmlns:controls=\u0022using:CommunityToolkit.WinUI.Controls\u0022"],"description":"Each cell in the grid, by default, will be the same size. If no value for Rows and Columns are provided, the UniformGrid will create a square layout based on the total number of visible items.","controlDescription":"Presents items in a evenly-spaced set of rows or columns to fill the total available display space. It reacts to changes in the layout as well as the content so it can adapt to different form factors automatically.","relatedControls":[],"apiNamespace":null,"docs":[]},{"id":"wraplayout-1","controlId":"wraplayout","controlName":"WrapLayout","headerText":"Basic usage","xaml":"\u003CGrid\u003E\n \u003CScrollViewer\u003E\n \u003Cmuxc:ItemsRepeater\n ItemTemplate=\u0022{StaticResource WrapTemplate}\u0022\n ItemsSource=\u0022{x:Bind ColorsCollection, Mode=OneWay}\u0022\u003E\n \u003Cmuxc:ItemsRepeater.Layout\u003E\n \u003Ccontrols:WrapLayout\n HorizontalSpacing=\u0022{x:Bind HorizontalSpacing, Mode=OneWay}\u0022\n VerticalSpacing=\u0022{x:Bind VerticalSpacing, Mode=OneWay}\u0022 /\u003E\n \u003C/muxc:ItemsRepeater.Layout\u003E\n \u003C/muxc:ItemsRepeater\u003E\n \u003C/ScrollViewer\u003E\n \u003C/Grid\u003E","csharp":"using CommunityToolkit.WinUI.Controls;\nusing Windows.UI;\n\nnamespace YourApp;\n\npublic sealed partial class YourPage : Page\n{\n public ObservableCollection\u003CColorItem\u003E ColorsCollection = new();\n public Random random;\n\n public YourPage()\n {\n this.InitializeComponent();\n\n random = new Random(DateTime.Now.Millisecond);\n for (int i = 0; i \u003C random.Next(1000, 5000); i\u002B\u002B)\n {\n var item = new ColorItem { Index = i, Width = random.Next(50, 250), Height = random.Next(50, 250), Color = Color.FromArgb(255, (byte)random.Next(0, 255), (byte)random.Next(0, 255), (byte)random.Next(0, 255)) };\n ColorsCollection.Add(item);\n }\n }\n}","source":"toolkit","nugetPackage":"CommunityToolkit.WinUI.Controls.Primitives","xmlnsImports":["xmlns:controls=\u0022using:CommunityToolkit.WinUI.Controls\u0022"],"description":"Subsequent ordering happens sequentially from top to bottom or from right to left, depending on the value of the Orientation property.","controlDescription":"The WrapLayout virtualizes child elements in sequential position from left to right, breaking content to the next line at the edge of the containing box.","relatedControls":[],"apiNamespace":null,"docs":[]},{"id":"wrappanel-1","controlId":"wrappanel","controlName":"WrapPanel","headerText":"Basic usage","xaml":"\u003Ccontrols:WrapPanel\n HorizontalSpacing=\u0022{Binding HorizontalSpacing, ElementName=ThisSamplePage, Mode=OneWay}\u0022\n VerticalSpacing=\u0022{Binding VerticalSpacing, ElementName=ThisSamplePage, Mode=OneWay}\u0022 /\u003E","csharp":"using CommunityToolkit.WinUI;\n\n// TODO: Discuss with Uno folks about their own internal WrapPanel implementation.\nusing WrapPanel = CommunityToolkit.WinUI.Controls.WrapPanel;\n\nnamespace YourApp;\n\npublic sealed partial class YourPage : Page\n{\n private static readonly Random Rand = new Random();\n private ObservableCollection\u003CPhotoDataItemWithDimension\u003E WrapPanelCollection = new();\n\n public YourPage()\n {\n this.InitializeComponent();\n }\n\n private void ItemControl_ItemClick(object sender, ItemClickEventArgs e)\n {\n var item = e.ClickedItem as PhotoDataItemWithDimension;\n if (item == null)\n {\n return;\n }\n\n WrapPanelCollection.Remove(item);\n }\n\n private void AddButton_Click(object sender, RoutedEventArgs e)\n {\n WrapPanelCollection.Add(new PhotoDataItemWithDimension\n {\n Category = \u0022Remove\u0022,\n Thumbnail = \u0022ms-appx:///Assets/BigFourSummerHeat.jpg\u0022,\n Width = Rand.Next(60, 180),\n Height = Rand.Next(40, 140)\n });\n }\n\n private void AddFixedBtn_Click(object sender, RoutedEventArgs e)\n {\n WrapPanelCollection.Add(new PhotoDataItemWithDimension\n {\n Category = \u0022Remove\u0022,\n Thumbnail = \u0022ms-appx:///Assets/BigFourSummerHeat.jpg\u0022,\n Width = 150,\n Height = 100\n });\n }\n\n private void SwitchBtn_Click(object sender, RoutedEventArgs e)\n {\n if (WrapPanelContainer.FindDescendant\u003CWrapPanel\u003E() is WrapPanel sampleWrapPanel)\n {\n if (sampleWrapPanel.Orientation == Orientation.Horizontal)\n {\n sampleWrapPanel.Orientation = Orientation.Vertical;\n ScrollViewer.SetVerticalScrollMode(WrapPanelContainer, ScrollMode.Disabled);\n ScrollViewer.SetVerticalScrollBarVisibility(WrapPanelContainer, ScrollBarVisibility.Disabled);\n ScrollViewer.SetHorizontalScrollMode(WrapPanelContainer, ScrollMode.Auto);\n ScrollViewer.SetHorizontalScrollBarVisibility(WrapPanelContainer, ScrollBarVisibility.Auto);\n }\n else\n {\n sampleWrapPanel.Orientation = Orientation.Horizontal;\n ScrollViewer.SetVerticalScrollMode(WrapPanelContainer, ScrollMode.Auto);\n ScrollViewer.SetVerticalScrollBarVisibility(WrapPanelContainer, ScrollBarVisibility.Auto);\n// ...truncated","source":"toolkit","nugetPackage":"CommunityToolkit.WinUI.Controls.Primitives","xmlnsImports":["xmlns:controls=\u0022using:CommunityToolkit.WinUI.Controls\u0022"],"description":"Subsequent ordering happens sequentially from top to bottom or from right to left, depending on the value of the Orientation property.","controlDescription":"The WrapPanel Control positions child elements in sequential position from left to right, breaking content to the next line at the edge of the containing box.","relatedControls":[],"apiNamespace":null,"docs":[]},{"id":"radialgauge-1","controlId":"radialgauge","controlName":"RadialGauge","headerText":"Basic usage","xaml":"\u003CStackPanel\n Orientation=\u0022Horizontal\u0022\u003E\u003C/StackPanel\u003E\n\u003C!-- ...truncated --\u003E","csharp":"using CommunityToolkit.WinUI.Controls;\n\nnamespace YourApp;\n\n/// \u003Csummary\u003E\n/// An example sample page of a custom control inheriting from Panel.\n/// \u003C/summary\u003E\npublic sealed partial class YourPage : Page\n{\n public YourPage()\n {\n this.InitializeComponent();\n }\n}","source":"toolkit","nugetPackage":"CommunityToolkit.WinUI.Controls.RadialGauge","xmlnsImports":["xmlns:controls=\u0022using:CommunityToolkit.WinUI.Controls\u0022"],"description":"This control will make data visualizations and dashboards more engaging with rich style and interactivity.","controlDescription":"The Radial Gauge Control displays a value in a certain range using a needle on a circular face.","relatedControls":[],"apiNamespace":null,"docs":[]},{"id":"rangeselector-1","controlId":"rangeselector","controlName":"RangeSelector","headerText":"Basic usage","xaml":"\u003CGrid\u003E\n \u003Ccontrols:RangeSelector\n Maximum=\u0022{x:Bind Maximum, Mode=OneWay}\u0022\n Minimum=\u0022{x:Bind Minimum, Mode=OneWay}\u0022\n Orientation=\u0022{x:Bind OrientationMode, Mode=OneWay}\u0022\n RangeEnd=\u0022100\u0022\n RangeStart=\u00220\u0022\n StepFrequency=\u0022{x:Bind StepFrequency, Mode=OneWay}\u0022 /\u003E\n \u003C/Grid\u003E","csharp":"using CommunityToolkit.WinUI.Controls;\n\nnamespace YourApp;\n\npublic sealed partial class YourPage : Page\n{\n public YourPage()\n {\n this.InitializeComponent();\n }\n}","source":"toolkit","nugetPackage":"CommunityToolkit.WinUI.Controls.RangeSelector","xmlnsImports":["xmlns:controls=\u0022using:CommunityToolkit.WinUI.Controls\u0022"],"description":"A RangeSelector is pretty similar to a regular Slider, and shares some of its properties such as Minimum, Maximum and StepFrequency.","controlDescription":"The RangeSelector Control is a Double Slider control that allows the user to select a sub-range of values from a larger range of possible values. The user can slide from the left or right of the range.","relatedControls":[],"apiNamespace":null,"docs":[]},{"id":"richsuggestbox-1","controlId":"richsuggestbox","controlName":"RichSuggestBox","headerText":"Multiple Prefixes","xaml":"\u003CStackPanel\u003E\n \u003Ccontrols:RichSuggestBox\n Header=\u0022RichSuggestBox that supports multiple prefixes (@ and #)\u0022\n ItemTemplateSelector=\u0022{StaticResource SuggestionTemplateSelector}\u0022\n Prefixes=\u0022@#\u0022\n SuggestionChosen=\u0022SuggestingBox_SuggestionChosen\u0022\n SuggestionRequested=\u0022SuggestingBox_SuggestionRequested\u0022 /\u003E\n \u003CListView\n ItemTemplate=\u0022{StaticResource TokenTemplate}\u0022 /\u003E\n \u003C/StackPanel\u003E","csharp":"using CommunityToolkit.WinUI.Controls;\n\nusing Microsoft.UI;\nusing Microsoft.UI.Text;\n\nnamespace YourApp;\n\npublic sealed partial class YourPage : Page\n{\n private readonly List\u003CSampleEmailDataType\u003E _emailSamples = new List\u003CSampleEmailDataType\u003E()\n {\n new SampleEmailDataType() { FirstName = \u0022Marcus\u0022, FamilyName = \u0022Perryman\u0022 },\n new SampleEmailDataType() { FirstName = \u0022Michael\u0022, FamilyName = \u0022Hawker\u0022 },\n new SampleEmailDataType() { FirstName = \u0022Matt\u0022, FamilyName = \u0022Lacey\u0022 },\n new SampleEmailDataType() { FirstName = \u0022Alexandre\u0022, FamilyName = \u0022Chohfi\u0022 },\n new SampleEmailDataType() { FirstName = \u0022Filip\u0022, FamilyName = \u0022Wallberg\u0022 },\n new SampleEmailDataType() { FirstName = \u0022Shane\u0022, FamilyName = \u0022Weaver\u0022 },\n new SampleEmailDataType() { FirstName = \u0022Vincent\u0022, FamilyName = \u0022Gromfeld\u0022 },\n new SampleEmailDataType() { FirstName = \u0022Sergio\u0022, FamilyName = \u0022Pedri\u0022 },\n new SampleEmailDataType() { FirstName = \u0022Alex\u0022, FamilyName = \u0022Wilber\u0022 },\n new SampleEmailDataType() { FirstName = \u0022Allan\u0022, FamilyName = \u0022Deyoung\u0022 },\n new SampleEmailDataType() { FirstName = \u0022Adele\u0022, FamilyName = \u0022Vance\u0022 },\n new SampleEmailDataType() { FirstName = \u0022Grady\u0022, FamilyName = \u0022Archie\u0022 },\n new SampleEmailDataType() { FirstName = \u0022Megan\u0022, FamilyName = \u0022Bowen\u0022 },\n new SampleEmailDataType() { FirstName = \u0022Ben\u0022, FamilyName = \u0022Walters\u0022 },\n new SampleEmailDataType() { FirstName = \u0022Debra\u0022, FamilyName = \u0022Berger\u0022 },\n new SampleEmailDataType() { FirstName = \u0022Emily\u0022, FamilyName = \u0022Braun\u0022 },\n new SampleEmailDataType() { FirstName = \u0022Christine\u0022, FamilyName = \u0022Cline\u0022 },\n new SampleEmailDataType() { FirstName = \u0022Enrico\u0022, FamilyName = \u0022Catteneo\u0022 },\n new SampleEmailDataType() { FirstName = \u0022Davit\u0022, FamilyName = \u0022Badalyan\u0022 },\n new SampleEmailDataType() { FirstName = \u0022Diego\u0022, FamilyName = \u0022Siciliani\u0022 },\n new SampleEmailDataType() { FirstName = \u0022Raul\u0022, FamilyName = \u0022Razo\u0022 },\n new SampleEmailDataType() { FirstName = \u0022Miriam\u0022, FamilyName = \u0022Graham\u0022 },\n new SampleEmailDataType() { FirstName = \u0022Lynne\u0022, FamilyName = \u0022Robbins\u0022 },\n new SampleEmailDataType() { FirstName = \u0022Lydia\u0022, FamilyName = \u0022Holloway\u0022 },\n new SampleEmailDataType() { FirstName = \u0022Nestor\u0022, FamilyName = \u0022Wilke\u0022 },\n// ...truncated","source":"toolkit","nugetPackage":"CommunityToolkit.WinUI.Controls.RichSuggestBox","xmlnsImports":["xmlns:controls=\u0022using:CommunityToolkit.WinUI.Controls\u0022"],"description":"The RichSuggestBox is a combination of AutoSuggestBox and RichEditBox that can provide suggestions based on customizable prefixes.","controlDescription":"A rich text input control that auto-suggests and stores token items in a document.","relatedControls":[],"apiNamespace":null,"docs":[]},{"id":"richsuggestbox-2","controlId":"richsuggestbox","controlName":"RichSuggestBox","headerText":"Plain Text","xaml":"\u003CStackPanel\u003E\n \u003Ccontrols:RichSuggestBox\n ClipboardCopyFormat=\u0022PlainText\u0022\n ClipboardPasteFormat=\u0022PlainText\u0022\n DisabledFormattingAccelerators=\u0022All\u0022\n FlyoutBase.AttachedFlyout=\u0022{StaticResource TokenSelectedFlyout}\u0022\n Header=\u0022Plain text RichSuggestBox with on token pointer over flyout\u0022\n ItemTemplate=\u0022{StaticResource EmailTemplate}\u0022\n Prefixes=\u0022@\u0022\n SuggestionChosen=\u0022SuggestingBox_SuggestionChosen\u0022\n SuggestionRequested=\u0022SuggestingBox_SuggestionRequested\u0022\n TokenPointerOver=\u0022SuggestingBox_TokenPointerOver\u0022 /\u003E\n \u003CListView\n ItemTemplate=\u0022{StaticResource TokenTemplate}\u0022 /\u003E\n \u003C/StackPanel\u003E","csharp":"using CommunityToolkit.WinUI.Controls;\n\nusing Microsoft.UI;\nusing Microsoft.UI.Dispatching;\nusing Microsoft.UI.Text;\n\nnamespace YourApp;\n\npublic sealed partial class RichSuggestBoxPlainTextSample : Page\n{\n private DispatcherQueue _dispatcherQueue;\n private readonly List\u003CSampleEmailDataType\u003E _emailSamples = new List\u003CSampleEmailDataType\u003E()\n {\n new SampleEmailDataType() { FirstName = \u0022Marcus\u0022, FamilyName = \u0022Perryman\u0022 },\n new SampleEmailDataType() { FirstName = \u0022Michael\u0022, FamilyName = \u0022Hawker\u0022 },\n new SampleEmailDataType() { FirstName = \u0022Matt\u0022, FamilyName = \u0022Lacey\u0022 },\n new SampleEmailDataType() { FirstName = \u0022Alexandre\u0022, FamilyName = \u0022Chohfi\u0022 },\n new SampleEmailDataType() { FirstName = \u0022Filip\u0022, FamilyName = \u0022Wallberg\u0022 },\n new SampleEmailDataType() { FirstName = \u0022Shane\u0022, FamilyName = \u0022Weaver\u0022 },\n new SampleEmailDataType() { FirstName = \u0022Vincent\u0022, FamilyName = \u0022Gromfeld\u0022 },\n new SampleEmailDataType() { FirstName = \u0022Sergio\u0022, FamilyName = \u0022Pedri\u0022 },\n new SampleEmailDataType() { FirstName = \u0022Alex\u0022, FamilyName = \u0022Wilber\u0022 },\n new SampleEmailDataType() { FirstName = \u0022Allan\u0022, FamilyName = \u0022Deyoung\u0022 },\n new SampleEmailDataType() { FirstName = \u0022Adele\u0022, FamilyName = \u0022Vance\u0022 },\n new SampleEmailDataType() { FirstName = \u0022Grady\u0022, FamilyName = \u0022Archie\u0022 },\n new SampleEmailDataType() { FirstName = \u0022Megan\u0022, FamilyName = \u0022Bowen\u0022 },\n new SampleEmailDataType() { FirstName = \u0022Ben\u0022, FamilyName = \u0022Walters\u0022 },\n new SampleEmailDataType() { FirstName = \u0022Debra\u0022, FamilyName = \u0022Berger\u0022 },\n new SampleEmailDataType() { FirstName = \u0022Emily\u0022, FamilyName = \u0022Braun\u0022 },\n new SampleEmailDataType() { FirstName = \u0022Christine\u0022, FamilyName = \u0022Cline\u0022 },\n new SampleEmailDataType() { FirstName = \u0022Enrico\u0022, FamilyName = \u0022Catteneo\u0022 },\n new SampleEmailDataType() { FirstName = \u0022Davit\u0022, FamilyName = \u0022Badalyan\u0022 },\n new SampleEmailDataType() { FirstName = \u0022Diego\u0022, FamilyName = \u0022Siciliani\u0022 },\n new SampleEmailDataType() { FirstName = \u0022Raul\u0022, FamilyName = \u0022Razo\u0022 },\n new SampleEmailDataType() { FirstName = \u0022Miriam\u0022, FamilyName = \u0022Graham\u0022 },\n new SampleEmailDataType() { FirstName = \u0022Lynne\u0022, FamilyName = \u0022Robbins\u0022 },\n new SampleEmailDataType() { FirstName = \u0022Lydia\u0022, FamilyName = \u0022Holloway\u0022 },\n// ...truncated","source":"toolkit","nugetPackage":"CommunityToolkit.WinUI.Controls.RichSuggestBox","xmlnsImports":["xmlns:controls=\u0022using:CommunityToolkit.WinUI.Controls\u0022"],"description":null,"controlDescription":"A rich text input control that auto-suggests and stores token items in a document.","relatedControls":[],"apiNamespace":null,"docs":[]},{"id":"segmented-1","controlId":"segmented","controlName":"Segmented","headerText":"Example 1","xaml":"\u003Ccontrols:Segmented HorizontalAlignment=\u0022{x:Bind local:SegmentedBasicSample.ConvertStringToHorizontalAlignment(Alignment), Mode=OneWay}\u0022\n Orientation=\u0022{x:Bind local:SegmentedBasicSample.ConvertStringToOrientation(OrientationMode), Mode=OneWay}\u0022\n SelectionMode=\u0022{x:Bind local:SegmentedBasicSample.ConvertStringToSelectionMode(SelectionMode), Mode=OneWay}\u0022\u003E\n \u003Ccontrols:SegmentedItem Content=\u0022Item 1\u0022\n Icon=\u0022{ui:FontIcon Glyph=\u0026#xEA3A;}\u0022 /\u003E\n \u003Ccontrols:SegmentedItem Content=\u0022Item 2\u0022\n Icon=\u0022{ui:FontIcon Glyph=\u0026#xEA3A;}\u0022 /\u003E\n \u003Ccontrols:SegmentedItem Content=\u0022Item 3 with a long label\u0022\n Icon=\u0022{ui:FontIcon Glyph=\u0026#xEA3A;}\u0022 /\u003E\n \u003Ccontrols:SegmentedItem Content=\u0022Item 4\u0022\n Icon=\u0022{ui:FontIcon Glyph=\u0026#xEA3A;}\u0022 /\u003E\n \u003C/controls:Segmented\u003E","csharp":null,"source":"toolkit","nugetPackage":"CommunityToolkit.WinUI.Controls.Segmented","xmlnsImports":["xmlns:controls=\u0022using:CommunityToolkit.WinUI.Controls\u0022","xmlns:ui=\u0022using:CommunityToolkit.WinUI\u0022"],"description":"The Segmented control is best used with 2-5 items and does not support overflow. The Icon and Content property can be set on the SegmentedItems.","controlDescription":"A common UI control to configure a view or setting.","relatedControls":[],"apiNamespace":null,"docs":[]},{"id":"segmented-2","controlId":"segmented","controlName":"Segmented","headerText":"Example 2","xaml":"\u003Ccontrols:Segmented HorizontalAlignment=\u0022{x:Bind local:SegmentedBasicSample.ConvertStringToHorizontalAlignment(Alignment), Mode=OneWay}\u0022\n Orientation=\u0022{x:Bind local:SegmentedBasicSample.ConvertStringToOrientation(OrientationMode), Mode=OneWay}\u0022\n SelectionMode=\u0022{x:Bind local:SegmentedBasicSample.ConvertStringToSelectionMode(SelectionMode), Mode=OneWay}\u0022\u003E\n \u003Ccontrols:SegmentedItem Icon=\u0022{ui:FontIcon Glyph=\u0026#xE8BF;}\u0022\n ToolTipService.ToolTip=\u0022Day view\u0022 /\u003E\n \u003Ccontrols:SegmentedItem Icon=\u0022{ui:FontIcon Glyph=\u0026#xE8C0;}\u0022\n ToolTipService.ToolTip=\u0022Week view\u0022 /\u003E\n \u003Ccontrols:SegmentedItem Icon=\u0022{ui:FontIcon Glyph=\u0026#xE787;}\u0022\n ToolTipService.ToolTip=\u0022Month view\u0022 /\u003E\n \u003C/controls:Segmented\u003E","csharp":null,"source":"toolkit","nugetPackage":"CommunityToolkit.WinUI.Controls.Segmented","xmlnsImports":["xmlns:controls=\u0022using:CommunityToolkit.WinUI.Controls\u0022","xmlns:ui=\u0022using:CommunityToolkit.WinUI\u0022"],"description":"The Segmented control is best used with 2-5 items and does not support overflow. The Icon and Content property can be set on the SegmentedItems.","controlDescription":"A common UI control to configure a view or setting.","relatedControls":[],"apiNamespace":null,"docs":[]},{"id":"segmented-3","controlId":"segmented","controlName":"Segmented","headerText":"Example 1","xaml":"\u003Ccontrols:Segmented Orientation=\u0022{x:Bind local:SegmentedStylesSample.ConvertStringToOrientation(OrientationMode), Mode=OneWay}\u0022\n SelectionMode=\u0022{x:Bind local:SegmentedStylesSample.ConvertStringToSelectionMode(SelectionMode), Mode=OneWay}\u0022\n Style=\u0022{StaticResource PivotSegmentedStyle}\u0022\u003E\n \u003Ccontrols:SegmentedItem\u003EItem 1\u003C/controls:SegmentedItem\u003E\n \u003Ccontrols:SegmentedItem\u003EItem 2\u003C/controls:SegmentedItem\u003E\n \u003Ccontrols:SegmentedItem\u003EItem with long label\u003C/controls:SegmentedItem\u003E\n \u003Ccontrols:SegmentedItem\u003EItem 4\u003C/controls:SegmentedItem\u003E\n \u003C/controls:Segmented\u003E","csharp":null,"source":"toolkit","nugetPackage":"CommunityToolkit.WinUI.Controls.Segmented","xmlnsImports":["xmlns:controls=\u0022using:CommunityToolkit.WinUI.Controls\u0022","xmlns:ui=\u0022using:CommunityToolkit.WinUI\u0022"],"description":"The Segmented control contains various additional styles, to match the look and feel of your application.","controlDescription":"A common UI control to configure a view or setting.","relatedControls":[],"apiNamespace":null,"docs":[]},{"id":"segmented-4","controlId":"segmented","controlName":"Segmented","headerText":"Example 2","xaml":"\u003Ccontrols:Segmented Orientation=\u0022{x:Bind local:SegmentedStylesSample.ConvertStringToOrientation(OrientationMode), Mode=OneWay}\u0022\n SelectionMode=\u0022{x:Bind local:SegmentedStylesSample.ConvertStringToSelectionMode(SelectionMode), Mode=OneWay}\u0022\n Style=\u0022{StaticResource ButtonSegmentedStyle}\u0022\u003E\n \u003Ccontrols:SegmentedItem Content=\u0022Day\u0022\n Icon=\u0022{ui:FontIcon Glyph=\u0026#xE8BF;}\u0022\n ToolTipService.ToolTip=\u0022Day view\u0022 /\u003E\n \u003Ccontrols:SegmentedItem Content=\u0022Week\u0022\n Icon=\u0022{ui:FontIcon Glyph=\u0026#xE8C0;}\u0022\n ToolTipService.ToolTip=\u0022Week view\u0022 /\u003E\n \u003Ccontrols:SegmentedItem Content=\u0022Month\u0022\n Icon=\u0022{ui:FontIcon Glyph=\u0026#xE787;}\u0022\n ToolTipService.ToolTip=\u0022Month view\u0022 /\u003E\n \u003C/controls:Segmented\u003E","csharp":null,"source":"toolkit","nugetPackage":"CommunityToolkit.WinUI.Controls.Segmented","xmlnsImports":["xmlns:controls=\u0022using:CommunityToolkit.WinUI.Controls\u0022","xmlns:ui=\u0022using:CommunityToolkit.WinUI\u0022"],"description":"The Segmented control contains various additional styles, to match the look and feel of your application.","controlDescription":"A common UI control to configure a view or setting.","relatedControls":[],"apiNamespace":null,"docs":[]},{"id":"segmented-5","controlId":"segmented","controlName":"Segmented","headerText":"Switch Presenter","xaml":"\u003Ccontrols:Segmented\u003E\n \u003Ccontrols:SegmentedItem Content=\u0022Square\u0022\n Icon=\u0022{ui:FontIcon Glyph=\u0026#xE739;}\u0022\n Tag=\u0022square\u0022 /\u003E\n \u003Ccontrols:SegmentedItem Content=\u0022Circle\u0022\n Icon=\u0022{ui:FontIcon Glyph=\u0026#xEA3A;}\u0022\n Tag=\u0022circle\u0022 /\u003E\n \u003Ccontrols:SegmentedItem Content=\u0022Rectangle\u0022\n Icon=\u0022{ui:FontIcon Glyph=\u0026#xE7FB;}\u0022\n Tag=\u0022rect\u0022 /\u003E\n \u003C/controls:Segmented\u003E","csharp":"using CommunityToolkit.WinUI.Controls;\n\nnamespace YourApp;\n\n/// \u003Csummary\u003E\n/// An example sample page of a Segmented control.\n/// \u003C/summary\u003E\n\npublic sealed partial class YourPage : Page\n{\n public YourPage()\n {\n this.InitializeComponent();\n }\n}","source":"toolkit","nugetPackage":"CommunityToolkit.WinUI.Controls.Segmented","xmlnsImports":["xmlns:controls=\u0022using:CommunityToolkit.WinUI.Controls\u0022","xmlns:ui=\u0022using:CommunityToolkit.WinUI\u0022"],"description":"The Segmented control can be combined with e.g. a SwitchPresenter to provide easy navigation and with limited XAML and no code-behind!","controlDescription":"A common UI control to configure a view or setting.","relatedControls":[],"apiNamespace":null,"docs":[]},{"id":"settingscard-1","controlId":"settingscard","controlName":"SettingsCard","headerText":"A clickable SettingsCard","xaml":"\u003Ccontrols:SettingsCard\n Click=\u0022OnCardClicked\u0022\n Description=\u0022A SettingsCard can be made clickable and you can leverage the Command property or Click event.\u0022\n Header=\u0022A clickable SettingsCard\u0022\n HeaderIcon=\u0022{ui:FontIcon Glyph=\u0026#xE799;}\u0022\n IsClickEnabled=\u0022True\u0022\u003E\n \u003CTextBlock Foreground=\u0022{ThemeResource TextFillColorSecondaryBrush}\u0022\n Text=\u0022This is content\u0022 /\u003E\n \u003C/controls:SettingsCard\u003E","csharp":null,"source":"toolkit","nugetPackage":"CommunityToolkit.WinUI.Controls.SettingsControls","xmlnsImports":["xmlns:controls=\u0022using:CommunityToolkit.WinUI.Controls\u0022","xmlns:ui=\u0022using:CommunityToolkit.WinUI\u0022"],"description":"SettingsCard can also be turned into a button, by setting the IsClickEnabled property. This can be useful whenever you want your settings component to navigate to a detail page or open an external link.","controlDescription":"A card control that can be used to create Windows 11 style settings experiences.","relatedControls":[],"apiNamespace":null,"docs":[]},{"id":"settingscard-2","controlId":"settingscard","controlName":"SettingsCard","headerText":"Customizing the ActionIcon","xaml":"\u003Ccontrols:SettingsCard ActionIcon=\u0022{ui:FontIcon Glyph=\u0026#xE8A7;}\u0022\n ActionIconToolTip=\u0022Open in new window\u0022\n Click=\u0022OnCardClicked\u0022\n Description=\u0022You can customize the ActionIcon and ActionIconToolTip.\u0022\n Header=\u0022Customizing the ActionIcon\u0022\n HeaderIcon=\u0022{ui:FontIcon Glyph=\u0026#xE774;}\u0022\n IsClickEnabled=\u0022True\u0022 /\u003E","csharp":null,"source":"toolkit","nugetPackage":"CommunityToolkit.WinUI.Controls.SettingsControls","xmlnsImports":["xmlns:controls=\u0022using:CommunityToolkit.WinUI.Controls\u0022","xmlns:ui=\u0022using:CommunityToolkit.WinUI\u0022"],"description":"SettingsCard can also be turned into a button, by setting the IsClickEnabled property. This can be useful whenever you want your settings component to navigate to a detail page or open an external link.","controlDescription":"A card control that can be used to create Windows 11 style settings experiences.","relatedControls":[],"apiNamespace":null,"docs":[]},{"id":"settingscard-3","controlId":"settingscard","controlName":"SettingsCard","headerText":"Hiding the ActionIcon","xaml":"\u003Ccontrols:SettingsCard Click=\u0022OnCardClicked\u0022\n Header=\u0022Hiding the ActionIcon\u0022\n HeaderIcon=\u0022{ui:FontIcon Glyph=\u0026#xE72E;}\u0022\n IsActionIconVisible=\u0022False\u0022\n IsClickEnabled=\u0022True\u0022 /\u003E","csharp":null,"source":"toolkit","nugetPackage":"CommunityToolkit.WinUI.Controls.SettingsControls","xmlnsImports":["xmlns:controls=\u0022using:CommunityToolkit.WinUI.Controls\u0022","xmlns:ui=\u0022using:CommunityToolkit.WinUI\u0022"],"description":"SettingsCard can also be turned into a button, by setting the IsClickEnabled property. This can be useful whenever you want your settings component to navigate to a detail page or open an external link.","controlDescription":"A card control that can be used to create Windows 11 style settings experiences.","relatedControls":[],"apiNamespace":null,"docs":[]},{"id":"settingscard-4","controlId":"settingscard","controlName":"SettingsCard","headerText":"This is a default card, with the Header, HeaderIcon, Description and Content set.","xaml":"\u003Ccontrols:SettingsCard\n Description=\u0022This is a default card, with the Header, HeaderIcon, Description and Content set.\u0022\n Header=\u0022This is the Header\u0022\n HeaderIcon=\u0022{ui:FontIcon Glyph=\u0026#xE799;}\u0022\u003E\n \u003CComboBox\u003E\n \u003CComboBoxItem\u003EOption 1\u003C/ComboBoxItem\u003E\n \u003CComboBoxItem\u003EOption 2\u003C/ComboBoxItem\u003E\n \u003CComboBoxItem\u003EOption 3\u003C/ComboBoxItem\u003E\n \u003C/ComboBox\u003E\n \u003C/controls:SettingsCard\u003E","csharp":null,"source":"toolkit","nugetPackage":"CommunityToolkit.WinUI.Controls.SettingsControls","xmlnsImports":["xmlns:controls=\u0022using:CommunityToolkit.WinUI.Controls\u0022","xmlns:ui=\u0022using:CommunityToolkit.WinUI\u0022"],"description":"SettingsCard is a control that can be used to display settings in your experience. It uses the default styling found in Windows 11 and is easy to use, meets all accessibility standards and will make your settings page look great! You can...","controlDescription":"A card control that can be used to create Windows 11 style settings experiences.","relatedControls":[],"apiNamespace":null,"docs":[]},{"id":"settingscard-5","controlId":"settingscard","controlName":"SettingsCard","headerText":"Icon options","xaml":"\u003Ccontrols:SettingsCard Description=\u0022You can use a FontIcon, SymbolIcon or BitmapIcon to set the cards HeaderIcon.\u0022\n Header=\u0022Icon options\u0022\n HeaderIcon=\u0022{ui:BitmapIcon Source=ms-appx:///Assets/AppTitleBar.scale-200.png}\u0022\u003E\n \u003CToggleSwitch /\u003E\n \u003C/controls:SettingsCard\u003E","csharp":null,"source":"toolkit","nugetPackage":"CommunityToolkit.WinUI.Controls.SettingsControls","xmlnsImports":["xmlns:controls=\u0022using:CommunityToolkit.WinUI.Controls\u0022","xmlns:ui=\u0022using:CommunityToolkit.WinUI\u0022"],"description":"SettingsCard is a control that can be used to display settings in your experience. It uses the default styling found in Windows 11 and is easy to use, meets all accessibility standards and will make your settings page look great! You can...","controlDescription":"A card control that can be used to create Windows 11 style settings experiences.","relatedControls":[],"apiNamespace":null,"docs":[]},{"id":"settingscard-6","controlId":"settingscard","controlName":"SettingsCard","headerText":"A card with custom objects as its Description","xaml":"\u003Ccontrols:SettingsCard Header=\u0022A card with custom objects as its Description\u0022\u003E\n \u003Ccontrols:SettingsCard.Description\u003E\n \u003CHyperlinkButton Content=\u0022Learn more about Phone Link\u0022 /\u003E\n \u003C/controls:SettingsCard.Description\u003E\n \u003CButton Content=\u0022Open Phone Link\u0022\n Style=\u0022{StaticResource AccentButtonStyle}\u0022 /\u003E\n \u003C/controls:SettingsCard\u003E","csharp":null,"source":"toolkit","nugetPackage":"CommunityToolkit.WinUI.Controls.SettingsControls","xmlnsImports":["xmlns:controls=\u0022using:CommunityToolkit.WinUI.Controls\u0022","xmlns:ui=\u0022using:CommunityToolkit.WinUI\u0022"],"description":"SettingsCard is a control that can be used to display settings in your experience. It uses the default styling found in Windows 11 and is easy to use, meets all accessibility standards and will make your settings page look great! You can...","controlDescription":"A card control that can be used to create Windows 11 style settings experiences.","relatedControls":[],"apiNamespace":null,"docs":[]},{"id":"settingscard-7","controlId":"settingscard","controlName":"SettingsCard","headerText":"Adaptive layouts","xaml":"\u003Ccontrols:SettingsCard Description=\u0022When resizing a SettingsCard, the Content will wrap vertically. You can override this breakpoint by setting the SettingsCardWrapThreshold resource. For edge cases, you can also hide the icon by setting SettingsCardWrapNoIconThreshold.\u0022\n Header=\u0022Adaptive layouts\u0022\n HeaderIcon=\u0022{ui:FontIcon Glyph=\u0026#xE745;}\u0022\u003E\n \u003Ccontrols:SettingsCard.Resources\u003E\n \u003Cx:Double x:Key=\u0022SettingsCardWrapThreshold\u0022\u003E800\u003C/x:Double\u003E\n \u003Cx:Double x:Key=\u0022SettingsCardWrapNoIconThreshold\u0022\u003E600\u003C/x:Double\u003E\n \u003C/controls:SettingsCard.Resources\u003E\n \u003CButton Content=\u0022This control will wrap vertically!\u0022\n Style=\u0022{StaticResource AccentButtonStyle}\u0022 /\u003E\n \u003C/controls:SettingsCard\u003E","csharp":null,"source":"toolkit","nugetPackage":"CommunityToolkit.WinUI.Controls.SettingsControls","xmlnsImports":["xmlns:controls=\u0022using:CommunityToolkit.WinUI.Controls\u0022","xmlns:ui=\u0022using:CommunityToolkit.WinUI\u0022"],"description":"SettingsCard is a control that can be used to display settings in your experience. It uses the default styling found in Windows 11 and is easy to use, meets all accessibility standards and will make your settings page look great! You can...","controlDescription":"A card control that can be used to create Windows 11 style settings experiences.","relatedControls":[],"apiNamespace":null,"docs":[]},{"id":"settingscard-8","controlId":"settingscard","controlName":"SettingsCard","headerText":"Example 5","xaml":"\u003Ccontrols:SettingsCard Header=\u0022This is a card with a Header only\u0022 /\u003E","csharp":null,"source":"toolkit","nugetPackage":"CommunityToolkit.WinUI.Controls.SettingsControls","xmlnsImports":["xmlns:controls=\u0022using:CommunityToolkit.WinUI.Controls\u0022","xmlns:ui=\u0022using:CommunityToolkit.WinUI\u0022"],"description":"SettingsCard is a control that can be used to display settings in your experience. It uses the default styling found in Windows 11 and is easy to use, meets all accessibility standards and will make your settings page look great! You can...","controlDescription":"A card control that can be used to create Windows 11 style settings experiences.","relatedControls":[],"apiNamespace":null,"docs":[]},{"id":"settingsexpander-1","controlId":"settingsexpander","controlName":"SettingsExpander","headerText":"Drag Handle","xaml":"\u003Ccontrols:SettingsExpander Grid.Column=\u00221\u0022\n Description=\u0022{x:Bind Info}\u0022\n Header=\u0022{x:Bind Name}\u0022\n IsExpanded=\u0022{x:Bind IsExpanded, Mode=TwoWay}\u0022\u003E\n \u003CToggleSwitch IsOn=\u0022{x:Bind IsExpanded, Mode=TwoWay}\u0022\n OffContent=\u0022Off\u0022\n OnContent=\u0022On\u0022 /\u003E\n \u003Ccontrols:SettingsExpander.Items\u003E\n \u003Ccontrols:SettingsCard Header=\u0022{x:Bind LinkDescription}\u0022\u003E\n \u003CHyperlinkButton Content=\u0022{x:Bind Url}\u0022\n NavigateUri=\u0022{x:Bind Url}\u0022 /\u003E\n \u003C/controls:SettingsCard\u003E\n \u003C/controls:SettingsExpander.Items\u003E\n \u003C/controls:SettingsExpander\u003E","csharp":"using CommunityToolkit.Mvvm.ComponentModel;\n\nnamespace YourApp;\n\npublic sealed partial class YourPage : Page\n{\n\n public ObservableCollection\u003CExpandedCardInfo\u003E MyDataSet = new() {\n new()\n {\n Name = \u0022First Item\u0022,\n Info = \u0022More about first item.\u0022,\n LinkDescription = \u0022Click the link for more on first item.\u0022,\n Url = \u0022https://microsoft.com/\u0022,\n },\n new()\n {\n Name = \u0022Second Item\u0022,\n Info = \u0022More about second item.\u0022,\n LinkDescription = \u0022Click the link for more on second item.\u0022,\n Url = \u0022https://xbox.com/\u0022,\n },\n new()\n {\n Name = \u0022Third Item\u0022,\n Info = \u0022More about third item.\u0022,\n LinkDescription = \u0022Click the link for more on third item.\u0022,\n Url = \u0022https://toolkitlabs.dev/\u0022,\n },\n };\n\n public YourPage()\n {\n this.InitializeComponent();\n }\n}\n\npublic partial class ExpandedCardInfo : ObservableObject\n{\n public string? Name { get; set; }\n\n public string? Info { get; set; }\n\n public string? LinkDescription { get; set; }\n\n public string? Url { get; set; }\n\n [ObservableProperty]\n public partial bool IsExpanded { get; set; } = false;\n}","source":"toolkit","nugetPackage":"CommunityToolkit.WinUI.Controls.SettingsControls","xmlnsImports":["xmlns:controls=\u0022using:CommunityToolkit.WinUI.Controls\u0022"],"description":"You may use a list of SettingsCard or SettingsExpander to represent configurable items within a tool.","controlDescription":"An expander control that can be used to create Windows 11 style settings experiences.","relatedControls":[],"apiNamespace":null,"docs":[]},{"id":"settingsexpander-2","controlId":"settingsexpander","controlName":"SettingsExpander","headerText":"Settings Expander with ItemsSource","xaml":"\u003Ccontrols:SettingsExpander Description=\u0022The SettingsExpander can use ItemsSource to define its Items.\u0022\n Header=\u0022Settings Expander with ItemsSource\u0022\n HeaderIcon=\u0022{ui:FontIcon Glyph=\u0026#xEA37;}\u0022\n ItemsSource=\u0022{x:Bind MyDataSet}\u0022\u003E\n \u003Ccontrols:SettingsExpander.ItemTemplate\u003E\n \u003CDataTemplate x:DataType=\u0022local:MyDataModel\u0022\u003E\n \u003Ccontrols:SettingsCard Description=\u0022{x:Bind Info}\u0022\n Header=\u0022{x:Bind Name}\u0022\u003E\n \u003CHyperlinkButton Content=\u0022{x:Bind LinkDescription}\u0022\n NavigateUri=\u0022{x:Bind Url}\u0022 /\u003E\n \u003C/controls:SettingsCard\u003E\n \u003C/DataTemplate\u003E\n \u003C/controls:SettingsExpander.ItemTemplate\u003E\n \u003Ccontrols:SettingsExpander.ItemsHeader\u003E\n \u003Cmuxc:InfoBar Title=\u0022This is the ItemsHeader\u0022\n IsIconVisible=\u0022False\u0022\n IsOpen=\u0022True\u0022\n Severity=\u0022Success\u0022\u003E\n \u003Cmuxc:InfoBar.ActionButton\u003E\n \u003CHyperlinkButton Content=\u0022It can host custom content\u0022 /\u003E\n \u003C/muxc:InfoBar.ActionButton\u003E\n \u003C/muxc:InfoBar\u003E\n \u003C/controls:SettingsExpander.ItemsHeader\u003E\n \u003Ccontrols:SettingsExpander.ItemsFooter\u003E\n \u003Ccontrols:SettingsCard Header=\u0022This is the ItemsFooter\u0022\n Style=\u0022{StaticResource DefaultSettingsExpanderItemStyle}\u0022\u003E\n \u003CButton Content=\u0022Add a device\u0022 /\u003E\n \u003C/controls:SettingsCard\u003E\n \u003C/controls:SettingsExpander.ItemsFooter\u003E\n \u003C/controls:SettingsExpander\u003E","csharp":null,"source":"toolkit","nugetPackage":"CommunityToolkit.WinUI.Controls.SettingsControls","xmlnsImports":["xmlns:controls=\u0022using:CommunityToolkit.WinUI.Controls\u0022","xmlns:ui=\u0022using:CommunityToolkit.WinUI\u0022"],"description":"You can easily override certain properties to create custom experiences. For instance, you can customize the ContentAlignment of a SettingsCard, to align your content to the Right (default), Left (hiding the HeaderIcon, Header and Descri...","controlDescription":"An expander control that can be used to create Windows 11 style settings experiences.","relatedControls":[],"apiNamespace":null,"docs":[]},{"id":"settingsexpander-3","controlId":"settingsexpander","controlName":"SettingsExpander","headerText":"Settings Expander with a custom ItemTemplate","xaml":"\u003Ccontrols:SettingsExpander Description=\u0022SettingsExpander can use a DataTemplate, DataTemplateSelector, or IElementFactory for its ItemTemplate.\u0022\n Header=\u0022Settings Expander with a custom ItemTemplate\u0022\n HeaderIcon=\u0022{ui:FontIcon Glyph=\u0026#xE8FD;}\u0022\n ItemsSource=\u0022{x:Bind MyDataSet}\u0022\u003E\n \u003Ccontrols:SettingsExpander.ItemTemplate\u003E\n \u003Clocal:MyDataModelTemplateSelector\u003E\n \u003Clocal:MyDataModelTemplateSelector.ButtonTemplate\u003E\n \u003CDataTemplate x:DataType=\u0022local:MyDataModel\u0022\u003E\n \u003Ccontrols:SettingsCard Description=\u0022{x:Bind ItemType}\u0022\n Header=\u0022{x:Bind Name}\u0022\u003E\n \u003CButton Click=\u0022Button_Click\u0022\n Content=\u0022{x:Bind LinkDescription}\u0022 /\u003E\n \u003C/controls:SettingsCard\u003E\n \u003C/DataTemplate\u003E\n \u003C/local:MyDataModelTemplateSelector.ButtonTemplate\u003E\n \u003Clocal:MyDataModelTemplateSelector.LinkButtonTemplate\u003E\n \u003CDataTemplate x:DataType=\u0022local:MyDataModel\u0022\u003E\n \u003Ccontrols:SettingsCard Description=\u0022{x:Bind ItemType}\u0022\n Header=\u0022{x:Bind Name}\u0022\u003E\n \u003CHyperlinkButton Content=\u0022{x:Bind LinkDescription}\u0022\n NavigateUri=\u0022{x:Bind Url}\u0022 /\u003E\n \u003C/controls:SettingsCard\u003E\n \u003C/DataTemplate\u003E\n \u003C/local:MyDataModelTemplateSelector.LinkButtonTemplate\u003E\n \u003Clocal:MyDataModelTemplateSelector.NoButtonTemplate\u003E\n \u003CDataTemplate x:DataType=\u0022local:MyDataModel\u0022\u003E\n \u003Ccontrols:SettingsCard Description=\u0022{x:Bind ItemType}\u0022\n Header=\u0022{x:Bind Name}\u0022 /\u003E\n \u003C/DataTemplate\u003E\n \u003C/local:MyDataModelTemplateSelector.NoButtonTemplate\u003E\n \u003C/local:MyDataModelTemplateSelector\u003E\n \u003C/controls:SettingsExpander.ItemTemplate\u003E\n \u003C/controls:SettingsExpander\u003E","csharp":null,"source":"toolkit","nugetPackage":"CommunityToolkit.WinUI.Controls.SettingsControls","xmlnsImports":["xmlns:controls=\u0022using:CommunityToolkit.WinUI.Controls\u0022","xmlns:ui=\u0022using:CommunityToolkit.WinUI\u0022"],"description":"You can easily override certain properties to create custom experiences. For instance, you can customize the ContentAlignment of a SettingsCard, to align your content to the Right (default), Left (hiding the HeaderIcon, Header and Descri...","controlDescription":"An expander control that can be used to create Windows 11 style settings experiences.","relatedControls":[],"apiNamespace":null,"docs":[]},{"id":"settingsexpander-4","controlId":"settingsexpander","controlName":"SettingsExpander","headerText":"Basic usage","xaml":"\u003Ccontrols:SettingsExpander\n Description=\u0022The SettingsExpander has the same properties as a Card, and you can set SettingsCard as part of the Items collection.\u0022\n Header=\u0022SettingsExpander\u0022\n HeaderIcon=\u0022{ui:FontIcon Glyph=\u0026#xE91B;}\u0022\u003E\n \u003CComboBox\u003E\n \u003CComboBoxItem\u003EOption 1\u003C/ComboBoxItem\u003E\n \u003CComboBoxItem\u003EOption 2\u003C/ComboBoxItem\u003E\n \u003CComboBoxItem\u003EOption 3\u003C/ComboBoxItem\u003E\n \u003C/ComboBox\u003E\n \u003Ccontrols:SettingsExpander.Items\u003E\n \u003Ccontrols:SettingsCard Header=\u0022A basic SettingsCard within an SettingsExpander\u0022\u003E\n \u003CButton Content=\u0022Button\u0022 /\u003E\n \u003C/controls:SettingsCard\u003E\n \u003Ccontrols:SettingsCard Description=\u0022SettingsCard within an Expander can be made clickable too!\u0022\n Header=\u0022This item can be clicked\u0022\n IsClickEnabled=\u0022True\u0022 /\u003E\u003C/controls:SettingsExpander.Items\u003E\u003C/controls:SettingsExpander\u003E\n\u003C!-- ...truncated --\u003E","csharp":"namespace YourApp;\n\npublic sealed partial class YourPage : Page\n{\n public YourPage()\n {\n this.InitializeComponent();\n }\n}","source":"toolkit","nugetPackage":"CommunityToolkit.WinUI.Controls.SettingsControls","xmlnsImports":["xmlns:controls=\u0022using:CommunityToolkit.WinUI.Controls\u0022","xmlns:ui=\u0022using:CommunityToolkit.WinUI\u0022"],"description":"The SettingsExpander can be used to group multiple SettingsCards into a single collapsible group. A SettingsExpander can have it\u0027s own content to display a setting on the right, just like a SettingsCard, but in addition can have any numb...","controlDescription":"An expander control that can be used to create Windows 11 style settings experiences.","relatedControls":[],"apiNamespace":null,"docs":[]},{"id":"settingscard-9","controlId":"settingscard","controlName":"SettingsCard","headerText":"Settings Page Example","xaml":"\u003Ccontrols:SettingsCard Description=\u0022This is a default card, with the Header, HeaderIcon, Description and Content set\u0022\n Header=\u0022This is the Header\u0022\n HeaderIcon=\u0022{ui:FontIcon Glyph=\u0026#xE716;}\u0022\u003E\n \u003CToggleSwitch IsOn=\u0022True\u0022 /\u003E\n \u003C/controls:SettingsCard\u003E\r\n\r\n\u003Ccontrols:SettingsCard Header=\u0022A basic SettingsCard within an SettingsExpander\u0022\u003E\n \u003CButton Content=\u0022Button\u0022 /\u003E\n \u003C/controls:SettingsCard\u003E\r\n\r\n\u003Ccontrols:SettingsCard Description=\u0022SettingsCard within an Expander can be made clickable too!\u0022\n Header=\u0022This item can be clicked\u0022\n IsClickEnabled=\u0022True\u0022 /\u003E\r\n\r\n\u003Ccontrols:SettingsCard ContentAlignment=\u0022Left\u0022\u003E\n \u003CCheckBox Content=\u0022Here the ContentAlignment is set to Left. This is great for e.g. CheckBoxes or RadioButtons\u0022 /\u003E\u003C/controls:SettingsCard\u003E\n\u003C!-- ...truncated --\u003E","csharp":"namespace YourApp;\n\npublic sealed partial class YourPage : Page\n{\n public YourPage()\n {\n this.InitializeComponent();\n }\n}","source":"toolkit","nugetPackage":"CommunityToolkit.WinUI.Controls.SettingsControls","xmlnsImports":["xmlns:controls=\u0022using:CommunityToolkit.WinUI.Controls\u0022","xmlns:ui=\u0022using:CommunityToolkit.WinUI\u0022"],"description":"The following sample provides a typical design page, following the correct Windows 11 design specifications for things like spacing, section headers and animations.","controlDescription":"A card control that can be used to create Windows 11 style settings experiences.","relatedControls":[],"apiNamespace":null,"docs":[]},{"id":"contentsizer-1","controlId":"contentsizer","controlName":"ContentSizer","headerText":"Left Shelf","xaml":"\u003CGrid\u003E\n \u003CGrid.ColumnDefinitions\u003E\n \u003CColumnDefinition Width=\u0022Auto\u0022 /\u003E\n \u003CColumnDefinition Width=\u0022Auto\u0022 /\u003E\n \u003CColumnDefinition /\u003E\n \u003C/Grid.ColumnDefinitions\u003E\n \u003CBorder\u003E\n \u003CTextBlock\n Foreground=\u0022{ThemeResource TextOnAccentFillColorPrimaryBrush}\u0022\n Style=\u0022{ThemeResource BodyStrongTextBlockStyle}\u0022\n Text=\u0022Side Content\u0022 /\u003E\n \u003C/Border\u003E\n \u003Ccontrols:ContentSizer Grid.Column=\u00221\u0022\n TargetControl=\u0022{x:Bind SideContent}\u0022 /\u003E\n \u003C/Grid\u003E","csharp":"namespace YourApp;\n\npublic sealed partial class YourPage : Page\n{\n public YourPage()\n {\n this.InitializeComponent();\n }\n}","source":"toolkit","nugetPackage":"CommunityToolkit.WinUI.Controls.Sizers","xmlnsImports":["xmlns:controls=\u0022using:CommunityToolkit.WinUI.Controls\u0022"],"description":"The following example shows how to use the ContentSizer to create a left-side shelf; however, this scenario can also be accomplished with a GridSplitter.","controlDescription":"The ContentSizer is a control which can be used to resize any element, usually its parent.","relatedControls":[],"apiNamespace":null,"docs":[]},{"id":"contentsizer-2","controlId":"contentsizer","controlName":"ContentSizer","headerText":"Top Shelf","xaml":"\u003CGrid\u003E\n \u003CGrid.RowDefinitions\u003E\n \u003CRowDefinition Height=\u0022Auto\u0022 /\u003E\n \u003CRowDefinition Height=\u0022Auto\u0022 /\u003E\n \u003CRowDefinition Height=\u0022*\u0022 /\u003E\n \u003C/Grid.RowDefinitions\u003E\n \u003Cmuxc:Expander\n HorizontalContentAlignment=\u0022Stretch\u0022\n ExpandDirection=\u0022Up\u0022\n Header=\u0022This is some Shelf\u0022\n IsExpanded=\u0022True\u0022\u003E\n \u003CGrid\u003E\n \u003CTextBlock\n Text=\u0022This is the expanded content\u0022\n TextWrapping=\u0022Wrap\u0022 /\u003E\n \u003C/Grid\u003E\n \u003C/muxc:Expander\u003E\n \u003Ccontrols:ContentSizer Grid.Row=\u00221\u0022\n Orientation=\u0022Horizontal\u0022\n TargetControl=\u0022{x:Bind ExpandContent}\u0022\n Visibility=\u0022{x:Bind TopExpander.IsExpanded, Mode=OneWay}\u0022 /\u003E\n \u003C/Grid\u003E","csharp":"namespace YourApp;\n\npublic sealed partial class YourPage : Page\n{\n public YourPage()\n {\n this.InitializeComponent();\n }\n}","source":"toolkit","nugetPackage":"CommunityToolkit.WinUI.Controls.Sizers","xmlnsImports":["xmlns:controls=\u0022using:CommunityToolkit.WinUI.Controls\u0022"],"description":"If you are using a Grid, use GridSplitter instead. The main use-case for a ContentSizer is to create an expandable shelf for your application.","controlDescription":"The ContentSizer is a control which can be used to resize any element, usually its parent.","relatedControls":[],"apiNamespace":null,"docs":[]},{"id":"gridsplitter-1","controlId":"gridsplitter","controlName":"GridSplitter","headerText":"Basic usage","xaml":"\u003Ccontrols:GridSplitter Grid.Column=\u00221\u0022\n ResizeBehavior=\u0022BasedOnAlignment\u0022\n ResizeDirection=\u0022Auto\u0022\u003E\n \u003Ccontrols:GridSplitter.RenderTransform\u003E\n \u003CTranslateTransform X=\u0022-7\u0022 /\u003E\n \u003C/controls:GridSplitter.RenderTransform\u003E\n \u003C/controls:GridSplitter\u003E\r\n\r\n\u003Ccontrols:GridSplitter Grid.Row=\u00221\u0022\n Grid.ColumnSpan=\u00224\u0022\u003E\n \u003Ccontrols:GridSplitter.RenderTransform\u003E\n \u003CTranslateTransform Y=\u0022-7\u0022 /\u003E\n \u003C/controls:GridSplitter.RenderTransform\u003E\n \u003C/controls:GridSplitter\u003E\r\n\r\n\u003Ccontrols:GridSplitter Grid.Row=\u00220\u0022\n Grid.RowSpan=\u00222\u0022\n Grid.Column=\u00223\u0022\n ResizeBehavior=\u0022BasedOnAlignment\u0022\n ResizeDirection=\u0022Auto\u0022\u003E\n \u003Ccontrols:GridSplitter.RenderTransform\u003E\n \u003CTranslateTransform X=\u0022-7\u0022 /\u003E\u003C/controls:GridSplitter.RenderTransform\u003E\u003C/controls:GridSplitter\u003E\n\u003C!-- ...truncated --\u003E","csharp":"namespace YourApp;\n\n/// \u003Csummary\u003E\n/// An empty page that can be used on its own or navigated to within a Frame.\n/// \u003C/summary\u003E\npublic sealed partial class YourPage : Page\n{\n public YourPage()\n {\n this.InitializeComponent();\n }\n}","source":"toolkit","nugetPackage":"CommunityToolkit.WinUI.Controls.Sizers","xmlnsImports":["xmlns:controls=\u0022using:CommunityToolkit.WinUI.Controls\u0022"],"description":"The control automatically detects the targeted columns/rows to resize, while dragging the control it starts to resize the columns/rows and redistributes space between columns/rows, you can manually specify the ResizeDirection (Auto / Col...","controlDescription":"The GridSplitter control provides an easy-to-use Splitter that redistributes space between columns or rows of a Grid Control.","relatedControls":[],"apiNamespace":null,"docs":[]},{"id":"propertysizer-1","controlId":"propertysizer","controlName":"PropertySizer","headerText":"Navigation View","xaml":"\u003Ccontrols:PropertySizer\n Binding=\u0022{x:Bind ViewPanel.OpenPaneLength, Mode=TwoWay}\u0022\n Maximum=\u0022440\u0022\n Minimum=\u002252\u0022\n Visibility=\u0022{x:Bind ViewPanel.IsPaneOpen, Mode=OneWay}\u0022 /\u003E","csharp":"namespace YourApp;\n\npublic sealed partial class YourPage : Page\n{\n public YourPage()\n {\n this.InitializeComponent();\n }\n}","source":"toolkit","nugetPackage":"CommunityToolkit.WinUI.Controls.Sizers","xmlnsImports":["xmlns:controls=\u0022using:CommunityToolkit.WinUI.Controls\u0022"],"description":"The main use-case is for PropertySizer to allow you to manipulate the OpenPaneLength property of a NavigationView control to create a user customizable size shelf.","controlDescription":"The PropertySizer is a control which can be used to manipulate the value of another double based property.","relatedControls":[],"apiNamespace":null,"docs":[]},{"id":"contentsizer-3","controlId":"contentsizer","controlName":"ContentSizer","headerText":"Sizer Cursor","xaml":"\u003CGrid\u003E\n \u003CGrid.ColumnDefinitions\u003E\n \u003CColumnDefinition Width=\u0022Auto\u0022 /\u003E\n \u003CColumnDefinition Width=\u0022Auto\u0022 /\u003E\n \u003CColumnDefinition /\u003E\n \u003C/Grid.ColumnDefinitions\u003E\n \u003Ccontrols:ContentSizer Grid.Column=\u00221\u0022\n Cursor=\u0022Hand\u0022\n TargetControl=\u0022{x:Bind SomeContent}\u0022 /\u003E\n \u003C/Grid\u003E","csharp":"namespace YourApp;\n\npublic sealed partial class YourPage : Page\n{\n public YourPage()\n {\n this.InitializeComponent();\n }\n}","source":"toolkit","nugetPackage":"CommunityToolkit.WinUI.Controls.Sizers","xmlnsImports":["xmlns:controls=\u0022using:CommunityToolkit.WinUI.Controls\u0022"],"description":"You may want to change the cursor that is shown when hovering over your element like this:","controlDescription":"The ContentSizer is a control which can be used to resize any element, usually its parent.","relatedControls":[],"apiNamespace":null,"docs":[]},{"id":"tabbedcommandbar-1","controlId":"tabbedcommandbar","controlName":"TabbedCommandBar","headerText":"Basic usage","xaml":"\u003CGrid\u003E\n \u003Ccontrols:TabbedCommandBar\u003E\n \u003Ccontrols:TabbedCommandBar.AutoSuggestBox\u003E\n \u003CAutoSuggestBox\n QueryIcon=\u0022Find\u0022 /\u003E\n \u003C/controls:TabbedCommandBar.AutoSuggestBox\u003E\n \u003Ccontrols:TabbedCommandBar.PaneFooter\u003E\n \u003CCommandBar Background=\u0022Transparent\u0022\n DefaultLabelPosition=\u0022Right\u0022\u003E\n \u003CAppBarButton Icon=\u0022{ui:FontIcon Glyph=\u0026#xE72D;}\u0022\n Label=\u0022Share\u0022 /\u003E\n \u003CAppBarButton Icon=\u0022{ui:FontIcon Glyph=\u0026#xE8BD;}\u0022\n Label=\u0022Comments\u0022 /\u003E\n \u003C/CommandBar\u003E\n \u003C/controls:TabbedCommandBar.PaneFooter\u003E\n \u003Ccontrols:TabbedCommandBar.MenuItems\u003E\n \u003Ccontrols:TabbedCommandBarItem Header=\u0022Home\u0022\u003E\n \u003CAppBarButton Icon=\u0022{ui:FontIcon Glyph=\u0026#xE7A7;}\u0022\n Label=\u0022Undo\u0022 /\u003E\u003C/controls:TabbedCommandBarItem\u003E\u003C/controls:TabbedCommandBar.MenuItems\u003E\u003C/controls:TabbedCommandBar\u003E\u003C/Grid\u003E\n\u003C!-- ...truncated --\u003E","csharp":"using CommunityToolkit.WinUI.Controls;\n\nnamespace YourApp;\n\npublic sealed partial class YourPage : Page\n{\n public YourPage()\n {\n this.InitializeComponent();\n }\n}","source":"toolkit","nugetPackage":"CommunityToolkit.WinUI.Controls.TabbedCommandBar","xmlnsImports":["xmlns:controls=\u0022using:CommunityToolkit.WinUI.Controls\u0022","xmlns:ui=\u0022using:CommunityToolkit.WinUI\u0022"],"description":"The TabbedCommandBar displays a set of TabbedCommandBarItem in a shared container found in many productivity type apps.","controlDescription":"A control for displaying multiple CommandBars in the same space, like Microsoft Office\u0027s ribbon.","relatedControls":[],"apiNamespace":null,"docs":[]},{"id":"tokenizingtextbox-1","controlId":"tokenizingtextbox","controlName":"TokenizingTextBox","headerText":"Basic usage","xaml":"\u003Ccontrols:TokenizingTextBox\n ItemClick=\u0022TokenBox_ItemClick\u0022\n ItemsSource=\u0022{x:Bind SelectedTokens, Mode=TwoWay}\u0022\n Loaded=\u0022TokenBox_Loaded\u0022\n MaximumTokens=\u00225\u0022\n PlaceholderText=\u0022Add actions\u0022\n QueryIcon=\u0022{ui:FontIconSource Glyph=\u0026#xE721;,\n FontSize=12}\u0022\n SuggestedItemsSource=\u0022{x:Bind _samples, Mode=OneWay}\u0022\n TextChanged=\u0022TextChanged\u0022\n TextMemberPath=\u0022Text\u0022\n TokenDelimiter=\u0022,\u0022\n TokenItemAdding=\u0022TokenItemCreating\u0022\u003E\n \u003Ccontrols:TokenizingTextBox.Header\u003E\n \u003C/controls:TokenizingTextBox.Header\u003E\u003C/controls:TokenizingTextBox\u003E\n\u003C!-- ...truncated --\u003E","csharp":"using CommunityToolkit.WinUI.Controls;\n\nnamespace YourApp;\n\npublic sealed partial class YourPage : Page\n{\n public readonly List\u003CSampleDataType\u003E _samples = new List\u003CSampleDataType\u003E()\n {\n new SampleDataType() { Text = \u0022Account\u0022, Icon = Symbol.Account },\n new SampleDataType() { Text = \u0022Add friend\u0022, Icon = Symbol.AddFriend },\n new SampleDataType() { Text = \u0022Attach\u0022, Icon = Symbol.Attach },\n new SampleDataType() { Text = \u0022Attach camera\u0022, Icon = Symbol.AttachCamera },\n new SampleDataType() { Text = \u0022Audio\u0022, Icon = Symbol.Audio },\n new SampleDataType() { Text = \u0022Block contact\u0022, Icon = Symbol.BlockContact },\n new SampleDataType() { Text = \u0022Calculator\u0022, Icon = Symbol.Calculator },\n new SampleDataType() { Text = \u0022Calendar\u0022, Icon = Symbol.Calendar },\n new SampleDataType() { Text = \u0022Camera\u0022, Icon = Symbol.Camera },\n new SampleDataType() { Text = \u0022Contact\u0022, Icon = Symbol.Contact },\n new SampleDataType() { Text = \u0022Favorite\u0022, Icon = Symbol.Favorite },\n new SampleDataType() { Text = \u0022Link\u0022, Icon = Symbol.Link },\n new SampleDataType() { Text = \u0022Mail\u0022, Icon = Symbol.Mail },\n new SampleDataType() { Text = \u0022Map\u0022, Icon = Symbol.Map },\n new SampleDataType() { Text = \u0022Phone\u0022, Icon = Symbol.Phone },\n new SampleDataType() { Text = \u0022Pin\u0022, Icon = Symbol.Pin },\n new SampleDataType() { Text = \u0022Rotate\u0022, Icon = Symbol.Rotate },\n new SampleDataType() { Text = \u0022Rotate camera\u0022, Icon = Symbol.RotateCamera },\n new SampleDataType() { Text = \u0022Send\u0022, Icon = Symbol.Send },\n new SampleDataType() { Text = \u0022Tags\u0022, Icon = Symbol.Tag },\n new SampleDataType() { Text = \u0022UnFavorite\u0022, Icon = Symbol.UnFavorite },\n new SampleDataType() { Text = \u0022UnPin\u0022, Icon = Symbol.UnPin },\n new SampleDataType() { Text = \u0022Zoom\u0022, Icon = Symbol.Zoom },\n new SampleDataType() { Text = \u0022ZoomIn\u0022, Icon = Symbol.ZoomIn },\n new SampleDataType() { Text = \u0022ZoomOut\u0022, Icon = Symbol.ZoomOut },\n };\n\n public ObservableCollection\u003CSampleDataType\u003E SelectedTokens { get; set; }\n\n public YourPage()\n {\n this.InitializeComponent();\n SelectedTokens = new()\n {\n _samples[0],\n _samples[1]\n };\n \n }\n\n private void TextChanged(AutoSuggestBox sender, AutoSuggestBoxTextChangedEventArgs args)\n {\n// ...truncated","source":"toolkit","nugetPackage":"CommunityToolkit.WinUI.Controls.TokenizingTextBox","xmlnsImports":["xmlns:controls=\u0022using:CommunityToolkit.WinUI.Controls\u0022","xmlns:ui=\u0022using:CommunityToolkit.WinUI\u0022"],"description":"The TokenizingTextBox is an advanced AutoSuggestBox which will display selected items as tokens within the textbox. A user can easily see the picked items or remove them easily.","controlDescription":"A text input control that auto-suggests and displays token items.","relatedControls":[],"apiNamespace":null,"docs":[]}] \ No newline at end of file diff --git a/src/tools/winui-search/Data/toolkit-tags.json b/src/tools/winui-search/Data/toolkit-tags.json deleted file mode 100644 index 3b639fef..00000000 --- a/src/tools/winui-search/Data/toolkit-tags.json +++ /dev/null @@ -1 +0,0 @@ -{"advancedcollectionview":["advancedcollectionview","collection","view","collectionviewsource","data","sorting","filtering","collections","viewmodel","sort","bound","listview","list","useful","features","provides"],"incrementalloadingcollection":["incrementalloadingcollection","incremental","loading","collection","data","collections","incrementally"],"colorpicker":["colorpicker","color","picker","spectrum","palette","sliders"],"headeredcontentcontrol":["headeredcontentcontrol","headered","align","left","same","contentcontrol"],"headereditemscontrol":["headereditemscontrol","headered","same","itemscontrol"],"headeredtreeview":["headeredtreeview","headered","tree","view","treeview"],"imagecropper":["imagecropper","image","cropper","media","freely","crop"],"metadatacontrol":["metadatacontrol","metadata","statusandinfo","bullet","separator","customized","string","list","metadataitem","displayed","either"],"constrainedbox":["constrainedbox","constrained","box","viewbox","content decorator","media","border","template","compatibility","future","inherit","frameworkelement","directly","platform"],"dockpanel":["dockpanel","dock","panel","position","child","left","right","bottom","lastchildfill","want","last"],"staggeredlayout":["staggeredlayout","staggered","staggeredpanel","column","better","virtualization","compared","below"],"staggeredpanel":["staggeredpanel","staggered","panel","staggeredlayout","column"],"switchpresenter":["switchpresenter","switch","presenter","logic","contentpresenter","visibility","triggers","converters","miscellaneous","statement","developer","condition","alternative","managing","multiple","complex","visual"],"uniformgrid":["uniformgrid","uniform","grid","responsive","miscellaneous","cell","same","size","square","total","number","visible"],"wraplayout":["wraplayout","wrap","ordering","bottom","right","left","orientation","positions","child","horizontal"],"wrappanel":["wrappanel","wrap","panel","ordering","bottom","right","left","orientation","position","child","horizontal"],"radialgauge":["radialgauge","radial","gauge","data","visualizations","dashboards","engaging","rich","style","interactivity","round"],"rangeselector":["rangeselector","range","selector","double slider","slider rangeslider","regular"],"richsuggestbox":["richsuggestbox","rich","suggest","box","combination","autosuggestbox","richeditbox","suggestions","customizable","prefixes","selected","embedded"],"segmented":["segmented","segmentedcontrol","best","overflow"],"settingscard":["settingscard","settings","card","experience","uses","styling","windows","meets","accessibility","standards","page"],"settingsexpander":["settingsexpander","settings","expander","settingscard","group","multiple","single","collapsible","right","addition","number","extra"],"contentsizer":["contentsizer","sizer","sizerbase","expander","splitter","sizers","gridsplitter","expandable","shelf","application","itself","remember","opening","closing"],"gridsplitter":["gridsplitter","grid","splitter","contentsizer","sizerbase","expander","sizers","automatically","detects","targeted","columns","rows","resize","dragging","starts"],"propertysizer":["propertysizer","sizer","sizerbase","navigationview","splitter","sizers","manipulating"],"tabbedcommandbar":["tabbedcommandbar","tabbed","command","bar","commandbar","ribbon","tabbedcommandbaritem","shared","container","productivity","apps","navigationview","change","style"],"tokenizingtextbox":["tokenizingtextbox","tokenizing","box","tokens","autosuggestbox","selected","within","textbox","easily","picked","remove"],"colorpickerbutton":["colorpickerbutton","color","picker","button","dropdown"]} \ No newline at end of file diff --git a/src/tools/winui-search/DataLoader.cs b/src/tools/winui-search/DataLoader.cs deleted file mode 100644 index c03880d7..00000000 --- a/src/tools/winui-search/DataLoader.cs +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using System.Reflection; -using System.Text.Json; - -internal static class DataLoader -{ - public static Scenario[] LoadGalleryScenarios() - { - using var stream = Assembly.GetExecutingAssembly() - .GetManifestResourceStream("gallery-scenarios.json")!; - return JsonSerializer.Deserialize(stream, JsonContext.Default.ScenarioArray)!; - } - - public static Scenario[] LoadToolkitScenarios() - { - using var stream = Assembly.GetExecutingAssembly() - .GetManifestResourceStream("toolkit-scenarios.json")!; - return JsonSerializer.Deserialize(stream, JsonContext.Default.ScenarioArray)!; - } - - public static CorePattern[] LoadCorePatterns() - { - using var stream = Assembly.GetExecutingAssembly() - .GetManifestResourceStream("core-patterns.json")!; - return JsonSerializer.Deserialize(stream, JsonContext.Default.CorePatternArray)!; - } - - public static Dictionary LoadGalleryTags() - { - using var stream = Assembly.GetExecutingAssembly() - .GetManifestResourceStream("gallery-tags.json")!; - return JsonSerializer.Deserialize(stream, JsonContext.Default.DictionaryStringStringArray)!; - } - - public static Dictionary LoadToolkitTags() - { - using var stream = Assembly.GetExecutingAssembly() - .GetManifestResourceStream("toolkit-tags.json")!; - return JsonSerializer.Deserialize(stream, JsonContext.Default.DictionaryStringStringArray)!; - } - - public static Scenario[] LoadReactorScenarios() - { - using var stream = Assembly.GetExecutingAssembly() - .GetManifestResourceStream("reactor-scenarios.json")!; - return JsonSerializer.Deserialize(stream, JsonContext.Default.ScenarioArray)!; - } - - /// Reactor's curated per-control keywords, served as the enrichment - /// tag dictionary. Verbatim — never stop-word cleaned (protects multi-word - /// intent terms like "css layout"). - public static Dictionary LoadReactorTags() - { - using var stream = Assembly.GetExecutingAssembly() - .GetManifestResourceStream("reactor-tags.json")!; - return JsonSerializer.Deserialize(stream, JsonContext.Default.DictionaryStringStringArray)!; - } - - /// Author-curated keywords from toolkit md frontmatter — short - /// list of high-quality intent terms scored at higher BM25 weight than - /// auto-extracted tags. Empty/missing → no extra signal. - public static Dictionary LoadToolkitKeywords() - { - var stream = Assembly.GetExecutingAssembly() - .GetManifestResourceStream("toolkit-keywords.json"); - if (stream == null) return new(); - using (stream) - { - return JsonSerializer.Deserialize(stream, JsonContext.Default.DictionaryStringStringArray) ?? new(); - } - } -} diff --git a/src/tools/winui-search/GalleryFetcher.cs b/src/tools/winui-search/GalleryFetcher.cs deleted file mode 100644 index 1e8925f4..00000000 --- a/src/tools/winui-search/GalleryFetcher.cs +++ /dev/null @@ -1,849 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using System.Net.Http; -using System.Text.Json; -using System.Text.RegularExpressions; -using System.Xml.Linq; - -internal static partial class GalleryFetcher -{ - private const string ControlInfoUrl = - "https://raw.githubusercontent.com/microsoft/WinUI-Gallery/main/WinUIGallery/SampleSupport/Data/ControlInfoData.json"; - // Per-control sample pages AND their co-located SampleDefinition .txt bundles both live - // under Samples/{UniqueId}/. Upstream retired Samples/ControlPages/ and Samples/SampleCode/. - private const string SamplesBase = - "https://raw.githubusercontent.com/microsoft/WinUI-Gallery/main/WinUIGallery/Samples/"; - - private static readonly HttpClient Http = new() - { - DefaultRequestHeaders = { { "User-Agent", "winui3-gallery-cli/1.0" } }, - Timeout = TimeSpan.FromSeconds(30) - }; - - [GeneratedRegex(@"]*?HeaderText=""([^""]+)""", RegexOptions.IgnoreCase)] - private static partial Regex ControlExampleHeaderRegex(); - - /// First XML comment in a XAML snippet — used as a fallback header when - /// the upstream ControlExample omits HeaderText (common for Accessibility samples). - [GeneratedRegex(@"")] - private static partial Regex FirstXmlCommentRegex(); - - /// New-format SampleDefinition attribute pointing at the co-located .txt bundle - /// (e.g. SampleDefinition="Button\ButtonSimple.txt", relative to Samples/). - [GeneratedRegex(@"SampleDefinition=""([^""]+)""", RegexOptions.IgnoreCase)] - private static partial Regex SampleDefinitionRegex(); - - /// A section-marker line inside a SampleDefinition .txt bundle: - /// --- header, --- xaml, or --- c# (case-insensitive, CRLF-tolerant). - [GeneratedRegex(@"^\s*---\s*(header|xaml|c#)\s*$", RegexOptions.IgnoreCase)] - private static partial Regex SampleSectionRegex(); - - [GeneratedRegex(@"\$\([^)]+\)")] - private static partial Regex SubstitutionRegex(); - - [GeneratedRegex(@"ms-appx:///Assets/SampleMedia/[^""'\s]+")] - private static partial Regex SampleMediaRegex(); - - [GeneratedRegex(@"x:Class=""WinUIGallery\.[^""]+""")] - private static partial Regex GalleryClassRegex(); - - [GeneratedRegex(@"typeof\(SamplePage\d+\)")] - private static partial Regex SamplePageTypeRegex(); - - [GeneratedRegex(@"SamplePage\d+")] - private static partial Regex SamplePageNameRegex(); - - /// Embedded snapshot baked into the exe at build time — the offline - /// fallback served when the on-disk cache is missing or stale. - internal static (Scenario[] scenarios, Dictionary tags) LoadEmbedded() - => (DataLoader.LoadGalleryScenarios(), CleanTags(DataLoader.LoadGalleryTags())); - - /// Fetch fresh scenarios + tags from GitHub (used by the `update` - /// command). Applies curated overrides and injects hand-maintained controls - /// missing from the upstream Gallery data. - internal static async Task<(Scenario[] scenarios, Dictionary tags)> FetchAsync() - { - var (scenarios, tags) = await FetchFromGitHub(); - if (scenarios.Length > 0) - { - ApplyOverrides(scenarios); - scenarios = InjectMissing(scenarios); - } - return (scenarios, tags); - } - - private static async Task<(Scenario[], Dictionary)> FetchFromGitHub() - { - // Step 1: Fetch ControlInfoData.json — list of controls + Subtitle/Description/RelatedControls/Docs - var infoJson = await Http.GetStringAsync(ControlInfoUrl); - using var doc = JsonDocument.Parse(infoJson); - var groups = doc.RootElement.GetProperty("Groups"); - - var controlPages = new List<(string uniqueId, string title)>(); - var subtitles = new Dictionary(); // controlId → "Title Subtitle Description" (tag-source text) - var controlSubtitles = new Dictionary(); // controlId → Subtitle alone (display-friendly one-liner) - var apiNamespaces = new Dictionary(); // controlId → "Microsoft.Windows.Notifications" etc. - var relatedControls = new Dictionary(); // controlId → ["Pivot","NavigationView",...] - var docs = new Dictionary(); // controlId → [{Title,Uri},...] - - foreach (var group in groups.EnumerateArray()) - { - // Upstream retired the per-group `Folder` subpath (IsSpecialSection items used to - // live under Samples/{Folder}/). Every control page is now uniformly at - // Samples/{UniqueId}/{UniqueId}Page.xaml, so we no longer read Folder. - if (!group.TryGetProperty("Items", out var items)) continue; - foreach (var item in items.EnumerateArray()) - { - var uniqueId = item.GetProperty("UniqueId").GetString() ?? ""; - var title = item.GetProperty("Title").GetString() ?? ""; - controlPages.Add((uniqueId, title)); - - var cid = uniqueId.ToLowerInvariant(); - string subtitle = ""; - if (item.TryGetProperty("Subtitle", out var sub)) subtitle = sub.GetString() ?? ""; - string description = ""; - if (item.TryGetProperty("Description", out var desc)) description = desc.GetString() ?? ""; - subtitles[cid] = $"{title} {subtitle} {description}".Trim(); - if (!string.IsNullOrWhiteSpace(subtitle)) controlSubtitles[cid] = subtitle; - - if (item.TryGetProperty("ApiNamespace", out var apiNs)) - { - var ns = apiNs.GetString(); - if (!string.IsNullOrWhiteSpace(ns)) apiNamespaces[cid] = ns!; - } - - if (item.TryGetProperty("RelatedControls", out var rel) && rel.ValueKind == JsonValueKind.Array) - { - var list = new List(); - foreach (var r in rel.EnumerateArray()) - { - var v = r.GetString(); - if (!string.IsNullOrEmpty(v)) list.Add(v!); - } - if (list.Count > 0) relatedControls[cid] = list.ToArray(); - } - - if (item.TryGetProperty("Docs", out var dList) && dList.ValueKind == JsonValueKind.Array) - { - var list = new List(); - foreach (var d in dList.EnumerateArray()) - { - var t = d.TryGetProperty("Title", out var tProp) ? (tProp.GetString() ?? "") : ""; - var u = d.TryGetProperty("Uri", out var uProp) ? (uProp.GetString() ?? "") : ""; - if (!string.IsNullOrEmpty(u)) list.Add(new DocLink { Title = t, Uri = u }); - } - if (list.Count > 0) docs[cid] = list.ToArray(); - } - } - } - - // Step 2: Fetch each control page and parse ControlExample blocks - var allScenarios = new List(); - var fetchTasks = new List>>(); - var semaphore = new SemaphoreSlim(10); - foreach (var (uniqueId, title) in controlPages) - { - fetchTasks.Add(FetchControlPageAsync( - uniqueId, title, controlSubtitles.GetValueOrDefault(uniqueId.ToLowerInvariant()), semaphore)); - } - var results = await Task.WhenAll(fetchTasks); - foreach (var batch in results) - allScenarios.AddRange(batch); - - // Stamp ControlInfoData metadata onto every scenario of that control. - // ControlDescription comes from Subtitle (median 68 chars / max 129) — the longer - // Description (median 144 / max 448) was retired during search-output compression. - // Subtitle is small enough to surface in search list without bloating tokens. - foreach (var s in allScenarios) - { - if (controlSubtitles.TryGetValue(s.ControlId, out var sub)) s.ControlDescription = sub; - if (apiNamespaces.TryGetValue(s.ControlId, out var ns)) s.ApiNamespace = ns; - if (relatedControls.TryGetValue(s.ControlId, out var r)) s.RelatedControls = r; - if (docs.TryGetValue(s.ControlId, out var dl)) s.Docs = dl; - } - - // Step 3: Build tags. For each control, prefer hand-curated embedded tags; - // otherwise auto-derive from Title + Subtitle. Always strip stop words. - var embeddedTags = DataLoader.LoadGalleryTags(); - var allTags = new Dictionary(); - foreach (var (controlId, text) in subtitles) - { - if (embeddedTags.TryGetValue(controlId, out var manual)) - { - allTags[controlId] = FilterStopWords(manual); - } - else - { - allTags[controlId] = ExtractTagsFromText(controlId, text); - } - } - // Also include any embedded tags for controls not in ControlInfoData (jumplist-* etc.) - foreach (var (k, v) in embeddedTags) - { - if (!allTags.ContainsKey(k)) allTags[k] = FilterStopWords(v); - } - - return (allScenarios.ToArray(), allTags); - } - - private static string[] FilterStopWords(string[] tags) - { - return global::StopWords.FilterTagList(tags); - } - - private static string[] ExtractTagsFromText(string controlId, string text) - { - var tags = new List { controlId }; - var seen = new HashSet { controlId }; - // Split CamelCase/PascalCase into separate words too - text = Regex.Replace(text, @"(?<=[a-z])(?=[A-Z])", " "); - foreach (Match m in Regex.Matches(text.ToLowerInvariant(), @"[a-z]{3,}")) - { - var w = m.Value; - if (global::StopWords.IsTagNoise(w)) continue; - if (seen.Add(w)) tags.Add(w); - if (tags.Count >= 12) break; - } - return tags.ToArray(); - } - - private static Dictionary CleanTags(Dictionary tags) - { - var result = new Dictionary(tags.Count); - foreach (var (k, v) in tags) result[k] = FilterStopWords(v); - return result; - } - - private static async Task> FetchControlPageAsync( - string uniqueId, string title, string? controlSubtitle, SemaphoreSlim semaphore) - { - var scenarios = new List(); - await semaphore.WaitAsync(); - try - { - // Pages are uniform: Samples/{UniqueId}/{UniqueId}Page.xaml. - var url = $"{SamplesBase}{uniqueId}/{uniqueId}Page.xaml"; - - var response = await Http.GetAsync(url); - if (!response.IsSuccessStatusCode) return scenarios; - - var xamlContent = await response.Content.ReadAsStringAsync(); - var controlId = uniqueId.ToLowerInvariant(); - int scenarioIndex = 0; - - foreach (var (rawHeader, sampleDef, block) in ExtractControlExampleBlocks(xamlContent)) - { - string headerText; - string? xaml; - string? csharp; - - if (!string.IsNullOrEmpty(sampleDef)) - { - // New format: header + xaml + c# all live in the co-located .txt bundle. - (headerText, xaml, csharp) = await FetchSampleDefinition(sampleDef); - } - else - { - // Legacy inline format — still used by a handful of Accessibility pages - // (AccessibilityKeyboard/ScreenReader): blocks - // with no SampleDefinition/HeaderText. Header falls back to the sample's own - // first XML comment — never the page-level copyright banner, which lives - // outside every ControlExample block and so is never inside `block`/`xaml`. - xaml = ExtractInlineCode(block, "Xaml"); - csharp = ExtractInlineCode(block, "CSharp"); - headerText = rawHeader; - if (string.IsNullOrEmpty(headerText) && xaml != null) - headerText = DeriveHeaderFromComment(xaml); - // A few legacy inline a11y samples have no leading comment either, which - // would leave HeaderText empty and render as "{ControlName}: " (trailing - // colon). Fall back to the control's ControlInfoData Subtitle one-liner. - // New-format samples never reach here — they always carry a --- header. - if (string.IsNullOrEmpty(headerText) && !string.IsNullOrWhiteSpace(controlSubtitle)) - headerText = controlSubtitle!.Trim(); - } - - if (xaml != null) xaml = TruncateXaml(xaml, MaxXamlChars); - if (csharp != null) csharp = TruncateCode(csharp, MaxCSharpChars, "// NOTE: snippet truncated — refer to full sample for additional code"); - - if (string.IsNullOrWhiteSpace(xaml)) xaml = null; - if (string.IsNullOrWhiteSpace(csharp)) csharp = null; - if (csharp == null && xaml == null) continue; - - scenarioIndex++; - // Scenario IDs use a simple {controlId}-{N} format (1-indexed). Stable - // within a single fetched cache; rebuilt fresh on each cache refresh. - var scenarioId = $"{controlId}-{scenarioIndex}"; - - scenarios.Add(new Scenario - { - Id = scenarioId, - ControlId = controlId, - ControlName = title, - HeaderText = headerText, - Xaml = xaml, - CSharp = csharp, - Source = "gallery", - }); - } - } - catch { /* skip this control */ } - finally { semaphore.Release(); } - - return scenarios; - } - - /// - /// Fetch and parse a new-format SampleDefinition .txt bundle. Splits it into the - /// "--- header" / "--- xaml" / "--- c#" sections and returns cleaned xaml/c# ready for - /// truncation. XAML keeps the existing $(...) → "..." flattening (stray placeholders there - /// are cosmetic). A c# section containing $(...) live-substitution tokens is dropped, because - /// flattening them yields non-compileable code (e.g. `new Vector3(..., ..., ...)`) — the same - /// "no misleading C#" rule the inline extractor already applied. - /// - private static async Task<(string header, string? xaml, string? csharp)> FetchSampleDefinition(string sampleDef) - { - var url = SamplesBase + sampleDef.Replace('\\', '/'); - string content; - try - { - var resp = await Http.GetAsync(url); - if (!resp.IsSuccessStatusCode) return ("", null, null); - content = await resp.Content.ReadAsStringAsync(); - } - catch { return ("", null, null); } - - var (header, rawXaml, rawCsharp) = SplitSampleSections(content); - - string? xaml = null; - if (!string.IsNullOrWhiteSpace(rawXaml)) - { - xaml = CleanGalleryContent(rawXaml.Trim()); - if (string.IsNullOrWhiteSpace(xaml)) xaml = null; - } - - string? csharp = null; - if (!string.IsNullOrWhiteSpace(rawCsharp) && !rawCsharp.Contains("$(")) - { - csharp = CompressCSharp(CleanGalleryContent(rawCsharp.Trim())); - if (string.IsNullOrWhiteSpace(csharp)) csharp = null; - } - - return (header, xaml, csharp); - } - - /// Split a SampleDefinition .txt bundle into its header/xaml/c# sections on the - /// "--- name" marker lines. Any content before the first marker is ignored. - private static (string header, string? xaml, string? csharp) SplitSampleSections(string content) - { - string header = ""; - string? xaml = null, csharp = null; - string? current = null; - var sb = new System.Text.StringBuilder(); - - void Flush() - { - if (current == null) return; - var text = sb.ToString().Trim('\r', '\n'); - switch (current) - { - case "header": header = text.Trim(); break; - case "xaml": xaml = text; break; - case "c#": csharp = text; break; - } - sb.Clear(); - } - - foreach (var rawLine in content.Split('\n')) - { - var line = rawLine.TrimEnd('\r'); - var m = SampleSectionRegex().Match(line); - if (m.Success) - { - Flush(); - current = m.Groups[1].Value.ToLowerInvariant(); - continue; - } - if (current != null) sb.Append(rawLine).Append('\n'); - } - Flush(); - return (header, xaml, csharp); - } - - private const int MaxXamlChars = 2000; - private const int MaxCSharpChars = 2500; - - [GeneratedRegex(@"<(/?)([A-Za-z_][\w:.\-]*)\b([^>]*?)(/?)>")] - private static partial Regex AnyTagRegex(); - - /// - /// Find all top-level <controls:ControlExample> blocks via stack-aware tag matching, - /// handling nested ScrollViewer/StackPanel inside ControlExample.Example. - /// - private static IEnumerable<(string headerText, string sampleDefinition, string block)> ExtractControlExampleBlocks(string xaml) - { - const string OpenTag = "' - int openTagEnd = xaml.IndexOf('>', afterPrefix); - if (openTagEnd < 0) yield break; - - // Self-closing? Skip. - if (xaml[openTagEnd - 1] == '/') - { - searchStart = openTagEnd + 1; - continue; - } - - // Extract header text (legacy) + SampleDefinition (new format) from opening-tag attributes - string openingTag = xaml.Substring(openIdx, openTagEnd - openIdx + 1); - var headerMatch = ControlExampleHeaderRegex().Match(openingTag); - string headerText = headerMatch.Success ? headerMatch.Groups[1].Value : ""; - var defMatch = SampleDefinitionRegex().Match(openingTag); - string sampleDefinition = defMatch.Success ? defMatch.Groups[1].Value : ""; - - // Walk forward, balancing tags - int depth = 1; - int pos = openTagEnd + 1; - int blockEnd = -1; - while (pos < xaml.Length) - { - int nextOpen = xaml.IndexOf(OpenTag, pos, StringComparison.OrdinalIgnoreCase); - int nextClose = xaml.IndexOf(CloseTag, pos, StringComparison.OrdinalIgnoreCase); - if (nextClose < 0) break; - if (nextOpen >= 0 && nextOpen < nextClose) - { - int after = nextOpen + OpenTag.Length; - // Skip ControlExample.Xaml/.CSharp/.Example sub-properties (they don't open a new block) - if (after < xaml.Length && xaml[after] != '.' && !char.IsLetterOrDigit(xaml[after])) - { - int gt = xaml.IndexOf('>', after); - if (gt > 0 && xaml[gt - 1] != '/') depth++; - pos = gt > 0 ? gt + 1 : nextOpen + OpenTag.Length; - continue; - } - pos = after; - } - else - { - depth--; - if (depth == 0) - { - blockEnd = nextClose + CloseTag.Length; - break; - } - pos = nextClose + CloseTag.Length; - } - } - - if (blockEnd < 0) yield break; - yield return (headerText, sampleDefinition, xaml.Substring(openIdx, blockEnd - openIdx)); - searchStart = blockEnd; - } - } - - /// Pull a usable header from the first XML comment in a sample's XAML. - /// Collapses whitespace, strips trailing punctuation, truncates at sentence boundary. - /// Returns "" when no comment is found or the comment is too short to be a real header. - private static string DeriveHeaderFromComment(string xaml) - { - var m = FirstXmlCommentRegex().Match(xaml); - if (!m.Success) return ""; - - var raw = m.Groups[1].Value; - // Collapse all whitespace runs (newlines, tabs, multi-space) to single space. - var collapsed = Regex.Replace(raw, @"\s+", " ").Trim(); - if (collapsed.Length < 4) return ""; - - // Strip stray decoration sometimes used as section dividers (****, ====, ----) - collapsed = collapsed.Trim('*', '=', '-', ' '); - if (collapsed.Length < 4) return ""; - - // Prefer the first sentence so very long explanatory comments stay short. - const int MaxHeaderLen = 120; - int firstStop = collapsed.IndexOfAny(new[] { '.', '!', '?', '\n' }); - if (firstStop > 0 && firstStop < MaxHeaderLen) collapsed = collapsed.Substring(0, firstStop); - if (collapsed.Length > MaxHeaderLen) collapsed = collapsed.Substring(0, MaxHeaderLen).TrimEnd() + "…"; - - return collapsed.Trim(); - } - - /// Truncate XAML at a safe boundary, appending closing tags for unclosed elements. - private static string TruncateXaml(string xaml, int maxChars) - { - bool needsTruncate = xaml.Length > maxChars; - string head; - if (needsTruncate) - { - // Find a safe '>' boundary - int cut = maxChars; - while (cut > 0) - { - cut = xaml.LastIndexOf('>', cut - 1); - if (cut < 0) return ""; - cut += 1; - int lastLt = xaml.LastIndexOf('<', cut - 1); - int lastGt = xaml.LastIndexOf('>', cut - 1); - if (lastLt < lastGt) break; - cut = lastLt; - } - if (cut <= 0) return ""; - head = xaml.Substring(0, cut); - } - else - { - head = xaml; - } - - // Count open/close tags. Ignore anything inside XML comments so that generic-type - // text like "ObservableCollection" inside an explanatory - // comment isn't mistaken for a real element (which would otherwise - // append a bogus ). A trailing unterminated comment (possible - // after a truncation cut) is stripped to end-of-string too. - var scanText = Regex.Replace(head, @"|$)", ""); - var stack = new Stack(); - bool sawMismatch = false; - foreach (Match m in AnyTagRegex().Matches(scanText)) - { - bool isClose = m.Groups[1].Value == "/"; - bool isSelf = m.Groups[4].Value == "/"; - string name = m.Groups[2].Value; - if (isSelf) continue; - if (isClose) - { - if (stack.Count > 0 && stack.Peek() == name) stack.Pop(); - else sawMismatch = true; - } - else - { - stack.Push(name); - } - } - - // If balanced and not truncated, return original - if (!needsTruncate && stack.Count == 0 && !sawMismatch) return xaml; - - var sb = new System.Text.StringBuilder(head.TrimEnd()); - while (stack.Count > 0) sb.Append("'); - if (needsTruncate) sb.Append("\n"); - return sb.ToString(); - } - - /// Truncate C# code at a brace-balanced boundary. - /// Walks forward tracking depth (skipping strings/chars/comments/verbatim) and - /// prefers the most recent depth=0 cut. When none exists in the prefix, cuts at - /// the last newline and appends synthetic `}` braces equal to the open depth so - /// agents can copy the snippet without the build breaking on unbalanced braces. - private static string TruncateCode(string code, int maxChars, string marker) - { - if (code.Length <= maxChars) return code; - - if (code.Contains('{')) - { - int depth = 0, lastZeroPos = -1, finalDepth = 0; - bool inStr = false, inChr = false, inLine = false, inBlk = false, inVerb = false; - int lastBeforeMax = 0; - for (int i = 0; i < code.Length && i < maxChars; i++) - { - char c = code[i]; char prev = i > 0 ? code[i - 1] : '\0'; - if (inLine) { if (c == '\n') inLine = false; continue; } - if (inBlk) { if (c == '/' && prev == '*') inBlk = false; continue; } - if (inStr) - { - if (inVerb) { if (c == '"' && (i + 1 >= code.Length || code[i + 1] != '"')) { inStr = false; inVerb = false; } else if (c == '"') i++; } - else if (c == '"' && prev != '\\') inStr = false; - continue; - } - if (inChr) { if (c == '\'' && prev != '\\') inChr = false; continue; } - if (c == '/' && i + 1 < code.Length && code[i + 1] == '/') { inLine = true; continue; } - if (c == '/' && i + 1 < code.Length && code[i + 1] == '*') { inBlk = true; continue; } - if (c == '@' && i + 1 < code.Length && code[i + 1] == '"') { inStr = true; inVerb = true; i++; continue; } - if (c == '"') { inStr = true; continue; } - if (c == '\'') { inChr = true; continue; } - if (c == '{') depth++; - else if (c == '}') { depth--; if (depth == 0) lastZeroPos = i + 1; } - lastBeforeMax = i + 1; - finalDepth = depth; - } - if (lastZeroPos > 0) - return code.Substring(0, lastZeroPos).TrimEnd() + "\n" + marker; - int cut1 = code.LastIndexOf('\n', Math.Min(lastBeforeMax, code.Length) - 1); - if (cut1 < 0) cut1 = lastBeforeMax; - var prefix = code.Substring(0, cut1).TrimEnd(); - var closers = finalDepth > 0 ? "\n" + new string('}', finalDepth) : ""; - return prefix + closers + "\n" + marker; - } - - int cut = code.LastIndexOf('\n', maxChars - 1); - if (cut < 0) cut = maxChars; - return code.Substring(0, cut).TrimEnd() + "\n" + marker; - } - - private static string? ExtractInlineCode(string block, string tagName) - { - var pattern = $@"\s*]*>([\s\S]*?)\s*"; - var match = Regex.Match(block, pattern, RegexOptions.IgnoreCase); - if (!match.Success) return null; - - var code = UnescapeXml(match.Groups[1].Value).Trim(); - if (code.Contains("$(")) - { - // C# inline templates with $(VarName) substitutions are bound to live UI - // controls. Replacing with "..." produces literals like `Title = "..."` - // and `Resize(new SizeInt32(..., ...))` that mislead agents into compiling - // them. The code-behind extractor is the right path for C#; if it failed - // (no .xaml.cs or no event/x:Bind/x:Name seeds), surface no csharp at all. - if (tagName == "CSharp") return null; - // For XAML, the placeholder substitution is generally cosmetic (color, size) - // and the surrounding markup is still useful — keep the existing behavior. - code = SubstitutionRegex().Replace(code, "..."); - } - code = CleanGalleryContent(code); - return string.IsNullOrWhiteSpace(code) ? null : code; - } - - private static string CleanGalleryContent(string code) - { - code = SampleMediaRegex().Replace(code, "ms-appx:///Assets/YourImage.png"); - code = GalleryClassRegex().Replace(code, @"x:Class=""YourApp.YourPage"""); - code = SamplePageTypeRegex().Replace(code, "typeof(YourPage)"); - code = SamplePageNameRegex().Replace(code, "YourPage"); - code = Regex.Replace(code, @"using WinUIGallery[^;\n]*;?", "// adapt namespace to your app"); - code = Regex.Replace(code, @"using AppUIBasics[^;\n]*;?", "// adapt namespace to your app"); - code = Regex.Replace(code, @"namespace WinUIGallery[^{;\n]*;?", "namespace YourApp;"); - code = Regex.Replace(code, @"namespace AppUIBasics[^{;\n]*;?", "namespace YourApp;"); - code = Regex.Replace(code, @".*NavigationHelper.*\n?", ""); - - // Clean demo-specific layout attributes (fixed sizes, negative margins, demo handlers). - // Only drop an attribute that sits on its OWN continuation line (no '<' or '>'), so we - // never delete a line that also carries the tag's closing '>' or other markup — which - // would corrupt multi-line open tags in the new SampleDefinition format - // (e.g. `Width="300" Margin="12" Height="68">`). - var lines = code.Split('\n').Where(line => - { - var trimmed = line.Trim(); - if (trimmed.IndexOf('<') >= 0 || trimmed.IndexOf('>') >= 0) return true; - if (Regex.IsMatch(trimmed, @"^(Min|Max)?(Height|Width)=""\d")) return false; - if (Regex.IsMatch(trimmed, @"^Margin=""-")) return false; - if (Regex.IsMatch(trimmed, @"^Loaded=""[^""]*_Loaded""")) return false; - if (Regex.IsMatch(trimmed, @"^SelectedIndex=""\d+""")) return false; - return true; - }); - code = string.Join('\n', lines); - - // Clean substitution placeholders: replace known $(...) or "..." with defaults - code = Regex.Replace(code, @"IsOpen=""(\$\(IsOpen\)|\.\.\.?)""", @"IsOpen=""True"""); - code = Regex.Replace(code, @"Severity=""(\$\(Severity\)|\.\.\.?)""", @"Severity=""Informational"""); - code = SubstitutionRegex().Replace(code, "..."); - - code = Regex.Replace(code, @"\n\s*\n\s*\n", "\n\n"); - return code.Trim(); - } - - private static string UnescapeXml(string s) - { - return s.Replace("<", "<") - .Replace(">", ">") - .Replace("&", "&") - .Replace(""", "\"") - .Replace("'", "'") - .Replace(" ", "\n") - .Replace(" ", "\r"); - } - - /// Tighten whitespace, drop license header + Gallery-internal helper lines. - private static string CompressCSharp(string code) - { - // Strip Gallery's UIHelper.* accessibility helper calls (not portable, agent doesn't have it). - code = Regex.Replace(code, @"^\s*UIHelper\.[^;]+;.*\n?", "", RegexOptions.Multiline); - - // Drop a leading "// C# code-behind" / "// C# Code" label line that some upstream - // SampleDefinition bundles put at the top of their --- c# section (pure noise; the - // real class/method code follows). Only the leading marker is removed, not inline - // explanatory comments that document the sample. - code = Regex.Replace(code, @"^\s*//\s*C#\s*(code-behind|code)\s*\r?\n", "", RegexOptions.IgnoreCase); - - // Strip #region / #endregion preprocessor directives — they're noise and - // can produce CS1038 errors when truncation cuts off the matching half. - code = Regex.Replace(code, @"^\s*#(?:region|endregion)\b.*\n?", "", RegexOptions.Multiline); - - // Drop "// Copyright (c) Microsoft..." + "// Licensed under..." header pair. - if (code.StartsWith("// Copyright")) - { - int nl1 = code.IndexOf('\n'); - if (nl1 > 0) - { - int nl2 = code.IndexOf('\n', nl1 + 1); - if (nl2 > 0 && code.Substring(nl1 + 1, nl2 - nl1 - 1).TrimStart().StartsWith("// Licensed")) - code = code.Substring(nl2 + 1).TrimStart(); - } - } - - // De-indent: turn 4-space indents into 2-space (saves ~12% per line). - code = Regex.Replace(code, @"(?m)^( {4})+", m => new string(' ', m.Length / 2)); - - // Collapse 3+ consecutive newlines into 2. - code = Regex.Replace(code, @"\n[\t ]*\n[\t ]*\n+", "\n\n"); - return code.Trim(); - } - - /// - /// Override Gallery demo code with production-quality snippets where the - /// original is known to mislead agents (e.g., TabView using Frame instead of direct content). - /// - private static void ApplyOverrides(Scenario[] scenarios) - { - foreach (var s in scenarios) - { - if (s.Id == "tabview-1" && s.CSharp != null && s.CSharp.Contains("Frame")) - { - s.CSharp = """ - private void TabView_AddButtonClick(TabView sender, object args) - { - sender.TabItems.Add(CreateNewTab(sender.TabItems.Count)); - } - - private void TabView_TabCloseRequested(TabView sender, TabViewTabCloseRequestedEventArgs args) - { - sender.TabItems.Remove(args.Tab); - } - - private TabViewItem CreateNewTab(int index) - { - TabViewItem newItem = new TabViewItem(); - newItem.Header = $"Document {index}"; - newItem.IconSource = new SymbolIconSource() { Symbol = Symbol.Document }; - newItem.IsClosable = true; - - // Content can be any UIElement — TextBox, Grid, UserControl, etc. - var textBox = new TextBox - { - AcceptsReturn = true, - TextWrapping = TextWrapping.Wrap, - HorizontalAlignment = HorizontalAlignment.Stretch, - VerticalAlignment = VerticalAlignment.Stretch, - BorderThickness = new Thickness(0), - }; - newItem.Content = textBox; - - return newItem; - } - """; - } - } - } - - /// Inject scenarios for controls that have no ControlExample code in the Gallery. - private static Scenario[] InjectMissing(Scenario[] scenarios) - { - var ids = new HashSet(scenarios.Select(s => s.ControlId)); - var injected = new List(scenarios); - - if (!ids.Contains("commandbar")) - { - injected.Add(new Scenario - { - Id = "commandbar-1", - ControlId = "commandbar", - ControlName = "CommandBar", - HeaderText = "Primary and secondary commands", - Xaml = """ - - - - - - - - - - - - """, - CSharp = null - }); - } - - // ItemsRepeater + UniformGridLayout for an image/photo grid is a very common - // need (media galleries, photo organizers) but every upstream UniformGridLayout - // sample in WinUI Gallery happens to demo something else (DataTemplateSelector, - // SelectorBar, connected animation, etc.) so the layout is buried in noise. - // Inject a clean canonical example so agents can copy it directly. - // Pick the next free {controlId}-N suffix so the ID stays consistent with - // the auto-numbered scenarios from the same control. - var nextRepeaterIdx = injected - .Where(s => s.ControlId == "itemsrepeater") - .Select(s => - { - var dash = s.Id.LastIndexOf('-'); - return (dash > 0 && int.TryParse(s.Id[(dash + 1)..], out var n)) ? n : 0; - }) - .DefaultIfEmpty(0) - .Max() + 1; - injected.Add(new Scenario - { - Id = $"itemsrepeater-{nextRepeaterIdx}", - ControlId = "itemsrepeater", - ControlName = "ItemsRepeater", - HeaderText = "Photo gallery: image grid (UniformGridLayout)", - Description = "Canonical pattern for displaying a grid of images/thumbnails: ItemsRepeater + UniformGridLayout, wrapped in a ScrollView for scrolling. Use this instead of GridView+ItemsWrapGrid when you want the modern WinUI 3 collection layout.", - Xaml = """ - - - - - - - - - - - - - - - - """, - CSharp = """ - public sealed partial class PhotoItem - { - public string Thumbnail { get; set; } = ""; - } - - // ItemsSource: - // public ObservableCollection Items { get; } = new(); - """, - Source = "gallery" - }); - - // CommunityToolkit controls now come from toolkit-scenarios.json - // Only CommandBar needs injection (no ControlExample in WinUI Gallery) - - return injected.ToArray(); - } -} - diff --git a/src/tools/winui-search/GalleryProvider.cs b/src/tools/winui-search/GalleryProvider.cs deleted file mode 100644 index 6128eadc..00000000 --- a/src/tools/winui-search/GalleryProvider.cs +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -/// -/// WinUI 3 Gallery scenarios (microsoft/WinUI-Gallery). Parse logic lives -/// in ; this type just wires it into the provider -/// model. Gallery contributes no author keywords. -/// -internal sealed class GalleryProvider : CachedProviderBase -{ - public override string Id => "gallery"; - public override string DisplayName => "Gallery (WinUI 3)"; - - protected override ProviderData LoadEmbedded() - { - var (scenarios, tags) = GalleryFetcher.LoadEmbedded(); - return new ProviderData(scenarios, tags, new()); - } - - protected override async Task FetchAsync() - { - var (scenarios, tags) = await GalleryFetcher.FetchAsync(); - return scenarios.Length > 0 - ? new ProviderData(scenarios, tags, new()) - : ProviderData.Empty; - } -} diff --git a/src/tools/winui-search/Models.cs b/src/tools/winui-search/Models.cs deleted file mode 100644 index 3145ad73..00000000 --- a/src/tools/winui-search/Models.cs +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using System.Text.Json.Serialization; - -[JsonSerializable(typeof(Scenario[]))] -[JsonSerializable(typeof(CorePattern[]))] -[JsonSerializable(typeof(Dictionary))] -[JsonSerializable(typeof(DocLink[]))] -internal partial class JsonContext : JsonSerializerContext { } - -internal sealed class Scenario -{ - [JsonPropertyName("id")] public string Id { get; set; } = ""; - [JsonPropertyName("controlId")] public string ControlId { get; set; } = ""; - [JsonPropertyName("controlName")] public string ControlName { get; set; } = ""; - [JsonPropertyName("headerText")] public string HeaderText { get; set; } = ""; - [JsonPropertyName("xaml")] public string? Xaml { get; set; } - [JsonPropertyName("csharp")] public string? CSharp { get; set; } - /// "gallery" or "toolkit". Drives id prefix and metadata output. - [JsonPropertyName("source")] public string Source { get; set; } = "gallery"; - /// NuGet package required to use this control (toolkit only). - [JsonPropertyName("nugetPackage")] public string? NuGetPackage { get; set; } - /// XAML namespace declarations needed (e.g., xmlns:controls="...") (toolkit only). - [JsonPropertyName("xmlnsImports")] public string[] XmlnsImports { get; set; } = []; - /// Longer description from ControlInfoData.json (Gallery only). - [JsonPropertyName("description")] public string? Description { get; set; } - /// Control-level one-line concept summary. For gallery: ControlInfoData.Subtitle - /// (short, median 68 chars). For toolkit: md frontmatter description. Surfaced in search - /// list as "[gallery] Name — <summary>". - [JsonPropertyName("controlDescription")] public string? ControlDescription { get; set; } - /// Related WinUI 3 controls — names of "see also" alternatives/pairings (Gallery only). - [JsonPropertyName("relatedControls")] public string[] RelatedControls { get; set; } = []; - /// API namespace from ControlInfoData.json (Gallery only). Surfaced in output - /// only when non-default — helps agents pick the right `using`/`xmlns` for long-tail - /// controls in Microsoft.Windows.*, Microsoft.UI.Windowing, etc. Empty when unknown - /// or when the standard Microsoft.UI.Xaml.Controls namespace is enough. - [JsonPropertyName("apiNamespace")] public string? ApiNamespace { get; set; } - /// Official documentation links (API reference, guidelines, etc.) (Gallery only). - [JsonPropertyName("docs")] public DocLink[] Docs { get; set; } = []; -} - -internal sealed class DocLink -{ - [JsonPropertyName("title")] public string Title { get; set; } = ""; - [JsonPropertyName("uri")] public string Uri { get; set; } = ""; -} - -internal sealed class CorePattern -{ - [JsonPropertyName("id")] public string Id { get; set; } = ""; - [JsonPropertyName("scenario")] public string Scenario { get; set; } = ""; - [JsonPropertyName("tags")] public string[] Tags { get; set; } = []; - [JsonPropertyName("description")] public string Description { get; set; } = ""; - [JsonPropertyName("prerequisites")] public string[] Prerequisites { get; set; } = []; - [JsonPropertyName("xaml")] public string? Xaml { get; set; } - [JsonPropertyName("csharp")] public string CSharp { get; set; } = ""; - [JsonPropertyName("notes")] public string[] Notes { get; set; } = []; -} diff --git a/src/tools/winui-search/Notes.cs b/src/tools/winui-search/Notes.cs deleted file mode 100644 index 435ee8f3..00000000 --- a/src/tools/winui-search/Notes.cs +++ /dev/null @@ -1,245 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -internal static class Notes -{ - /// - /// Cross-control family disambiguation. Single source of truth for "when to pick - /// X vs Y vs Z" — referenced by every family member so we don't repeat the same - /// guidance in 3-5 places (and don't drift between control entries). - /// - private static readonly Dictionary FamilyGuide = new() - { - ["Tabs"] = "TabView=closable doc tabs (browser-style); Pivot=static sections (legacy, prefer SelectorBar for new code); SelectorBar=modern Win11 flat selector; Segmented (Toolkit)=2-5 mutually-exclusive short toggles", - ["Toolbars"] = "CommandBar=app-wide toolbar (PrimaryCommands always-visible, SecondaryCommands overflow); TabbedCommandBar (Toolkit)=Office ribbon-style with multiple tabs of AppBarButton groups", - ["Popups"] = "ContentDialog=modal blocking decision; Flyout=inline contextual UI; MenuFlyout=context/dropdown menu; TeachingTip=non-blocking targeted hint; InfoBar=persistent inline status (Severity Info/Success/Warning/Error); AppNotification=system-wide toast", - ["Collections"] = "ListView=vertical text rows; GridView=image/card grid; ItemsView=modern flexible (LinedFlow/Stack/UniformGrid layouts; replaces ListView/GridView for new code); ItemsRepeater=fully custom layout (no selection, no scroll, wrap in ScrollViewer); TreeView=hierarchy", - ["TextInput"] = "TextBox=plain; RichEditBox=formatted (bold/italic/lists); AutoSuggestBox=search-as-you-type; ComboBox=closed-list dropdown; TokenizingTextBox (Toolkit)=removable chip/tag pills; RichSuggestBox (Toolkit)=@mention/#hashtag inline tokens", - ["Numeric"] = "NumberBox=precise typed value with validation; Slider=visual single-value range; RangeSelector (Toolkit)=two-handle min/max range", - ["Navigation"] = "NavigationView=app sidebar with built-in UX (SelectionChanged + Frame); SplitView=low-level pane primitive (build the list yourself); BreadcrumbBar=path-style trail (ItemsSource only)", - ["Settings"] = "SettingsCard=single setting row (Win11 standard); SettingsExpander=group of related cards under one collapsible header", - ["Sizers"] = "GridSplitter (Toolkit)=column/row resize within a Grid; ContentSizer (Toolkit)=single-axis resize of a sibling element outside a Grid", - ["LayoutPanels"] = "StackPanel=linear; Grid=row/column with sizes; Canvas=absolute positioning; DockPanel (Toolkit)=Dock attached property + LastChildFill; WrapPanel (Toolkit)=row/col then wrap; UniformGrid (Toolkit)=equal cells; StaggeredPanel (Toolkit)=Pinterest masonry; ItemsRepeater Layout=virtualized variants (StackLayout/UniformGridLayout/WrapLayout/StaggeredLayout)", - ["ColorPickers"] = "Microsoft.UI.Xaml.Controls.ColorPicker=basic, dependency-free; CommunityToolkit.WinUI.Controls.ColorPicker=adds ShowAccentColors + IsColorPaletteVisible swatches + IsColorSpectrumVisible toggle; ColorPickerButton (Toolkit)=compact button+flyout wrapper", - }; - - /// Maps each control name to its family key. - private static readonly Dictionary ControlToFamily = new() - { - ["TabView"] = "Tabs", - ["Pivot"] = "Tabs", - ["SelectorBar"] = "Tabs", - ["Segmented"] = "Tabs", - ["CommandBar"] = "Toolbars", - ["TabbedCommandBar"] = "Toolbars", - ["ContentDialog"] = "Popups", - ["Flyout"] = "Popups", - ["MenuFlyout"] = "Popups", - ["TeachingTip"] = "Popups", - ["InfoBar"] = "Popups", - ["AppNotification"] = "Popups", - ["ListView"] = "Collections", - ["GridView"] = "Collections", - ["ItemsView"] = "Collections", - ["ItemsRepeater"] = "Collections", - ["TreeView"] = "Collections", - ["TextBox"] = "TextInput", - ["RichEditBox"] = "TextInput", - ["AutoSuggestBox"] = "TextInput", - ["ComboBox"] = "TextInput", - ["TokenizingTextBox"] = "TextInput", - ["RichSuggestBox"] = "TextInput", - ["NumberBox"] = "Numeric", - ["Slider"] = "Numeric", - ["RangeSelector"] = "Numeric", - ["NavigationView"] = "Navigation", - ["SplitView"] = "Navigation", - ["BreadcrumbBar"] = "Navigation", - ["SettingsCard"] = "Settings", - ["SettingsExpander"] = "Settings", - ["GridSplitter"] = "Sizers", - ["ContentSizer"] = "Sizers", - ["DockPanel"] = "LayoutPanels", - ["WrapPanel"] = "LayoutPanels", - ["UniformGrid"] = "LayoutPanels", - ["StaggeredPanel"] = "LayoutPanels", - ["ColorPicker"] = "ColorPickers", - ["ColorPickerButton"] = "ColorPickers", - }; - - /// - /// Per-control pitfalls. ONLY control-specific guidance — cross-control "use X vs Y" - /// disambiguation lives in FamilyGuide above. - /// - private static readonly Dictionary KnownPitfalls = new() - { - // ─── Data binding (covers x:Bind / Binding / DataTemplate / x:DataType) ─── - ["Binding"] = [ - "x:Bind OneWay/TwoWay needs INotifyPropertyChanged on source. Easiest: inherit ViewModel from ObservableObject (CommunityToolkit.Mvvm), mark fields [ObservableProperty], collections ObservableCollection. Else WMC1506 + UI silently never updates.", - "x:Bind enforces target type at compile time. UIElement-typed prop bound to FrameworkElement-typed (e.g. TeachingTip.Target) → WMC1121. Bind to x:Name'd element, or expose prop as the more specific type." - ], - ["Templates"] = [ - "Every with x:Bind MUST set x:DataType — without it x:Bind silently falls back to {Binding} (no IntelliSense, no errors).", - "x:Bind in a DataTemplate references the x:DataType item, NOT the parent Page's ViewModel. Use ElementName or RelativeSource to escape." - ], - - // ─── Tabs ─── - ["TabView"] = [ - "TabCloseRequested provides args.Tab — don't construct TabViewTabCloseRequestedEventArgs manually.", - "IsClosable on individual TabViewItem controls which tabs can be closed.", - "Set VerticalAlignment=\"Stretch\" on TabView so content fills available space.", - "TabViewItem.Content can be ANY UIElement (TextBox, Grid, UserControl); use Frame only for page navigation." - ], - - // ─── Collections ─── - ["TreeView"] = [ - "Don't use C# record/class as TreeViewNode.Content with x:Bind — WinRT can't roundtrip custom managed types through IInspectable.", - "Data-bound trees: ItemsSource → DataTemplate with TreeViewItem.ItemsSource={x:Bind Children}.", - "TreeViewItemTemplateSelector doesn't exist in WinUI 3 — use one DataTemplate with x:Bind, or ItemContainerStyleSelector + ItemTemplate.", - "TreeViewItem has no .Icon — put Image/FontIcon/SymbolIcon as first child of horizontal StackPanel inside DataTemplate.", - "File-explorer sidebar: ObservableCollection with Children:ObservableCollection; root DataTemplate binds ItemsSource={x:Bind Children}." - ], - ["ListView"] = [ - "Don't wrap ListView in ScrollViewer — breaks virtualization.", - "Prefer x:Bind in DataTemplates over Binding for performance.", - "WinUI 3 has no DataGrid. For tables: ListView with Grid-based ItemTemplate (columns) + separate header Grid above; CommunityToolkit GridSplitter for resizable cols.", - "Sortable columns: handle header Click events, re-sort ObservableCollection or use AdvancedCollectionView (Toolkit)." - ], - ["GridView"] = [ - "GridView has no built-in column resize — for spreadsheet UI use ListView + Grid ItemTemplate + GridSplitter." - ], - ["ItemsRepeater"] = [ - "ItemsRepeater is a layout primitive — NO selection, NO scrolling. Wrap in ScrollViewer.", - "x:Bind OneWay binding needs INPC source — see Binding entry." - ], - ["ItemsView"] = [ - "x:Bind OneWay binding needs INPC source — see Binding entry." - ], - - // ─── Popups ─── - ["ContentDialog"] = [ - "Set XamlRoot = Content.XamlRoot before ShowAsync() in WinUI 3 desktop apps.", - "Save/discard/cancel flows: provide all three of PrimaryButtonText, SecondaryButtonText, CloseButtonText." - ], - ["Flyout"] = [ - "Flyout auto-dismisses on outside click; ShowMode='Standard' for explicit dismiss.", - "Attach via FlyoutBase.AttachedFlyout or Button.Flyout." - ], - ["MenuFlyout"] = [ - "Items: MenuFlyoutItem / ToggleMenuFlyoutItem / MenuFlyoutSubItem." - ], - ["TeachingTip"] = [ - "Without a Target, TeachingTip shows as a banner instead of near a control.", - "TeachingTip.Target is FrameworkElement, NOT UIElement. x:Bind from UIElement-typed prop → WMC1121. Bind to x:Name'd element or expose as FrameworkElement (Image/TextBlock/Button work)." - ], - ["InfoBar"] = [ - "InfoBar auto-closes on user-click — bind IsOpen TwoWay." - ], - - // ─── Navigation ─── - ["NavigationView"] = [ - "MenuItems for static nav; MenuItemsSource for data-bound.", - "Handle SelectionChanged, NOT ItemInvoked, for reliable navigation." - ], - ["SplitView"] = [ - "DisplayMode='Inline'=always-visible pane; 'CompactInline'=icon strip; 'Overlay'=hamburger flyout." - ], - ["BreadcrumbBar"] = [ - "BreadcrumbBar has no Items property — only ItemsSource." - ], - - // ─── Numeric ─── - ["NumberBox"] = [ - "NumberBox.Value is double — Math.Round for integer scenarios.", - "SpinButtonPlacementMode='Inline' shows +/- buttons.", - "ValidationMode='InvalidInputOverwritten' auto-corrects invalid input." - ], - - // ─── Text input ─── - ["AutoSuggestBox"] = [ - "Filter suggestions in TextChanged when reason==UserInput, NOT in SuggestionChosen." - ], - ["RichEditBox"] = [ - "Content access: Document.GetText/SetText with TextGetOptions/TextSetOptions." - ], - ["RichSuggestBox"] = [ - "Prefixes property defines trigger chars (e.g. '@#'); inline tokens tracked in Tokens collection." - ], - ["ComboBox"] = [ - "Bind SelectedItem/SelectedIndex, NOT SelectedValue (unless SelectedValuePath is also set)." - ], - - // ─── Settings ─── - ["SettingsCard"] = [ - "Don't build settings UI with plain StackPanel+ToggleSwitch — use SettingsCard (Win11 standard).", - "IsClickEnabled=True turns the card into a button (e.g. for nav to detail page)." - ], - ["SettingsExpander"] = [ - "Items collection holds child SettingsCards under one collapsible header." - ], - - // ─── Sizers ─── - ["GridSplitter"] = [ - "Place in an Auto-width column between two content columns.", - "ResizeBehavior='BasedOnAlignment' for between-columns; ResizeDirection='Auto' infers." - ], - - // ─── Layout ─── - ["DockPanel"] = [ - "LastChildFill=True makes last child fill remaining space.", - "Dock attached property on children: Top/Bottom/Left/Right." - ], - ["WrapPanel"] = [ - "For virtualized wrap: use WrapLayout (Toolkit) inside ItemsRepeater." - ], - ["UniformGrid"] = [ - "All cells equal-sized; specify Rows OR Columns, the other auto-calculates." - ], - ["StaggeredPanel"] = [ - "For virtualized masonry: StaggeredLayout (Toolkit) inside ItemsRepeater." - ], - - // ─── Toolbars ─── - ["CommandBar"] = [ - "PrimaryCommands=always-visible; SecondaryCommands=overflow menu." - ], - - // ─── Other commonly-confused controls ─── - ["Border"] = [ - "Border has no .Cursor in WinUI 3 (WPF holdover). Override ProtectedCursor on a custom UserControl hosting the Border, or set ProtectedCursor on nearest parent FrameworkElement deriving from Control.", - "Clickable border: wrap with Button Style=\"{StaticResource TransparentButtonStyle}\" — don't catch pointer events on Border directly." - ], - ["WebView2"] = [ - "Always call EnsureCoreWebView2Async() before using CoreWebView2 properties.", - "NavigateToString(html) loads inline HTML without a URL." - ], - ["Expander"] = [ - "Expander.IsExpanded TwoWay binding needs explicit x:Bind Mode=TwoWay (default doesn't work)." - ], - ["MenuBar"] = [ - "Place MenuBar in title bar or at top of window for standard layout." - ], - ["AdvancedCollectionView"] = [ - "Wrap ObservableCollection with AdvancedCollectionView for sorting/filtering/grouping without modifying source.", - "Call RefreshFilter() after changing the Filter predicate." - ], - }; - - /// Result payload combining specific pitfalls with the optional family guide. - public readonly record struct NotesPayload(string[] Pitfalls, string? FamilyName, string? FamilyGuide); - - public static NotesPayload Get(string controlName) - { - var pitfalls = KnownPitfalls.TryGetValue(controlName, out var p) ? p : Array.Empty(); - string? famName = null, famGuide = null; - if (ControlToFamily.TryGetValue(controlName, out var fk) && FamilyGuide.TryGetValue(fk, out var guide)) - { - famName = fk; - famGuide = guide; - } - return new NotesPayload(pitfalls, famName, famGuide); - } - - /// Backward-compat: just the pitfalls (no family). - public static string[] GetNotes(string controlName) => Get(controlName).Pitfalls; -} \ No newline at end of file diff --git a/src/tools/winui-search/Program.cs b/src/tools/winui-search/Program.cs deleted file mode 100644 index 1a65259f..00000000 --- a/src/tools/winui-search/Program.cs +++ /dev/null @@ -1,441 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -internal class Program -{ - private static async Task Main(string[] args) - { - if (args.Length == 0) - { - PrintUsage(); - return 1; - } - - var command = args[0].ToLowerInvariant(); - - // Force-refresh on update: clear cache, then pull fresh data from GitHub. - // Hot path commands (search/get/list) never fetch from GitHub — they hit cache - // or embedded fallback for fast, reliable response. They DO opportunistically - // spawn a background `update --background` child if the cache is >7 days old. - if (command == "update") - { - bool isBackground = BackgroundUpdater.IsBackgroundInvocation(args); - BackgroundUpdater.DebugLogPublic($"update entered (isBackground={isBackground})"); - var refreshResults = new List<(string id, bool ok)>(); - // Foreground update participates in the same lock protocol as the - // background updater so a hot-path-spawned `update --background` child - // doesn't write the same cache files concurrently with us. Background - // invocations already hold the lock (acquired by TryKickoffIfStale before - // spawn), so we only acquire here for the foreground path. - bool acquiredForeground = false; - if (!isBackground) - { - acquiredForeground = BackgroundUpdater.TryAcquireLock(); - if (!acquiredForeground) - { - Console.Error.WriteLine( - "Note: a background refresh appears to be in progress. " + - "Proceeding with foreground update anyway (atomic writes prevent corruption)."); - } - } - try - { - if (!isBackground) ForceFetch(); - foreach (var provider in ProviderRegistry.All) - { - var label = char.ToUpperInvariant(provider.Id[0]) + provider.Id.Substring(1); - try - { - await provider.RefreshFromGitHubAsync(); - refreshResults.Add((provider.Id, true)); - BackgroundUpdater.DebugLogPublic($"{label} refresh OK"); - } - catch (Exception e) - { - refreshResults.Add((provider.Id, false)); - BackgroundUpdater.DebugLogPublic($"{label} refresh failed: {e.GetType().Name}: {e.Message}"); - if (!isBackground) Console.Error.WriteLine($"{label} refresh failed: {e.Message}"); - } - } - if (!isBackground) - { - if (refreshResults.All(r => r.ok)) - { - Console.WriteLine("Cache refreshed from GitHub."); - } - else if (refreshResults.Any(r => r.ok)) - { - var summary = string.Join(", ", refreshResults.Select(r => $"{r.id}={(r.ok ? "OK" : "FAILED")}")); - Console.WriteLine($"Cache partially refreshed: {summary} (failed sources fall back to embedded snapshots)"); - } - else - { - Console.WriteLine("Cache refresh failed (search still works via embedded snapshots)."); - } - } - } - finally - { - if (refreshResults.Count > 0 && refreshResults.All(r => r.ok)) BackgroundUpdater.MarkSuccess(); - else BackgroundUpdater.MarkAttempt(); - // Release the lock we own — for background invocations that's the lock - // TryKickoffIfStale acquired before spawning us; for foreground that's - // the lock we acquired above (only release if we successfully acquired). - if (isBackground || acquiredForeground) BackgroundUpdater.ReleaseLock(); - } - return (refreshResults.Count > 0 && refreshResults.All(r => r.ok)) ? 0 : 1; - } - - // Load every registered provider and merge into the engine's inputs. Tag - // and keyword dictionaries are namespaced by provider id ("{source}:{controlId}") - // so colliding controlIds (gallery + toolkit both expose `colorpicker`, - // `wrappanel`) don't overwrite each other — SearchEngine looks them up by the - // same composite key it uses for scenario grouping. - var allScenarios = new List(); - var allTags = new Dictionary(StringComparer.OrdinalIgnoreCase); - var allKeywords = new Dictionary(StringComparer.OrdinalIgnoreCase); - foreach (var provider in ProviderRegistry.All) - { - var data = provider.Load(); - allScenarios.AddRange(data.Scenarios); - foreach (var kv in data.Tags) allTags[$"{provider.Id}:{kv.Key}"] = kv.Value; - foreach (var kv in data.Keywords) allKeywords[$"{provider.Id}:{kv.Key}"] = kv.Value; - } - - var engine = new SearchEngine( - allScenarios.ToArray(), - DataLoader.LoadCorePatterns(), - allTags, - allKeywords - ); - - return command switch - { - "search" => RunWithBackgroundRefresh(() => RunSearch(engine, args.Skip(1).ToArray())), - "get" => RunWithBackgroundRefresh(() => RunGet(engine, args.Skip(1).ToArray())), - "list" => RunWithBackgroundRefresh(() => RunList(engine, args.Skip(1).ToArray())), - "debug" => RunWithBackgroundRefresh(() => RunDebug(engine, args.Skip(1).ToArray())), - _ => PrintUsage() - }; - } - - /// Run a hot-path command, then opportunistically spawn a background - /// cache refresh if the GitHub cache is stale (>7d). The spawn is fire-and-forget; - /// the user has already received their answer by the time it kicks off. - private static int RunWithBackgroundRefresh(Func action) - { - var exit = action(); - BackgroundUpdater.TryKickoffIfStale(); - return exit; - } - - private static int RunDebug(SearchEngine engine, string[] args) - { - var query = string.Join(" ", args); - Console.WriteLine($"Query: \"{query}\""); - Console.WriteLine($"Preprocessed: \"{Synonyms.Preprocess(query)}\""); - var tokens = BM25.Tokenize(Synonyms.Preprocess(query)); - Console.WriteLine($"Tokens: [{string.Join(", ", tokens)}]"); - Console.WriteLine($"Expanded: [{string.Join(", ", Synonyms.Expand(tokens))}]"); - Console.WriteLine(); - var groups = engine.SearchGrouped(query, maxControls: 20, maxScenariosPerControl: 1, applyFloor: false); - Console.WriteLine($"Top {groups.Count} groups (no floor):"); - foreach (var g in groups) - { - var boostMark = g.HasNameBoost ? "★" : " "; - Console.WriteLine($" {boostMark} {g.Score,7:F3} [{g.Source}] {g.ControlName} ({g.Scenarios[0].Id})"); - } - return 0; - } - - private static int RunSearch(SearchEngine engine, string[] args) - { - int max = 3; - var queries = new List(); - string? sourceFilter = null; - - for (int i = 0; i < args.Length; i++) - { - if (args[i] == "--max" && i + 1 < args.Length) - { - int.TryParse(args[++i], out max); - } - else if (args[i] == "--source" && i + 1 < args.Length) - { - var raw = args[++i]; - sourceFilter = raw.ToLowerInvariant(); - if (!ProviderRegistry.IsValidSourceFilter(sourceFilter)) - { - Console.Error.WriteLine($"--source must be one of: {string.Join(", ", ProviderRegistry.SourceFilterValues)} (got: {raw})"); - return 1; - } - } - else if (!args[i].StartsWith('-')) - { - queries.Add(args[i]); - } - } - - if (queries.Count == 0) - { - Console.Error.WriteLine("Usage: winui-search search \"\" [\"\" ...] [--max N] [--source gallery|toolkit|core]"); - Console.Error.WriteLine(" Pass each query as a SEPARATE quoted argument to batch them in one call."); - return 1; - } - - // Single query: legacy behaviour (treat all positional args as one phrase if just one was passed) - if (queries.Count == 1) - { - return EmitSearch(engine, queries[0], max, header: false, sourceFilter: sourceFilter); - } - - // Batch: emit each query under its own header. - // NOTE: do NOT emit blank separator lines anywhere in this output — the - // Copilot CLI tool-result capture collapses runs of blank lines, which would - // glue "### Query N" headers onto the previous query's last row. Single - // newlines (one per logical line) survive intact and keep markers parseable. - var batchSuffix = sourceFilter != null ? $" (--source {sourceFilter})" : ""; - Console.WriteLine($"Batch search: {queries.Count} queries{batchSuffix}"); - // Track control IDs already shown in this batch. When a later query would - // re-surface the same control with a noticeably weaker score, suppress it - // and emit a one-line back-reference instead — saves tokens AND signals to - // the agent that they already have this info. - var shownControls = new Dictionary(StringComparer.OrdinalIgnoreCase); - int rc = 0; - for (int i = 0; i < queries.Count; i++) - { - Console.WriteLine($"### Query {i + 1}: \"{queries[i]}\""); - int qrc = EmitSearch(engine, queries[i], max, header: true, queryIndex: i + 1, shownControls: shownControls, sourceFilter: sourceFilter); - if (qrc != 0) rc = qrc; - } - Console.WriteLine("To get full code, pass one or more IDs to: winui-search get [ ...]"); - return rc; - } - - private static int EmitSearch( - SearchEngine engine, string query, int max, bool header, - int queryIndex = 0, - Dictionary? shownControls = null, - string? sourceFilter = null) - { - var groups = engine.SearchGrouped(query, maxControls: max, maxScenariosPerControl: 3, sourceFilter: sourceFilter); - if (groups.Count == 0) - { - var noMatchSuffix = sourceFilter != null ? $" (--source {sourceFilter})" : ""; - Console.WriteLine($"No patterns found for: \"{query}\"{noMatchSuffix}"); - return 0; - } - if (!header) Console.WriteLine($"Found {groups.Count} matches for \"{query}\":"); - foreach (var g in groups) - { - // Batch-level dedup: if this control already appeared in a previous query - // and the current query's score isn't materially higher (≥1.3×), emit only - // a back-reference. This handles the SettingsCard/SettingsExpander overlap - // and similar agent-side query duplication. - var dedupKey = g.Source == "core" - ? $"core:{g.Scenarios[0].Id}" - : $"{g.Source}:{g.ControlName}"; - if (shownControls != null - && shownControls.TryGetValue(dedupKey, out var prev) - && prev.queryIndex != queryIndex - && g.Score < prev.topScore * 1.3) - { - Console.WriteLine($" [{g.Source}] {g.ControlName} → see Query {prev.queryIndex}"); - continue; - } - if (shownControls != null && !shownControls.ContainsKey(dedupKey)) - shownControls[dedupKey] = (queryIndex, g.Score); - - // Header line: e.g. "[gallery] MenuFlyout (7 scenarios)" / "[core]" - if (g.Source == "core") - { - // Core patterns are single-row; flat output with no group header. - var row = g.Scenarios[0]; - Console.WriteLine($" {row.Id}: {CompressHeader(row.Header, controlName: "")}"); - continue; - } - - // Compact control header: "[source] Name — " (when available). - // Subtitle (median 68 chars) is short enough to keep tokens reasonable while - // giving the agent a one-liner so it can decide whether to drill into `get`. - // The earlier scenario-count summary ("showing top 3 of 8") stays dropped — - // low information density per token. - var ctrlSummary = !string.IsNullOrEmpty(g.ControlDescription) - ? $" — {g.ControlDescription}" - : ""; - Console.WriteLine($" [{g.Source}] {g.ControlName}{ctrlSummary}"); - foreach (var row in g.Scenarios) - { - // Compact: ":
" — saves ~10-15 chars/row vs. fixed-width padding, - // and the colon stays scannable for both humans and agents. - var compactHeader = CompressHeader(row.Header, g.ControlName); - var rowDesc = !string.IsNullOrEmpty(row.Description) && row.Description != g.ControlDescription - ? $" — {row.Description}" - : ""; - Console.WriteLine($" {row.Id}: {compactHeader}{rowDesc}"); - } - } - if (!header) Console.WriteLine("To get full code: winui-search get [ ...]"); - return 0; - } - - /// - /// Trim filler from a scenario header at display time. Cheap, deterministic, - /// reversible (full text still in cache). Specifically: - /// • Drop leading article ("A "/"An "/"The "). - /// • Drop trailing " by <ControlName>" / " using <ControlName>" — the - /// control name is already shown on the group header above. - /// • Replace "with support for" → "supports". - /// Saves ~10–15 chars per row across a typical search result. - /// - private static string CompressHeader(string h, string controlName) - { - if (string.IsNullOrEmpty(h)) return h; - - // Leading article — "A "/"An "/"The " at the very start. We don't require the - // next char to be uppercase because some headers are "A basic …" (lowercase b) - // and we still want the article gone. False-positive risk is negligible — - // no real header begins with "A "+single-letter token. - if (h.StartsWith("A ", StringComparison.Ordinal)) h = h[2..]; - else if (h.StartsWith("An ", StringComparison.Ordinal)) h = h[3..]; - else if (h.StartsWith("The ", StringComparison.Ordinal)) h = h[4..]; - - if (!string.IsNullOrEmpty(controlName)) - { - var byPattern = " by " + controlName; - var usingPattern = " using " + controlName; - if (h.EndsWith(byPattern, StringComparison.OrdinalIgnoreCase)) - h = h[..^byPattern.Length]; - else if (h.EndsWith(usingPattern, StringComparison.OrdinalIgnoreCase)) - h = h[..^usingPattern.Length]; - } - - h = System.Text.RegularExpressions.Regex.Replace( - h, @"\bwith support for\b", "supports", - System.Text.RegularExpressions.RegexOptions.IgnoreCase); - - return h.TrimEnd(); - } - - private static int RunGet(SearchEngine engine, string[] args) - { - if (args.Length == 0) - { - Console.Error.WriteLine("Usage: winui-search get [ ...]"); - Console.Error.WriteLine(" Pass multiple ids to batch them in one call."); - return 1; - } - - // Single id: print directly (no separator), preserve legacy output - if (args.Length == 1) - { - var (formatted, found) = engine.GetPattern(args[0]); - Console.WriteLine(formatted); - return found ? 0 : 1; - } - - // Batch: print each pattern with a clear separator and surface any not-found ids. - // The separator is just "---" on its own line — surrounding blank lines would be - // collapsed by the Copilot CLI tool-result capture (gluing it to neighboring - // content), so we emit the separator alone. - bool anyMissing = false; - for (int i = 0; i < args.Length; i++) - { - if (i > 0) - { - Console.WriteLine("---"); - } - var (formatted, found) = engine.GetPattern(args[i]); - Console.WriteLine(formatted); - if (!found) anyMissing = true; - } - return anyMissing ? 1 : 0; - } - - private static int RunList(SearchEngine engine, string[] args) - { - string? sourceFilter = null; - for (int i = 0; i < args.Length; i++) - { - if (args[i] == "--source" && i + 1 < args.Length) - { - var raw = args[++i]; - sourceFilter = raw.ToLowerInvariant(); - if (!ProviderRegistry.IsValidSourceFilter(sourceFilter)) - { - Console.Error.WriteLine($"--source must be one of: {string.Join(", ", ProviderRegistry.SourceFilterValues)} (got: {raw})"); - return 1; - } - } - } - - Console.WriteLine($"Available patterns{(sourceFilter != null ? $" (--source {sourceFilter})" : "")}:"); - Console.WriteLine(); - - string? lastType = null; - foreach (var (id, scenario) in engine.ListAll()) - { - string type; - string source; - var provider = ProviderRegistry.ForScenarioId(id); - if (provider != null) { type = provider.DisplayName; source = provider.Id; } - else { type = "Core platform patterns"; source = "core"; } - - if (sourceFilter != null && source != sourceFilter) continue; - - if (type != lastType) - { - if (lastType != null) Console.WriteLine(); - Console.WriteLine($"## {type}"); - lastType = type; - } - Console.WriteLine($" - {id}: {scenario}"); - } - return 0; - } - - private static void ForceFetch() - { - // Delete only the per-source data subdirectories. Crucially, do NOT touch - // the cache root, because BackgroundUpdater stores its coordination files - // there (update.lock, last-github-update.txt, last-github-attempt.txt, - // background.log). A recursive delete of the root would wipe the lock file - // we may currently hold and break the single-writer guarantee against an - // in-flight background updater. - var cacheRoot = Path.Combine( - Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), - "winui-search", "cache"); - foreach (var sub in ProviderRegistry.All.Select(p => p.Id)) - { - var subDir = Path.Combine(cacheRoot, sub); - if (Directory.Exists(subDir)) - { - try { Directory.Delete(subDir, recursive: true); } catch { } - } - } - } - - private static int PrintUsage() - { - Console.WriteLine("winui-search - WinUI 3 control pattern search"); - Console.WriteLine(); - Console.WriteLine("Commands:"); - Console.WriteLine(" search \"\" [\"\" ...] [--max N] [--source S] Search controls (batch one focused query per feature)"); - Console.WriteLine(" get [ ...] Get full XAML + C# (batch up to 3 IDs per call)"); - Console.WriteLine(" list [--source S] List all available patterns"); - Console.WriteLine(" debug \"\" Diagnostic dump: tokens, synonym expansion, top matches (no score floor)"); - Console.WriteLine(" update Force refresh from GitHub (clears cache; auto-runs in background when stale)"); - Console.WriteLine(); - Console.WriteLine(" --source S Restrict to one of: gallery, toolkit, reactor, core (applies to search + list)"); - Console.WriteLine(); - Console.WriteLine("Examples:"); - Console.WriteLine(" winui-search search \"tabbed document interface\" \"settings card\" \"info bar status\""); - Console.WriteLine(" winui-search search \"file picker\" --source core"); - Console.WriteLine(" winui-search list --source toolkit"); - Console.WriteLine(" winui-search get gallery-tabview-1 toolkit-settingscard-9 gallery-infobar-1"); - Console.WriteLine(" winui-search get jumplist-recent-files"); - Console.WriteLine(" winui-search debug \"settings card with toggle\""); - return 1; - } -} - diff --git a/src/tools/winui-search/README.md b/src/tools/winui-search/README.md deleted file mode 100644 index dd8ed0c7..00000000 --- a/src/tools/winui-search/README.md +++ /dev/null @@ -1,196 +0,0 @@ -# winui-search — WinUI 3 Gallery, Community Toolkit & Reactor Scenario Search - -A native-AOT CLI that searches for sample scenarios across three WinUI 3 reference -codebases ([WinUI Gallery](https://github.com/microsoft/WinUI-Gallery), the -[Windows Community Toolkit](https://github.com/CommunityToolkit/Windows), and -[microsoft-ui-reactor](https://github.com/microsoft/microsoft-ui-reactor)) plus a -small curated catalog of core WinUI 3 patterns. Designed to be invoked by the -`winui-design` and `winui-dev-workflow` skills so a Copilot agent can answer -"what's the canonical WinUI sample for X?" without reading hundreds of XAML -files at runtime. - -## What it indexes - -| Source | How it's loaded | -|---|---| -| WinUI Gallery samples | Embedded JSON snapshot baked into the exe at build time, refreshable on demand via `winui-search update` (which re-fetches from `microsoft/WinUI-Gallery@main`). | -| Community Toolkit samples | Same pattern — embedded snapshot + on-demand GitHub fetch from `CommunityToolkit/Windows@main`. C# samples have platform `#if WINAPPSDK / #else / #endif` folded so emitted code compiles cleanly against WinAppSDK. | -| Reactor samples | Embedded snapshot + on-demand fetch of `microsoft/microsoft-ui-reactor@main`'s purpose-built `reactor-search-index.json`. C#-only declarative WinUI (no XAML); the 4 controls with control-level `usings` get them folded into each snippet. Curated per-control keywords are served verbatim as the enrichment tag field. | -| Toolkit author keywords | `Data/toolkit-keywords.json` — hand-picked terms from each sample's `.md` frontmatter `keywords:` list, surfaced as a higher-weighted BM25 field separate from auto-extracted tags. | -| Core WinUI 3 patterns | Hand-curated `Data/core-patterns.json` baked in. Used for foundational layouts (NavigationView, MVVM scaffolds, etc.) where pulling a Gallery scenario is overkill. | -| Tag dictionaries | `Data/gallery-tags.json` / `Data/toolkit-tags.json` / `Data/reactor-tags.json`, also embedded — used by the BM25 scoring to bias results toward category matches. | - -The on-demand `update` mode does live `https://raw.githubusercontent.com` fetches -to refresh the cached payloads. Snapshots ship with the exe so the tool works -fully offline; `update` is opt-in. - -> **Same-team caveat.** Both WinUI Gallery and Community Toolkit are owned by -> the same Microsoft team that ships this repo, so the embedded data isn't -> third-party vendoring in the legal sense — but it does still drift, and the -> `update` mode + the long-term plan in launch tracker §10.3 cover the -> cron-regenerate option. - -For a deeper breakdown of every input — which GitHub paths are scraped, how -tags/keywords are derived, and how each `Data\*.json` file is regenerated — -see [`DATA_SOURCES.md`](DATA_SOURCES.md). - -## Building - -Requires the .NET 10 SDK. From the repo root: - -```powershell -# Plain build (faster iteration; no AOT) -dotnet build src/tools/winui-search/winui-search.csproj -c Release - -# Native-AOT publish + deploy to src/skills/winui-search/winui-search.exe -.\scripts\build-search.ps1 - -# Cross-publish for ARM64 from an x64 host -.\scripts\build-search.ps1 -Runtime win-arm64 - -# Build only, don't deploy to the skill folder -.\scripts\build-search.ps1 -SkipPublish -``` - -`build-search.ps1` produces a self-contained ~8 MB single-file `winui-search.exe` -under `src/tools/winui-search/bin/Release/net10.0//publish/` and copies it -into `src/skills/winui-search/winui-search.exe` (currently distributed via the -`winui-search` skill, which `winui-design` and `winui-dev-workflow` depend on). - -For a one-shot rebuild of all three tools (analyzer DLL refresh + AOT exes for -host arch), use [`scripts/build-tools.ps1`](../../../scripts/build-tools.ps1) -from the repo root. - -## Architecture - -* `Program.cs` — entry point, command parsing, opportunistic background-refresh - hook on hot-path commands. -* `DataLoader.cs` — loads the embedded JSON snapshots into memory at startup. -* `SearchProvider.cs` — the `ISearchProvider` abstraction, `CachedProviderBase` - (shared cache protocol: schema-version + 7-day TTL + atomic writes + embedded - fallback), and `ProviderRegistry` — the single place a new source is registered. -* `GalleryProvider.cs` / `ToolkitProvider.cs` / `ReactorProvider.cs` — the three - built-in providers (identity + wiring), delegating parse logic to their fetchers. -* `GalleryFetcher.cs` / `ToolkitFetcher.cs` / `ReactorFetcher.cs` — `update`-mode - network code that re-pulls snapshots from GitHub (exposed as `LoadEmbedded()` + - `FetchAsync()` for their providers). `ToolkitFetcher` also folds platform `#if` - blocks (`#if WINAPPSDK / #else / #endif`) so emitted samples are clean WinAppSDK - code without UWP/Uno preprocessor noise. `ReactorFetcher` maps the Reactor team's - purpose-built `reactor-search-index.json` (C#-only, kept verbatim). -* `BackgroundUpdater.cs` — stale-while-revalidate refresher: hot-path commands - spawn a detached `winui-search update --background` child if the GitHub cache - is older than 7 days. Concurrency-safe (atomic `update.lock`, 10-min TTL, - 1-hour failure backoff). See "Background updates" below. -* `CacheVersion.cs` — single source of truth for cache schema versioning. Both - fetchers stamp `CacheVersion.Current` into `schema-version.txt`; mismatched - caches are discarded on read so embedded JSON wins until the next refresh. -* `SearchEngine.cs` + `BM25.cs` — BM25 scoring with stop-word filtering - (`StopWords.cs`) and synonym expansion (`Synonyms.cs`). -* `Notes.cs` — embeds extra context strings appended to result snippets when - the agent benefits from a hint (e.g. "this scenario lives under - `Samples/CommandBar/CommandBarPage.xaml`, but the canonical control template - is in `CommonStyles/CommandBar.xaml` — read both"). -* `Models.cs` — the `Scenario` / `Tag` POCOs the search engine operates on. - -## Usage - -```text -winui-search search [ ...] [--max N] [--source S] - Search for control patterns by description. Multiple queries are batched - into a single response, grouped by control. - -winui-search get [ ...] - Get full XAML + C# code (plus NuGet/xmlns prereqs and pitfall notes) for - one or more scenario ids. Skill convention is ≤3 ids per call. - -winui-search list [--source S] - List all available patterns. - -winui-search debug - Diagnostic dump: query preprocessing, token expansion, top-N grouped - matches without the score floor. Useful for tuning queries / synonyms. - -winui-search update - Force a synchronous re-fetch from GitHub (clears the on-disk cache and - repopulates it). Takes ~10s. Normally not needed — see "Background - updates" below. -``` - -`--source ` restricts results to a single source on -both `search` and `list` (case-insensitive, single value). Useful when you -already know the answer is a Toolkit-only control or a curated core pattern -and want to skip Gallery noise. - -Output is compact text designed for agent consumption — `search` returns a -short header per match, `get` returns fenced XAML/C# blocks plus prerequisite -hints separated by `---`. - -## Background updates - -Hot-path commands (`search` / `get` / `list` / `debug`) never block on a -GitHub fetch. After answering, they consult `BackgroundUpdater.TryKickoffIfStale()`, -which spawns a detached `winui-search update --background` child when: - -1. `last-github-update.txt` is older than 7 days (or absent), AND -2. `last-github-attempt.txt` is older than 1 hour (rate-limit on failures), AND -3. No other process holds `update.lock` (atomic `FileMode.CreateNew`; a 10-min - TTL reaps locks orphaned by a crashed child). - -The child fetches GitHub and updates the cache while the user has already -received their answer. Detach is true fire-and-forget on Windows: the parent -exits within ~1.5 s on a cold cache, and the child outlives it without -blocking pipes. - -Environment overrides: - -| Variable | Effect | -|---|---| -| `WINUI_SEARCH_NO_BACKGROUND=1` | Skip the spawn entirely. Use in CI, sandboxed networks, or when offline. | -| `WINUI_SEARCH_DEBUG=1` | Emit a trace to `%LOCALAPPDATA%\winui-search\cache\background.log` for diagnosing the spawn / fetch / lock lifecycle. | - -The internal `--background` flag on `winui-search update` is for the spawned -child only — it suppresses console output, skips the cache wipe (so the lock -file survives), and writes only the timestamp markers. Don't pass it manually. - -## Cache layout - -``` -%LOCALAPPDATA%\winui-search\cache\ - schema-version.txt # Stamped with CacheVersion.Current - last-github-update.txt # Last successful GitHub fetch (UTC ISO) - last-github-attempt.txt # Last attempted fetch (success or failure) - update.lock # Held by spawned child while fetching - background.log # Optional trace (WINUI_SEARCH_DEBUG=1 only) - gallery\ - scenarios.json - tags.json - schema-version.txt - last-updated.txt - toolkit\ - scenarios.json - tags.json - keywords.json - schema-version.txt - last-updated.txt - reactor\ - scenarios.json - tags.json - schema-version.txt - last-updated.txt -``` - -The on-disk cache is per-user and discarded when `CacheVersion.Current` bumps; -embedded JSON in the exe is the safety net. - -## Tests - -None yet. Tracked by the `tool-winui-search-improvement-plan` todo and -launch tracker §12.3. - -## Status - -**Preview / unsigned**, ships from this repo as a committed prebuilt exe inside -the consuming skill payload. Long-term homes under consideration: publish as a -`dotnet tool` on NuGet, or fold into [`microsoft/winappcli`](https://github.com/microsoft/winappcli) -as a `winapp search` subcommand. Decision tracked in launch tracker §12.4 + -the open `skill-distribution-decision` todo. diff --git a/src/tools/winui-search/ReactorFetcher.cs b/src/tools/winui-search/ReactorFetcher.cs deleted file mode 100644 index 9cee82bb..00000000 --- a/src/tools/winui-search/ReactorFetcher.cs +++ /dev/null @@ -1,148 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using System.Net.Http; -using System.Text.Json; - -/// -/// microsoft-ui-reactor ReactorGallery scenarios. Reads the purpose-built -/// reactor-search-index.json (a schema the Reactor team owns) and maps it -/// onto the internal model. Reactor samples are C#-only -/// declarative WinUI (UseMemo, DataGrid(...), Column<T>(...)) — -/// kept verbatim, never run through the gallery/toolkit sample cleaners. There is -/// no XAML, so stays null. -/// -/// Each control's curated keywords become the 3.0-weighted enrichment tag -/// field (); they are served VERBATIM — not -/// stop-word cleaned — so multi-word intent terms like "css layout" survive -/// (cleaning would drop the TagOnly stop word "layout" and break searches such as -/// "flex layout"). The 4 controls that declare control-level usings -/// (data-grid, docking, flex, property-grid) get those folded into each sample's -/// C# so the emitted snippet compiles standalone. -/// -internal static class ReactorFetcher -{ - private const string IndexUrl = - "https://raw.githubusercontent.com/microsoft/microsoft-ui-reactor/main/samples/ReactorGallery/reactor-search-index.json"; - - private static readonly HttpClient Http = new() - { - DefaultRequestHeaders = { { "User-Agent", "winui-search/1.0" } }, - Timeout = TimeSpan.FromSeconds(30) - }; - - /// Embedded snapshot baked into the exe at build time — the offline - /// fallback served when the on-disk cache is missing or stale. Tags are already - /// verbatim (no cleaning applied on write, so none on read either). - internal static (Scenario[] scenarios, Dictionary tags) LoadEmbedded() - => (DataLoader.LoadReactorScenarios(), DataLoader.LoadReactorTags()); - - /// Fetch fresh scenarios + tags from GitHub (used by the `update` - /// command). Reactor C# and curated keywords are kept verbatim. - internal static async Task<(Scenario[] scenarios, Dictionary tags)> FetchAsync() - { - var json = await Http.GetStringAsync(IndexUrl); - return Parse(json); - } - - /// Map the reactor-search-index.json document to - /// [] + the per-control tag dictionary. Parsed with - /// (AOT-safe, no reflection). - internal static (Scenario[] scenarios, Dictionary tags) Parse(string json) - { - using var doc = JsonDocument.Parse(json); - var root = doc.RootElement; - - var scenarios = new List(); - var tags = new Dictionary(StringComparer.OrdinalIgnoreCase); - - if (root.ValueKind != JsonValueKind.Object - || !root.TryGetProperty("controls", out var controls) - || controls.ValueKind != JsonValueKind.Array) - { - return (Array.Empty(), tags); - } - - foreach (var control in controls.EnumerateArray()) - { - var controlId = GetString(control, "id"); - if (string.IsNullOrEmpty(controlId)) continue; - - var controlName = GetString(control, "name"); - var controlDescription = GetString(control, "description"); - var apiNamespace = GetString(control, "apiNamespace"); - var nugetPackage = GetString(control, "nugetPackage"); - var relatedControls = GetStringArray(control, "relatedControls"); - var usings = GetStringArray(control, "usings"); - var keywords = GetStringArray(control, "keywords"); - - // Curated keywords -> 3.0-weighted enrichment tag field, verbatim. - if (keywords.Length > 0) tags[controlId] = keywords; - - // For controls that declare usings, prepend `using X;` lines + a blank - // line to EACH sample's code so the declarative snippet compiles alone. - var usingsPrefix = usings.Length > 0 - ? string.Concat(usings.Select(u => $"using {u};\n")) + "\n" - : ""; - - if (!control.TryGetProperty("samples", out var samples) - || samples.ValueKind != JsonValueKind.Array) - { - continue; - } - - var index = 0; - foreach (var sample in samples.EnumerateArray()) - { - var header = GetString(sample, "header"); - var code = GetString(sample, "code"); - - // Reactor samples are C#-only (Xaml is always null), so a sample - // with no code has no usable content — skip it rather than emit a - // blank scenario. Guard on the raw code (before the usings prefix) - // so a control that only has control-level usings can't slip - // through as a using-only stub. Mirrors GalleryFetcher's - // "csharp == null && xaml == null → continue" rule. - if (string.IsNullOrWhiteSpace(code)) continue; - - index++; - scenarios.Add(new Scenario - { - Id = $"{controlId}-{index}", - ControlId = controlId, - ControlName = controlName, - HeaderText = header, - Xaml = null, - CSharp = usingsPrefix + code, - Source = "reactor", - NuGetPackage = string.IsNullOrEmpty(nugetPackage) ? null : nugetPackage, - ApiNamespace = string.IsNullOrEmpty(apiNamespace) ? null : apiNamespace, - ControlDescription = string.IsNullOrEmpty(controlDescription) ? null : controlDescription, - RelatedControls = relatedControls, - }); - } - } - - return (scenarios.ToArray(), tags); - } - - private static string GetString(JsonElement el, string prop) - => el.TryGetProperty(prop, out var v) && v.ValueKind == JsonValueKind.String - ? v.GetString() ?? "" - : ""; - - private static string[] GetStringArray(JsonElement el, string prop) - { - if (!el.TryGetProperty(prop, out var v) || v.ValueKind != JsonValueKind.Array) - return Array.Empty(); - - var list = new List(); - foreach (var item in v.EnumerateArray()) - { - if (item.ValueKind != JsonValueKind.String) continue; - var s = item.GetString(); - if (!string.IsNullOrEmpty(s)) list.Add(s); - } - return list.ToArray(); - } -} diff --git a/src/tools/winui-search/ReactorProvider.cs b/src/tools/winui-search/ReactorProvider.cs deleted file mode 100644 index ff151478..00000000 --- a/src/tools/winui-search/ReactorProvider.cs +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -/// -/// microsoft-ui-reactor ReactorGallery scenarios (C#-only declarative WinUI). -/// Parse logic lives in ; this type just wires it into -/// the provider model. Reactor's curated per-control keywords are supplied as the -/// enrichment field (3.0 weight) and served -/// verbatim — no stop-word cleaning (so multi-word intent terms like "css layout" -/// survive), hence no NormalizeTagsOnRead override. Reactor contributes no -/// separate curated-keyword field. -/// -internal sealed class ReactorProvider : CachedProviderBase -{ - public override string Id => "reactor"; - public override string DisplayName => "Reactor (WinUI)"; - - protected override ProviderData LoadEmbedded() - { - var (scenarios, tags) = ReactorFetcher.LoadEmbedded(); - return new ProviderData(scenarios, tags, new()); - } - - protected override async Task FetchAsync() - { - var (scenarios, tags) = await ReactorFetcher.FetchAsync(); - return scenarios.Length > 0 - ? new ProviderData(scenarios, tags, new()) - : ProviderData.Empty; - } -} diff --git a/src/tools/winui-search/SearchEngine.cs b/src/tools/winui-search/SearchEngine.cs deleted file mode 100644 index 978a6155..00000000 --- a/src/tools/winui-search/SearchEngine.cs +++ /dev/null @@ -1,853 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -internal sealed class SearchEngine -{ - private readonly Scenario[] _scenarios; - private readonly CorePattern[] _corePatterns; - private readonly Dictionary _enrichmentTags; - private readonly Dictionary _curatedKeywords; - private readonly Dictionary> _scenariosByControl; - private readonly string[] _uniqueControls; - private readonly string[] _knownSources; - - public SearchEngine( - Scenario[] scenarios, - CorePattern[] corePatterns, - Dictionary enrichmentTags, - Dictionary? curatedKeywords = null) - { - _scenarios = scenarios; - _corePatterns = corePatterns; - _enrichmentTags = enrichmentTags; - _curatedKeywords = curatedKeywords ?? new(); - - _scenariosByControl = new(); - foreach (var s in scenarios) - { - // Use composite key (source + controlId) to keep Toolkit and Gallery - // controls with the same controlId (e.g., "colorpicker") separate. - var key = $"{s.Source}:{s.ControlId}"; - if (!_scenariosByControl.TryGetValue(key, out var list)) - { - list = new List(); - _scenariosByControl[key] = list; - } - list.Add(s); - } - _uniqueControls = _scenariosByControl.Keys.ToArray(); - _knownSources = scenarios.Select(s => s.Source) - .Where(s => !string.IsNullOrEmpty(s)) - .Distinct(StringComparer.OrdinalIgnoreCase) - .ToArray(); - } - - public record SearchResult(string Id, string Scenario, string Type, double Score); - - /// One entry inside a control group (a single scenario row). - public record ScenarioRow(string Id, string Header, string? Description = null); - - /// - /// Grouped search result. For core patterns, Scenarios holds one row. - /// For gallery/toolkit controls, it holds up to maxScenariosPerControl rows - /// — letting the caller decide which scenario fits best. - /// - public record GroupedResult( - string Source, // "core" / "gallery" / "toolkit" - string ControlName, // empty for core - int TotalScenarios, - List Scenarios, - double Score, - string? ControlDescription = null, // one-line concept summary (toolkit/gallery) - bool HasNameBoost = false); // matched via name/id/compound/substring (vs. only via headers/tags) - - // ─── Intent classification ─────────────────────────────────────────── - private static readonly string[] ToolkitIntent = - ["toolkit", "communitytoolkit", "community"]; - - /// - /// Maps platform-intent query keywords → the core pattern id that should be boosted. - /// Keys are lowercased single tokens that appear in the user's query (after Preprocess). - /// We use this to nudge the *specific* curated pattern, not every core pattern. - /// - private static readonly Dictionary PlatformKeywordToPatternId = new(StringComparer.OrdinalIgnoreCase) - { - ["share"] = "share-contract-desktop", - ["jumplist"] = "jumplist-recent-files", - ["taskbar"] = "jumplist-recent-files", - ["tray"] = "system-tray-minimize", - ["systemtray"] = "system-tray-minimize", - ["drag"] = "drag-drop-files", - ["drop"] = "drag-drop-files", - ["dragdrop"] = "drag-drop-files", - ["picker"] = "file-picker-desktop", - ["filepicker"] = "file-picker-desktop", - ["folderpicker"] = "file-picker-desktop", - }; - - private static string CompactQuery(string q) => - System.Text.RegularExpressions.Regex.Replace(q.ToLowerInvariant(), @"[^a-z0-9]", ""); - - /// - /// Split a CamelCase or PascalCase identifier into space-separated words. - /// "TokenizingTextBox" → "Tokenizing Text Box" (then BM25.Tokenize lowercases). - /// "ColorPicker" → "Color Picker". Used to build a tokenized variant of control - /// names for BM25 so multi-word queries can match the *parts* of a name, not - /// only the name as a single opaque token. - /// - private static string SplitCamelCase(string s) - { - if (string.IsNullOrEmpty(s)) return s; - var sb = new System.Text.StringBuilder(s.Length + 8); - for (int i = 0; i < s.Length; i++) - { - char c = s[i]; - if (i > 0 && char.IsUpper(c) - && (char.IsLower(s[i - 1]) || (i + 1 < s.Length && char.IsLower(s[i + 1])))) - { - sb.Append(' '); - } - sb.Append(c); - } - return sb.ToString(); - } - - /// Two-layer search: find controls first, then pick best scenario. - public List Search(string query, int maxResults = 5) - { - // Phrase preprocessing: append merged tokens (e.g. "data grid" → keeps "data", "grid", adds "datagrid") - var preprocessed = Synonyms.Preprocess(query); - var queryWords = BM25.Tokenize(preprocessed); - if (queryWords.Length == 0) return []; - var queryCompact = CompactQuery(query); // e.g., "Color Picker Button" → "colorpickerbutton" - - // Expand query with synonyms (datagrid → listview, modal → contentdialog, etc.) - var expandedWords = Synonyms.Expand(queryWords); - - // Detect query intents - bool wantsToolkit = queryWords.Any(w => ToolkitIntent.Contains(w)); - // Targeted platform-intent: only boost the SPECIFIC core pattern keyed by the query token. - // (Avoids the old "any platform keyword boosts ALL core patterns" noise.) - var platformBoostIds = new HashSet(StringComparer.Ordinal); - foreach (var w in queryWords) - { - if (PlatformKeywordToPatternId.TryGetValue(w, out var pid)) - platformBoostIds.Add(pid); - } - - // Build docs for core patterns - var coreDocs = _corePatterns.Select(p => BM25.BuildDoc( - (string.Join(" ", p.Tags), 3.0), - (p.Scenario, 2.0), - (p.Description, 1.0), - (p.Id, 1.0) - )).ToArray(); - - // Build docs for gallery controls - var controlDocs = _uniqueControls.Select(key => - { - var scenarios = _scenariosByControl[key]; - var controlId = scenarios[0].ControlId; - var controlName = scenarios[0].ControlName; - // `key` is already "{source}:{controlId}" — match the composite-key - // dictionaries Program.cs builds so gallery↔toolkit collisions - // (colorpicker, wrappanel) don't bleed tags/keywords across sources. - var enrichTags = _enrichmentTags.TryGetValue(key, out var tags) ? tags : []; - var keywords = _curatedKeywords.TryGetValue(key, out var kws) ? kws : []; - var nameSplit = SplitCamelCase(controlName); - return BM25.BuildDoc( - (controlName, 3.0), - (controlId, 3.0), - (nameSplit, 2.5), - (string.Join(" ", keywords), 5.0), - (string.Join(" ", enrichTags), 3.0), - (scenarios[0].HeaderText, 1.5) - ); - }).ToArray(); - - var allDocs = coreDocs.Concat(controlDocs).ToArray(); - var corpus = BM25.BuildCorpus(allDocs); - - var results = new List(); - - // Score core patterns + targeted platform-intent boost - for (int i = 0; i < _corePatterns.Length; i++) - { - var s = BM25.Score(coreDocs[i], expandedWords, corpus); - // Only boost the core pattern(s) the query actually points at. - if (platformBoostIds.Contains(_corePatterns[i].Id)) s *= 1.6; - if (s > 0) results.Add(new(_corePatterns[i].Id, _corePatterns[i].Scenario, "core", s)); - } - - // Find the LONGEST control name (compact form) that the query contains, so for - // queries like "color picker button" we boost ColorPickerButton (17 chars) and - // explicitly NOT ColorPicker (11 chars). Both technically match the compact form, - // but the longer one is what the user actually asked for. - string? longestCompactMatch = null; - for (int i = 0; i < _uniqueControls.Length; i++) - { - var compactName = CompactQuery(_scenariosByControl[_uniqueControls[i]][0].ControlName); - if (compactName.Length >= 8 && queryCompact.Contains(compactName)) - { - if (longestCompactMatch == null || compactName.Length > longestCompactMatch.Length) - longestCompactMatch = compactName; - } - } - - // Score gallery/toolkit controls, then pick best scenario - for (int i = 0; i < _uniqueControls.Length; i++) - { - var s = BM25.Score(controlDocs[i], expandedWords, corpus); - var scenarios = _scenariosByControl[_uniqueControls[i]]; - var first = scenarios[0]; - var controlName = first.ControlName; - var controlLower = controlName.ToLowerInvariant(); - var controlCompact = CompactQuery(controlName); - - // Whole-word match on control name (existing boost) - if (controlLower.Length > 2 && queryWords.Any(w => w == controlLower)) - s *= 2.0; - - // Compound-name match — but only the LONGEST match wins big. - // Shorter prefixes that happen to be contained get a small boost; the - // most-specific match gets the strong one. - if (controlCompact.Length >= 8 && queryCompact.Contains(controlCompact)) - { - if (controlCompact == longestCompactMatch) s *= 4.0; // strongest: most specific - else s *= 1.3; // mild: matched but not most specific - } - - // Source intent boost - if (wantsToolkit && first.Source == "toolkit") s *= 1.6; - - if (s <= 0) continue; - - var bestScenario = PickBestScenario(scenarios, expandedWords); - // Demote scenarios with placeholder/generic header (Basic usage, Example N, "This is the Header") - if (IsGenericHeader(bestScenario.HeaderText)) s *= 0.85; - - var prefix = $"{bestScenario.Source}-"; - results.Add(new($"{prefix}{bestScenario.Id}", ControlHeader(bestScenario.ControlName, bestScenario.HeaderText), bestScenario.Source, s)); - } - - results.Sort((a, b) => b.Score.CompareTo(a.Score)); - return results.Take(maxResults).ToList(); - } - - /// - /// Grouped search: returns up to matched controls, - /// each with all its scenarios (capped at ) - /// ordered by per-scenario relevance. Lets callers (and the AI) pick which - /// scenario actually fits without the engine having to commit to one. - /// - public List SearchGrouped( - string query, int maxControls = 3, int maxScenariosPerControl = 3, - bool applyFloor = true, string? sourceFilter = null) - { - var preprocessed = Synonyms.Preprocess(query); - var queryWords = BM25.Tokenize(preprocessed); - if (queryWords.Length == 0) return []; - var queryCompact = CompactQuery(query); - var expandedWords = Synonyms.Expand(queryWords); - - // Coverage gate inputs: original query tokens (NOT preprocessed/expanded), - // so synonyms inflating N to 7 don't cause false rejections. - // Distinct so repeated tokens don't double-count. - var rawQueryTokens = BM25.Tokenize(query).Distinct().ToArray(); - // Only enforce the gate for queries with >= 3 user tokens. With 1-2 tokens, - // BM25's own ranking is already adequate and adding a half-coverage rule - // would reject normal short queries like "tab close" → TabView (hits=1/2). - bool applyCoverageGate = rawQueryTokens.Length >= 3; - int coverageMin = (rawQueryTokens.Length + 1) / 2; // ceil(N/2) - - bool wantsToolkit = queryWords.Any(w => ToolkitIntent.Contains(w)); - var platformBoostIds = new HashSet(StringComparer.Ordinal); - foreach (var w in queryWords) - { - if (PlatformKeywordToPatternId.TryGetValue(w, out var pid)) - platformBoostIds.Add(pid); - } - - var coreDocs = _corePatterns.Select(p => BM25.BuildDoc( - (string.Join(" ", p.Tags), 3.0), - (p.Scenario, 2.0), - (p.Description, 1.0), - (p.Id, 1.0) - )).ToArray(); - - // Pre-collect enrichment tags per control so the scoring loop can re-use them - // for the platform-keyword reverse-demotion check below. `key` is composite - // ("{source}:{controlId}") to keep gallery + toolkit colliding controlIds - // separate. - var controlEnrichTags = _uniqueControls.Select(key => - { - return _enrichmentTags.TryGetValue(key, out var tags) ? tags : Array.Empty(); - }).ToArray(); - - // Author-curated keywords (toolkit md frontmatter). Empty for gallery - // controls; used both as a high-weight BM25 field AND added to the - // tag substring check so a query word that appears only in keywords - // still counts as a "real" match for the platform-keyword guard. - var controlKeywords = _uniqueControls.Select(key => - { - return _curatedKeywords.TryGetValue(key, out var kws) ? kws : Array.Empty(); - }).ToArray(); - - var controlDocs = _uniqueControls.Select((key, idx) => - { - var scenarios = _scenariosByControl[key]; - var controlName = scenarios[0].ControlName; - var controlId = scenarios[0].ControlId; - var enrichTags = controlEnrichTags[idx]; - var keywords = controlKeywords[idx]; - // All scenario headers concatenated, controlName stripped to avoid - // double-counting against the dedicated controlName field. No "primary" - // bias: every scenario contributes equally; BM25's TF saturation handles repeats. - string CleanHeader(string h) - { - var stripped = h.Replace(controlName, "", StringComparison.OrdinalIgnoreCase); - return string.Join(" ", global::StopWords.FilterTagList(BM25.Tokenize(stripped))); - } - var allHeaders = string.Join(" ", scenarios.Select(s => CleanHeader(s.HeaderText))); - // CamelCase-split control name: "TokenizingTextBox" → "tokenizing text box" - // so a query like "tokenizing tag input" can match the *name* directly, - // not only via tags. Without this, BM25 sees "tokenizingtextbox" as one - // opaque token; "tokenizing" never matches and good answers tie with noise. - var nameSplit = SplitCamelCase(controlName); - return BM25.BuildDoc( - (controlName, 3.0), - (controlId, 3.0), - (nameSplit, 2.5), - (string.Join(" ", keywords), 5.0), - (string.Join(" ", enrichTags), 3.0), - (allHeaders, 0.8) - ); - }).ToArray(); - - var allDocs = coreDocs.Concat(controlDocs).ToArray(); - var corpus = BM25.BuildCorpus(allDocs); - - var groups = new List(); - - // Core patterns — always one row each. - for (int i = 0; i < _corePatterns.Length; i++) - { - var s = BM25.Score(coreDocs[i], expandedWords, corpus); - if (platformBoostIds.Contains(_corePatterns[i].Id)) s *= 1.6; - if (applyCoverageGate && BM25.CountHits(coreDocs[i], rawQueryTokens) < coverageMin) s = 0; - if (s <= 0) continue; - groups.Add(new GroupedResult( - Source: "core", - ControlName: "", - TotalScenarios: 1, - Scenarios: [new ScenarioRow(_corePatterns[i].Id, _corePatterns[i].Scenario)], - Score: s)); - } - - // Find the longest compact control name contained in the query (same as Search). - string? longestCompactMatch = null; - for (int i = 0; i < _uniqueControls.Length; i++) - { - var compactName = CompactQuery(_scenariosByControl[_uniqueControls[i]][0].ControlName); - if (compactName.Length >= 8 && queryCompact.Contains(compactName)) - { - if (longestCompactMatch == null || compactName.Length > longestCompactMatch.Length) - longestCompactMatch = compactName; - } - } - - // Single-name auto-tighten:when the query is a single token that matches a - // control name exactly (e.g. "combobox", "togglesswitch"), the user already - // knows what they want — don't pad the result list with weak siblings. - // Show ONE control with more of its scenarios instead. - if (queryWords.Length == 1 && longestCompactMatch != null && longestCompactMatch == queryCompact) - { - maxControls = 1; - maxScenariosPerControl = Math.Max(maxScenariosPerControl, 5); - } - - // Platform-keyword reverse demotion targets: any control whose compact name - // contains a platform-intent keyword in the query (e.g. "picker") but whose - // name doesn't satisfy any *other* (non-keyword) query word should be demoted — - // it's matching only on the platform noun, which already has a curated core - // pattern that wins. - var platformKeywordsInQuery = queryWords - .Where(w => PlatformKeywordToPatternId.ContainsKey(w)) - .ToArray(); - var nonPlatformQueryWords = queryWords - .Where(w => !PlatformKeywordToPatternId.ContainsKey(w)) - .ToArray(); - - for (int i = 0; i < _uniqueControls.Length; i++) - { - var s = BM25.Score(controlDocs[i], expandedWords, corpus); - var scenarios = _scenariosByControl[_uniqueControls[i]]; - var first = scenarios[0]; - var controlName = first.ControlName; - var controlLower = controlName.ToLowerInvariant(); - var controlCompact = CompactQuery(controlName); - var enrichTags = controlEnrichTags[i]; - var keywords = controlKeywords[i]; - - // Substring boost: a long query word fully contained in the control's - // compact name is strong evidence of intent ("tokenizing" inside - // "tokenizingtextbox", "advanced" inside "advancedcollectionview"). - // Skip platform keywords — they have their own targeted boost on the - // curated core pattern; substring-matching them on every *Picker / - // *Tray control would re-amplify exactly the noise we just demoted. - bool hasNameBoost = false; - foreach (var qw in queryWords) - { - if (qw.Length >= 6 - && !PlatformKeywordToPatternId.ContainsKey(qw) - && controlCompact.Contains(qw)) - { - s *= 2.5; - hasNameBoost = true; - break; // one substring boost per control - } - } - - if (controlLower.Length > 2 && queryWords.Any(w => w == controlLower)) - { - s *= 2.0; - hasNameBoost = true; - } - - if (controlCompact.Length >= 8 && queryCompact.Contains(controlCompact)) - { - if (controlCompact == longestCompactMatch) s *= 4.0; - else s *= 1.3; - hasNameBoost = true; - } - - if (wantsToolkit && first.Source == "toolkit") s *= 1.6; - - // Reverse demotion: control name contains a platform keyword from the query - // (e.g. DatePicker matched on "picker"), but no non-keyword query word - // independently matches the control name or its tags. The targeted core - // pattern already covers this intent — we don't want to also surface every - // *Picker control just because they share the noun. - if (platformKeywordsInQuery.Length > 0 - && platformKeywordsInQuery.Any(kw => controlLower.Contains(kw))) - { - bool hasOtherMatch = nonPlatformQueryWords.Any(qw => - controlLower.Contains(qw) - || enrichTags.Any(t => t.Contains(qw, StringComparison.OrdinalIgnoreCase)) - || keywords.Any(k => k.Contains(qw, StringComparison.OrdinalIgnoreCase))); - if (!hasOtherMatch) s *= 0.3; - } - - // Coverage gate: when the user typed >=3 distinct words and this control - // matched fewer than half of them, suppress it. Skipped when hasNameBoost - // fires (the user named the control directly), since a single strong - // intent signal can override missing supporting tokens. - if (applyCoverageGate - && !hasNameBoost - && BM25.CountHits(controlDocs[i], rawQueryTokens) < coverageMin) - { - s = 0; - } - - if (s <= 0) continue; - - // Score each scenario individually so we can present them in relevance order. - var scenDocs = scenarios.Select(sc => BM25.BuildDoc( - (sc.HeaderText, 2.0), - (sc.ControlName, 1.0) - )).ToArray(); - var scenCorpus = BM25.BuildCorpus(scenDocs); - - var ranked = scenarios - .Select((sc, idx) => - { - var score = BM25.Score(scenDocs[idx], expandedWords, scenCorpus); - // Tie-breaker nudge: when nothing in the query specifically matches a - // wordier scenario (e.g. "settings page" vs. SettingsExpander's - // ItemsSource demo), prefer the canonical "Basic usage" / "A basic …" - // entry. Small additive boost so it only flips near-ties. - if (IsBasicHeader(sc.HeaderText)) score += 0.1; - return (sc, score); - }) - // Stable order: by score desc, then by ID for determinism. - .OrderByDescending(t => t.score) - .ThenBy(t => t.sc.Id, StringComparer.OrdinalIgnoreCase) - .ToList(); - - // Demote whole control if every scenario has a generic header. - if (ranked.All(r => IsGenericHeader(r.sc.HeaderText))) s *= 0.85; - - var prefix = $"{first.Source}-"; - // Drop scenarios with zero BM25 score: they have no query-token hits at - // all, so they're pure noise pulled in only because the parent control - // ranked into top-N. Fall back to top-1 if that empties the list, so - // the control still shows a representative scenario. - var withSignal = ranked.Where(r => r.score > 0).Take(maxScenariosPerControl).ToList(); - var rows = (withSignal.Count > 0 ? withSignal : ranked.Take(1)) - .Select(r => new ScenarioRow($"{prefix}{r.sc.Id}", r.sc.HeaderText, r.sc.Description)) - .ToList(); - - // Control-level summary: prefer explicit ControlDescription (toolkit frontmatter). - string? controlDesc = scenarios - .Select(sc => sc.ControlDescription) - .FirstOrDefault(d => !string.IsNullOrEmpty(d)); - // Fallback: when every scenario shares the same Description (Gallery, where - // Description is per-control), promote it so per-row rendering can dedupe. - if (controlDesc == null) - { - var firstDesc = scenarios.FirstOrDefault()?.Description; - if (!string.IsNullOrEmpty(firstDesc) && scenarios.All(sc => sc.Description == firstDesc)) - controlDesc = firstDesc; - } - - groups.Add(new GroupedResult( - Source: first.Source, - ControlName: controlName, - TotalScenarios: scenarios.Count, - Scenarios: rows, - Score: s, - ControlDescription: controlDesc, - HasNameBoost: hasNameBoost)); - } - - groups.Sort((a, b) => b.Score.CompareTo(a.Score)); - - // Source filter applied BEFORE the relevance floor + Take(maxControls). - // If callers post-filtered after Take, valid hits could be silently dropped - // when a non-matching source ranked above them (e.g. `--source toolkit` on - // "colorpicker" — gallery's ColorPicker scores higher, would consume the - // only slot, then the post-filter would return empty). - if (sourceFilter != null) - { - groups = groups - .Where(g => string.Equals(g.Source, sourceFilter, StringComparison.OrdinalIgnoreCase)) - .ToList(); - } - - // Relevance floor (applied to RUNNERS-UP only — top-1 always survives): - // Runner-up needs score ≥ 70% of top to be shown. - // - // Replaces an earlier two-tier (15%/40%) floor that let weak name-substring - // hits leak through (e.g. "find text" → RichTextBlock + TextBlock + TextBox, - // "image crop" → ImageCropper + Image). With 70% we keep only runners-up - // that are genuinely close to top-1, e.g. "settings page" → SettingsCard + - // SettingsExpander or "tabbed documents" → TabView + TabbedCommandBar. - if (applyFloor && groups.Count > 1) - { - var topScore = groups[0].Score; - var runnerUpFloor = topScore * 0.70; - groups = groups.Where((g, i) => i == 0 || g.Score >= runnerUpFloor).ToList(); - } - - return groups.Take(maxControls).ToList(); - } - - /// True if a scenario header is a placeholder (Basic usage, Example N, "This is X"). - private static bool IsGenericHeader(string h) - { - if (string.IsNullOrWhiteSpace(h)) return true; - var t = h.Trim(); - if (t.Equals("Basic usage", StringComparison.OrdinalIgnoreCase)) return true; - if (System.Text.RegularExpressions.Regex.IsMatch(t, @"^Example\s*\d*$", System.Text.RegularExpressions.RegexOptions.IgnoreCase)) return true; - if (System.Text.RegularExpressions.Regex.IsMatch(t, @"^Sample\s*\d*$", System.Text.RegularExpressions.RegexOptions.IgnoreCase)) return true; - if (t.StartsWith("This is the ", StringComparison.OrdinalIgnoreCase)) return true; - return false; - } - - /// - /// True if the header is the canonical "first example" of a control. Used as a - /// per-scenario tie-breaker — when nothing in the query specifically picks a - /// wordier scenario, the Basic/Simple variant should win. - /// - private static bool IsBasicHeader(string h) - { - if (string.IsNullOrWhiteSpace(h)) return false; - var t = h.Trim(); - if (t.Equals("Basic usage", StringComparison.OrdinalIgnoreCase)) return true; - if (t.StartsWith("Basic ", StringComparison.OrdinalIgnoreCase)) return true; - if (t.StartsWith("Simple ", StringComparison.OrdinalIgnoreCase)) return true; - if (t.StartsWith("A basic ", StringComparison.OrdinalIgnoreCase)) return true; - if (t.StartsWith("A simple ", StringComparison.OrdinalIgnoreCase)) return true; - return false; - } - - private Scenario PickBestScenario(List scenarios, string[] queryWords) - { - if (scenarios.Count == 1) return scenarios[0]; - - var scenDocs = scenarios.Select(s => BM25.BuildDoc( - (s.HeaderText, 2.0), - (s.ControlName, 1.0) - )).ToArray(); - var corpus = BM25.BuildCorpus(scenDocs); - - int bestIdx = 0; - double bestScore = 0; - for (int i = 0; i < scenarios.Count; i++) - { - var s = BM25.Score(scenDocs[i], queryWords, corpus); - if (s > bestScore) { bestScore = s; bestIdx = i; } - } - return scenarios[bestIdx]; - } - - public (string formatted, bool found) GetPattern(string id) - { - // Check core patterns - var core = _corePatterns.FirstOrDefault(p => p.Id == id); - if (core != null) return (FormatCorePattern(core), true); - - // Strip a known "{source}-" prefix and remember which source the caller asked - // for, so we don't return a Gallery scenario for a "toolkit-..." id (or - // vice-versa) when the bare ids happen to collide. - string? expectedSource = null; - var bareId = id; - foreach (var src in _knownSources) - { - var p = src + "-"; - if (id.StartsWith(p, StringComparison.Ordinal)) - { - expectedSource = src; - bareId = id[p.Length..]; - break; - } - } - - bool MatchesSource(Scenario s) => expectedSource == null || s.Source == expectedSource; - - // Exact match on the new {controlId}-{N} scheme. - var scenario = _scenarios.FirstOrDefault(s => s.Id == bareId && MatchesSource(s)); - - // Fallback: caller passed a bare control id (e.g. "gallery-gridview") - // → return the lowest-numbered scenario for that control. Parses the - // trailing -{N} as an integer so e.g. "-2" sorts before "-10" (which - // a lexicographic sort would invert). Ids without a parseable suffix - // fall to the end and break ties via OrdinalIgnoreCase. - if (scenario == null) - { - scenario = _scenarios - .Where(s => s.ControlId == bareId && MatchesSource(s)) - .OrderBy(s => ParseTrailingNumber(s.Id)) - .ThenBy(s => s.Id, StringComparer.OrdinalIgnoreCase) - .FirstOrDefault(); - } - - if (scenario != null) return (FormatScenario(scenario), true); - return ($"Pattern '{id}' not found.", false); - } - - /// Parse the integer after the last - in , - /// returning if no parseable suffix is present so - /// such ids sort to the end. - private static int ParseTrailingNumber(string id) - { - int dash = id.LastIndexOf('-'); - if (dash < 0 || dash == id.Length - 1) return int.MaxValue; - return int.TryParse(id.AsSpan(dash + 1), out var n) ? n : int.MaxValue; - } - - public IEnumerable<(string id, string scenario)> ListAll() - { - foreach (var p in _corePatterns) - yield return (p.Id, p.Scenario); - - // Show ALL scenarios grouped by (source, control) so multi-scenario controls are - // discoverable AND collisions like ColorPicker (Gallery vs Toolkit) stay separate. - var byControl = _scenarios - .GroupBy(s => $"{s.Source}:{s.ControlId}") - .OrderBy(g => g.First().Source) // gallery first, toolkit after - .ThenBy(g => g.First().ControlName); - - foreach (var group in byControl) - { - var first = group.First(); - var prefix = $"{first.Source}-"; - foreach (var s in group) - yield return ($"{prefix}{s.Id}", ControlHeader(s.ControlName, s.HeaderText)); - } - } - - private static string FormatCorePattern(CorePattern p) - { - // Note: blank lines between sections are intentionally omitted — the Copilot CLI - // tool-result capture collapses runs of newlines, which would glue "**XAML:**" - // onto the previous block's content. Single newlines (one per logical line) - // survive intact. - var sb = new System.Text.StringBuilder(); - sb.AppendLine($"## {p.Scenario}"); - sb.AppendLine(p.Description); - if (p.Prerequisites.Length > 0) - { - sb.AppendLine("**Prerequisites:**"); - foreach (var pre in p.Prerequisites) sb.AppendLine($"- {pre}"); - } - if (p.Xaml != null) - { - sb.AppendLine("**XAML:**"); - sb.AppendLine("```xml"); - sb.AppendLine(NormalizeIndent(p.Xaml)); - sb.AppendLine("```"); - } - sb.AppendLine("**C#:**"); - sb.AppendLine("```csharp"); - sb.AppendLine(NormalizeIndent(p.CSharp)); - sb.AppendLine("```"); - if (p.Notes.Length > 0) - { - sb.AppendLine("**Important:**"); - foreach (var n in p.Notes) sb.AppendLine($"- {n}"); - } - return sb.ToString(); - } - - /// Render "ControlName: HeaderText", or just "ControlName" when HeaderText is - /// empty — a few legacy inline samples have no header source, and a bare ": " reads poorly. - private static string ControlHeader(string controlName, string headerText) - => string.IsNullOrWhiteSpace(headerText) ? controlName : $"{controlName}: {headerText}"; - - private static string FormatScenario(Scenario s) - { - // See note on FormatCorePattern: no blank-line separators (runtime collapses them). - var sb = new System.Text.StringBuilder(); - var sourceTag = s.Source switch - { - "toolkit" => " [CommunityToolkit]", - "reactor" => " [Reactor]", - _ => "" - }; - sb.AppendLine($"## {ControlHeader(s.ControlName, s.HeaderText)}{sourceTag}"); - - // Toolkit-specific prerequisites — single compact line - if (s.Source == "toolkit" && (!string.IsNullOrEmpty(s.NuGetPackage) || s.XmlnsImports.Length > 0)) - { - var parts = new List(1 + s.XmlnsImports.Length); - if (!string.IsNullOrEmpty(s.NuGetPackage)) - parts.Add($"NuGet `{s.NuGetPackage}`"); - foreach (var ns in s.XmlnsImports) - parts.Add($"`{ns}`"); - sb.AppendLine($"**Setup:** {string.Join(" · ", parts)}"); - } - // Reactor: surface the (uniform) NuGet package. Any control-level `using` - // directives are already folded into the C# snippet, and the shared - // Microsoft.UI.Reactor api namespace is deliberately NOT emitted as a - // **Namespace:** line — all 93 controls share it, so it'd be pure noise. - else if (s.Source == "reactor") - { - if (!string.IsNullOrEmpty(s.NuGetPackage)) - sb.AppendLine($"**Setup:** NuGet `{s.NuGetPackage}`"); - } - // Gallery non-default namespace hint — agents miss `using Microsoft.Windows.Notifications` - // and similar long-tail imports. Skip the dominant Microsoft.UI.Xaml.Controls (auto-imported - // in default templates) so 79/107 controls stay quiet. - else if (s.Source == "gallery" - && !string.IsNullOrEmpty(s.ApiNamespace) - && s.ApiNamespace != "Microsoft.UI.Xaml.Controls") - { - sb.AppendLine($"**Namespace:** `{s.ApiNamespace}`"); - } - - if (s.Xaml != null) - { - sb.AppendLine("**XAML:**"); - sb.AppendLine("```xml"); - sb.AppendLine(NormalizeIndent(s.Xaml)); - sb.AppendLine("```"); - } - if (s.CSharp != null && !IsBoilerplatePageWrapper(s.CSharp)) - { - sb.AppendLine("**C#:**"); - sb.AppendLine("```csharp"); - sb.AppendLine(NormalizeIndent(s.CSharp)); - sb.AppendLine("```"); - } - var notesPayload = Notes.Get(s.ControlName); - if (notesPayload.Pitfalls.Length > 0) - { - sb.AppendLine("**Important:**"); - foreach (var n in notesPayload.Pitfalls) sb.AppendLine($"- {n}"); - } - if (notesPayload.FamilyName != null) - { - sb.AppendLine($"**Family ({notesPayload.FamilyName}):** {notesPayload.FamilyGuide}"); - } - - // Related controls (from WinUI Gallery's ControlInfoData.json) - if (s.RelatedControls.Length > 0) - { - sb.AppendLine($"**See also:** {string.Join(", ", s.RelatedControls)}"); - } - - // Note: Docs links from ControlInfoData.json are intentionally not emitted — - // benchmark logs show agents never fetch them, so the bytes/tokens are pure - // overhead. The data is still kept on Scenario.Docs for potential future use. - - return sb.ToString(); - } - - /// - /// Re-maps the distinct leading-whitespace levels in a code block to a canonical - /// 0/2/4/6/... scale, preserving relative nesting structure. - /// Gallery samples are sliced from deeply-nested original XAML, so attribute lines - /// often start at column 30+. This collapses those huge prefixes (e.g. 36 → 4) while - /// keeping each child line strictly indented relative to its parent. - /// For already-clean code (e.g. C# at 0/4/8/12) this slightly tightens to 0/2/4/6. - /// - private static string NormalizeIndent(string code) - { - if (string.IsNullOrEmpty(code)) return code; - var lines = code.Split('\n'); - var distinct = new SortedSet(); - foreach (var line in lines) - { - if (line.Trim().Length == 0) continue; - var indent = 0; - while (indent < line.Length && (line[indent] == ' ' || line[indent] == '\t')) indent++; - distinct.Add(indent); - } - if (distinct.Count == 0) return code; - - var map = new Dictionary(distinct.Count); - int rank = 0; - foreach (var d in distinct) - { - map[d] = rank * 2; - rank++; - } - - var sb = new System.Text.StringBuilder(code.Length); - for (int i = 0; i < lines.Length; i++) - { - var line = lines[i]; - if (line.Trim().Length == 0) - { - if (i > 0) sb.Append('\n'); - continue; - } - var indent = 0; - while (indent < line.Length && (line[indent] == ' ' || line[indent] == '\t')) indent++; - if (i > 0) sb.Append('\n'); - sb.Append(' ', map[indent]); - sb.Append(line, indent, line.Length - indent); - } - return sb.ToString(); - } - - /// - /// True when the C# block is just an empty page wrapper (constructor that only calls - /// InitializeComponent — no other members or methods). Suppressing these saves ~140 - /// chars per scenario without losing any signal. - /// - private static bool IsBoilerplatePageWrapper(string cs) - { - if (string.IsNullOrWhiteSpace(cs)) return true; - if (!cs.Contains("InitializeComponent")) return false; - // Strip whitespace; if the only method body is `InitializeComponent();` the wrapper - // is empty. Heuristic: count occurrences of `(` that introduce a callable other - // than the ctor + InitializeComponent — none means boilerplate. - var collapsed = System.Text.RegularExpressions.Regex.Replace(cs, @"\s+", " "); - // Pattern: ... class X : Page { public X() { this.InitializeComponent(); } } - return System.Text.RegularExpressions.Regex.IsMatch( - collapsed, - @"class\s+\w+\s*:\s*Page\s*\{\s*public\s+\w+\s*\(\s*\)\s*\{\s*(?:this\.)?InitializeComponent\(\)\s*;\s*\}\s*\}\s*$"); - } -} diff --git a/src/tools/winui-search/SearchProvider.cs b/src/tools/winui-search/SearchProvider.cs deleted file mode 100644 index f814a0b9..00000000 --- a/src/tools/winui-search/SearchProvider.cs +++ /dev/null @@ -1,186 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using System.Text.Json; - -/// -/// Data contributed by a search provider: its scenarios plus the per-control -/// tag and keyword dictionaries. Tag/keyword keys are bare controlIds — the -/// engine namespaces them by provider id ({providerId}:{controlId}). -/// -internal sealed record ProviderData( - Scenario[] Scenarios, - Dictionary Tags, - Dictionary Keywords) -{ - public static ProviderData Empty { get; } = - new(Array.Empty(), new(), new()); -} - -/// -/// A source of WinUI scenarios (WinUI Gallery, Community Toolkit, …). A single -/// stable ties together everything downstream: it is the -/// Scenario.Source value, the on-disk cache subdirectory, the scenario -/// id prefix ({Id}-…), the --source token, and the composite -/// tag/keyword key namespace. Register a new provider in -/// and the rest of the tool picks it up. -/// -internal interface ISearchProvider -{ - /// Lowercase, stable identifier, e.g. "gallery" / "toolkit". - string Id { get; } - - /// Human-readable heading used by winui-search list. - string DisplayName { get; } - - /// Hot-path load: cached or embedded data. Never hits the network. - ProviderData Load(); - - /// update-path refresh: fetch from GitHub and rewrite the cache. - Task RefreshFromGitHubAsync(); -} - -/// -/// Boilerplate shared by every GitHub-backed provider: the on-disk cache -/// protocol (schema-version stamp + 7-day TTL + atomic writes) and the -/// embedded-snapshot fallback. Concrete providers only supply their identity, -/// their embedded snapshot, and their GitHub fetch. -/// -internal abstract class CachedProviderBase : ISearchProvider -{ - public abstract string Id { get; } - public abstract string DisplayName { get; } - - private static readonly TimeSpan CacheTtl = TimeSpan.FromDays(7); - - private string CacheDir => Path.Combine( - Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), - "winui-search", "cache", Id); - - /// Fully-prepared embedded snapshot (tags already cleaned). - protected abstract ProviderData LoadEmbedded(); - - /// Fully-prepared GitHub fetch (tags already cleaned). Return - /// to leave the cache untouched. - protected abstract Task FetchAsync(); - - /// Hook to re-normalize tags read back from cache. Defaults to - /// identity; providers that clean tags on write override this to match. - protected virtual Dictionary NormalizeTagsOnRead( - Dictionary tags) => tags; - - public ProviderData Load() - { - var cached = TryReadCache(); - if (cached != null) return cached; - - // Cache miss/stale: serve embedded data immediately (no GitHub fetch on - // the hot path) and prime the cache from it. A stale GitHub refresh is - // kicked off separately by BackgroundUpdater. - var embedded = LoadEmbedded(); - TryWriteCache(embedded); - return embedded; - } - - public async Task RefreshFromGitHubAsync() - { - var data = await FetchAsync(); - if (data.Scenarios.Length > 0) TryWriteCache(data); - } - - private ProviderData? TryReadCache() - { - var scenariosPath = Path.Combine(CacheDir, "scenarios.json"); - var tagsPath = Path.Combine(CacheDir, "tags.json"); - var keywordsPath = Path.Combine(CacheDir, "keywords.json"); - var timestampPath = Path.Combine(CacheDir, "last-updated.txt"); - var versionPath = Path.Combine(CacheDir, "schema-version.txt"); - - if (!File.Exists(scenariosPath) || !File.Exists(tagsPath) - || !File.Exists(timestampPath) || !File.Exists(versionPath)) - return null; - - try - { - if (File.ReadAllText(versionPath).Trim() != CacheVersion.Current) return null; - var lastUpdated = BackgroundUpdater.ReadTimestamp(timestampPath); - if (!lastUpdated.HasValue || DateTime.UtcNow - lastUpdated.Value >= CacheTtl) - return null; - - var scenarios = JsonSerializer.Deserialize( - File.ReadAllText(scenariosPath), JsonContext.Default.ScenarioArray); - var tags = JsonSerializer.Deserialize( - File.ReadAllText(tagsPath), JsonContext.Default.DictionaryStringStringArray); - if (scenarios == null || scenarios.Length == 0 || tags == null) return null; - - Dictionary? keywords = null; - if (File.Exists(keywordsPath)) - { - try - { - keywords = JsonSerializer.Deserialize( - File.ReadAllText(keywordsPath), JsonContext.Default.DictionaryStringStringArray); - } - catch { keywords = null; } - } - - return new ProviderData(scenarios, NormalizeTagsOnRead(tags), keywords ?? new()); - } - catch { return null; } - } - - private void TryWriteCache(ProviderData data) - { - try - { - var scenariosPath = Path.Combine(CacheDir, "scenarios.json"); - var tagsPath = Path.Combine(CacheDir, "tags.json"); - var keywordsPath = Path.Combine(CacheDir, "keywords.json"); - var timestampPath = Path.Combine(CacheDir, "last-updated.txt"); - var versionPath = Path.Combine(CacheDir, "schema-version.txt"); - - // Atomic per-file writes (temp + rename) so a crash mid-sequence can't - // leave truncated JSON. Order: data first, version next, timestamp LAST, - // so a partially-written set is detected as still-stale on next read - // (no fresh timestamp ⇒ Load() falls back to embedded again). - BackgroundUpdater.AtomicWriteAllText(scenariosPath, - JsonSerializer.Serialize(data.Scenarios, JsonContext.Default.ScenarioArray)); - BackgroundUpdater.AtomicWriteAllText(tagsPath, - JsonSerializer.Serialize(data.Tags, JsonContext.Default.DictionaryStringStringArray)); - if (data.Keywords.Count > 0) - BackgroundUpdater.AtomicWriteAllText(keywordsPath, - JsonSerializer.Serialize(data.Keywords, JsonContext.Default.DictionaryStringStringArray)); - BackgroundUpdater.AtomicWriteAllText(versionPath, CacheVersion.Current); - BackgroundUpdater.AtomicWriteAllText(timestampPath, DateTime.UtcNow.ToString("o")); - } - catch { /* cache write is best-effort */ } - } -} - -/// -/// The ordered set of scenario providers. This is the single place to register -/// a new source; and are -/// driven entirely off this list (plus the special-cased curated core patterns). -/// -internal static class ProviderRegistry -{ - /// All scenario providers, in display order (gallery first). - public static readonly ISearchProvider[] All = - { - new GalleryProvider(), - new ToolkitProvider(), - new ReactorProvider(), - }; - - /// Provider ids plus the pseudo-source "core" — the valid - /// values for --source. - public static IEnumerable SourceFilterValues => - All.Select(p => p.Id).Append("core"); - - public static bool IsValidSourceFilter(string source) => - SourceFilterValues.Any(s => string.Equals(s, source, StringComparison.OrdinalIgnoreCase)); - - /// Provider whose {Id}- prefix matches , if any. - public static ISearchProvider? ForScenarioId(string scenarioId) => - All.FirstOrDefault(p => scenarioId.StartsWith($"{p.Id}-", StringComparison.Ordinal)); -} diff --git a/src/tools/winui-search/StopWords.cs b/src/tools/winui-search/StopWords.cs deleted file mode 100644 index 5d96c5b9..00000000 --- a/src/tools/winui-search/StopWords.cs +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -internal static class StopWords -{ - /// - /// Common words that don't help discriminate between controls. - /// Used by both Gallery and Toolkit tag extractors. - /// Note: BM25 already does IDF weighting, but stripping these saves space. - /// - public static readonly HashSet Common = new(StringComparer.OrdinalIgnoreCase) - { - // Articles, conjunctions, pronouns, prepositions - "the","a","an","and","or","is","are","was","were","be","been", - "can","will","that","this","it","its","in","on","of","to","for", - "with","by","from","as","at","has","have","had","not","but", - "all","any","each","how","when","where","which","who","you","your", - "we","our","they","them","their","also","more","than","like","just", - "about","into","over","such","only","very","well","see", - // Generic verbs - "use","used","using","set","get","make","made", - "displays","display","displaying","presents","shows","show","lets","let", - "between","while","contain","contains","containing", - "maintain","maintains","maintaining", - // Generic UI nouns (no discrimination value across many controls) - "control","controls","property","properties","value","values", - "default","custom","new","component","sample","example", - "user","content","app","item","items","element","elements", - // Tech terms / infra - "csharp","xaml","uwp","winui","communitytoolkit", - // Description filler from WCT docs - "some","note","however","should","similar","objects","object","allows", - "setting","based","usage","having","public","instead","provide","found", - "does","support","many","main","case","create","certain", - "depending","technical","reasons","inherits","treated","added","whichever", - "acts","provided","subsequent","happens","sequentially","pretty","shares", - "needs","generate","accessible","replacement","look","specify", - "interface","represents","source","whose","loaded","ienumerable", - "instances","instance","examples", - // Auto-extraction noise from sample C#/XAML / commit messages - "true","false","pass","done","constructor", - "functionality","effect","through","various","modern","easy","simple", - "kind","type","types","approach","amount","least","space", - // Low-signal words common in Gallery sample HeaderText - "basic","adding","changes","header","options","another", - }; - - /// - /// Words that pollute control tag lists but a user might legitimately type as - /// a query token. Removed from tag dictionaries (in ) - /// but NOT from BM25.Tokenize, so queries like "text editor" still see - /// the "text" token and match TextBox via its nameSplit field. - /// - /// - /// Why this matters: control docs contain a SplitCamelCase field - /// (TextBox → "text"+"box", CalendarDatePicker → "calendar"+"date"+"picker"), - /// so removing these tokens from enrichment tags does NOT lose the canonical - /// match — only the spurious matches (Clipboard's "text", ColorPicker's - /// "text/input/layout/pick", every panel's "layout" subcategory). - /// - public static readonly HashSet TagOnly = new(StringComparer.OrdinalIgnoreCase) - { - "text", // Clipboard/HyperlinkButton/RichSuggestBox/ColorPicker noise; Text* controls keep it via nameSplit - "input", // Button/ColorPicker/RangeSelector noise; *Box controls keep it via nameSplit - "layout", // Toolkit subcategory — auto-stamped onto 18 controls, near-zero IDF - "pick", // Picker controls keep "picker" via nameSplit; "pick a X" queries match via X - "basics", // section heading filler - "advanced", // AdvancedCollectionView keeps it via nameSplit - }; - - /// True if the token should be dropped from BOTH BM25 query tokens AND tag dicts. - public static bool IsCommon(string w) => Common.Contains(w); - - /// True if the token should be dropped from tag dicts (a superset of ). - public static bool IsTagNoise(string w) => Common.Contains(w) || TagOnly.Contains(w); - - /// - /// Drops stop words (Common + TagOnly), sample-suffix tokens (e.g., - /// "imagecroppersample"), and dedupes. Multi-word tags ("context menu") are - /// preserved as-is. Use this for tag dictionaries; for BM25 query - /// tokenization use directly. - /// - public static string[] FilterTagList(string[] tags) - { - var seen = new HashSet(); - var result = new List(tags.Length); - foreach (var t in tags) - { - if (string.IsNullOrWhiteSpace(t)) continue; - var lower = t.Trim().ToLowerInvariant(); - if (IsTagNoise(lower)) continue; - // Drop auto-extracted *sample suffix tokens like "imagecroppersample" - // (only single-word tokens; preserve multi-word tags as-is). - if (!lower.Contains(' ') && lower.Length > "sample".Length && lower.EndsWith("sample")) - continue; - if (seen.Add(lower)) result.Add(lower); - } - return result.ToArray(); - } - - /// Apply to every entry of a tag dictionary. - public static Dictionary CleanTagDictionary(Dictionary tags) - { - var result = new Dictionary(tags.Count); - foreach (var (k, v) in tags) result[k] = FilterTagList(v); - return result; - } -} diff --git a/src/tools/winui-search/Synonyms.cs b/src/tools/winui-search/Synonyms.cs deleted file mode 100644 index 741897ab..00000000 --- a/src/tools/winui-search/Synonyms.cs +++ /dev/null @@ -1,365 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -internal static class Synonyms -{ - /// - /// Multi-word phrases that should be merged into a single token before - /// running synonym expansion. Keys must be lowercase. Match is exact-substring. - /// - public static readonly Dictionary Phrases = new(StringComparer.OrdinalIgnoreCase) - { - // Cross-framework / multi-word terms agents may use - ["data grid"] = "datagrid", - ["data-grid"] = "datagrid", - ["pull to refresh"] = "pulltorefresh", - ["pull-to-refresh"] = "pulltorefresh", - ["infinite scroll"] = "infinite", - ["lazy load"] = "lazy", - ["lazy loading"] = "lazy", - ["floating action button"] = "fab", - ["context menu"] = "contextmenu", - ["right click menu"] = "contextmenu", - ["right-click menu"] = "contextmenu", - ["nav bar"] = "navbar", - ["tab bar"] = "tabbar", - ["status bar"] = "infobar", - ["text area"] = "textarea", - ["text field"] = "textbox", - ["text input"] = "textbox", - ["date picker"] = "datepicker", - ["time picker"] = "timepicker", - ["color picker"] = "colorpicker", - ["file picker"] = "filepicker", - ["folder picker"] = "filepicker", - ["info bar"] = "infobar", - ["search box"] = "searchbox", - ["search bar"] = "searchbox", - ["scroll view"] = "scrollview", - ["scroll viewer"] = "scrollviewer", - ["check box"] = "checkbox", - ["radio button"] = "radio", - ["radio group"] = "radiogroup", - ["combo box"] = "combobox", - ["progress bar"] = "progressbar", - ["progress ring"] = "progressring", - ["loading indicator"] = "loading", - ["split button"] = "splitbutton", - ["split view"] = "splitview", - ["dropdown button"] = "dropdownbutton", - ["icon button"] = "iconbutton", - ["app bar"] = "commandbar", - ["tab view"] = "tabview", - ["tree view"] = "treeview", - // Accessibility / screen-reader / automation - ["screen reader"] = "screenreader", - ["screen-reader"] = "screenreader", - ["automation properties"] = "automationproperties", - ["automation property"] = "automationproperties", - ["automation id"] = "automationid", - ["automation name"] = "automationproperties", - ["accessible name"] = "automationproperties", - ["alt text"] = "automationproperties", - ["aria label"] = "automationproperties", - ["aria-label"] = "automationproperties", - ["live region"] = "liveregion", - ["list view"] = "listview", - ["grid view"] = "gridview", - ["web view"] = "webview", - ["map view"] = "map", - ["image view"] = "image", - ["video player"] = "video", - ["audio player"] = "audio", - ["media player"] = "player", - ["calendar view"] = "calendar", - ["number box"] = "stepper", - ["numeric input"] = "stepper", - ["password box"] = "password", - ["rich text"] = "richeditbox", - ["plain text"] = "textbox", - ["title bar"] = "titlebar", - ["status indicator"] = "infobadge", - ["badge count"] = "badge", - ["share sheet"] = "share", - ["action sheet"] = "actionsheet", - ["bottom sheet"] = "contentdialog", - ["app notification"] = "appnotification", - ["push notification"] = "appnotification", - ["system tray icon"] = "systemtray", - ["system tray"] = "systemtray", - ["jump list"] = "jumplist", - ["recent files"] = "recent", - ["drag and drop"] = "dragdrop", - ["drag drop"] = "dragdrop", - }; - - /// - /// Algorithmic suffix-stripping stemmer for query words. Yields candidate base - /// forms (without removing the original token from the query). Handles -s, -ed, - /// and -ing inflections including doubled-consonant cases (dropped → drop, - /// dragging → drag) and silent-e cases (closing → close, themed → theme). - /// - /// We emit multiple candidates per word to avoid false stems (e.g. "scrolled" - /// stems to BOTH "scroll" and "scrol" — the wrong one matches nothing in the - /// corpus, the right one matches; BM25 handles the rest). This is much smaller - /// and easier to maintain than the previous hand-curated 60+ entry Stems dict. - /// - public static IEnumerable Stem(string word) - { - if (string.IsNullOrEmpty(word)) yield break; - - if (word.Length > 5 && word.EndsWith("ing", StringComparison.Ordinal)) - { - var b = word[..^3]; // editing → edit, scrolling → scroll - yield return b; - yield return b + "e"; // closing → close, sharing → share - if (b.Length >= 2 && b[^1] == b[^2]) // dragging → dragg → drag - yield return b[..^1]; - } - else if (word.Length > 4 && word.EndsWith("ed", StringComparison.Ordinal)) - { - var b = word[..^2]; // edited → edit, scrolled → scroll - yield return b; - yield return word[..^1]; // themed → theme - if (b.Length >= 2 && b[^1] == b[^2]) // dropped → dropp → drop - yield return b[..^1]; - } - else if (word.Length > 3 && word.EndsWith("s", StringComparison.Ordinal) - && !word.EndsWith("ss", StringComparison.Ordinal)) - { - yield return word[..^1]; // tabs → tab, folders → folder - if (word.Length > 4 && word.EndsWith("es", StringComparison.Ordinal)) - yield return word[..^2]; // boxes → box - } - } - - /// - /// Manual exceptions to the algorithmic stemmer: words whose base form cannot be - /// derived by suffix stripping (e.g. "paginated" → "page", not "paginat"). - /// Keep this list small — most morphology is handled by . - /// - public static readonly Dictionary StemExceptions = new(StringComparer.OrdinalIgnoreCase) - { - ["paginated"] = ["page"], - ["paginating"] = ["page"], - ["paging"] = ["page"], - ["pages"] = ["page"], - ["tabbed"] = ["tab", "tabs"], // need both forms; "tabs" is in Map - }; - - /// - /// Append single-token equivalents for known multi-word phrases AND base forms - /// for inflected words, KEEPING the original words. So "file picker" becomes - /// tokens {file, picker, filepicker} and "tabbed editor" becomes {tabbed, editor, - /// tab, tabs, edit} — BM25 can match on either form. Synonym expansion still runs - /// after this step, so "tabs" → "tabview" via Map. - /// - public static string Preprocess(string query) - { - var lower = query.ToLowerInvariant(); - var sb = new System.Text.StringBuilder(lower); - foreach (var (phrase, replacement) in Phrases) - { - int searchFrom = 0; - while (true) - { - int idx = lower.IndexOf(phrase, searchFrom, StringComparison.Ordinal); - if (idx < 0) break; - searchFrom = idx + phrase.Length; - // Word-boundary check - bool leftOk = idx == 0 || !IsWordChar(lower[idx - 1]); - bool rightOk = searchFrom == lower.Length || !IsWordChar(lower[searchFrom]); - if (!leftOk || !rightOk) continue; - // Append the merged token instead of replacing — keeps both forms searchable - sb.Append(' ').Append(replacement); - } - } - - // Stemming: append base forms for inflected query words. Whole-word match on - // the lowercased original (we don't restem the appended phrase tokens — those - // are already canonical). Manual exceptions take precedence over the - // algorithmic stemmer for irregular cases (paginated → page, tabbed → tabs). - foreach (var word in lower.Split(WordSeparators, StringSplitOptions.RemoveEmptyEntries)) - { - if (StemExceptions.TryGetValue(word, out var bases)) - { - foreach (var b in bases) sb.Append(' ').Append(b); - } - else - { - foreach (var b in Stem(word)) sb.Append(' ').Append(b); - } - } - - return sb.ToString(); - } - - private static readonly char[] WordSeparators = [' ', '\t', '\n', '\r', ',', '.', ';', ':', '!', '?', '(', ')', '[', ']', '{', '}', '"', '\'']; - - private static bool IsWordChar(char c) => char.IsLetterOrDigit(c) || c == '_'; - - /// - /// Maps common cross-platform/cross-framework UI terms to WinUI 3 control names. - /// Used by SearchEngine to expand queries before BM25 scoring so agents - /// familiar with HTML/React/WPF/iOS terminology can still find the right controls. - /// All keys and values are lowercase. Lookup is case-insensitive. - /// - public static readonly Dictionary Map = new(StringComparer.OrdinalIgnoreCase) - { - // ─── Tables / lists ─── - ["datagrid"] = ["listview", "table", "rows", "columns"], - ["table"] = ["listview", "datagrid", "rows", "columns"], - ["spreadsheet"] = ["listview", "datagrid", "rows"], - - // ─── Dialogs / popups ─── - ["modal"] = ["contentdialog", "dialog"], - ["popup"] = ["flyout", "dialog", "teachingtip"], - ["prompt"] = ["contentdialog"], - ["actionsheet"] = ["contentdialog", "menuflyout"], - ["snackbar"] = ["infobar", "teachingtip"], - ["tooltip"] = ["tooltipservice", "teachingtip"], - - // ─── Navigation ─── - ["sidebar"] = ["navigationview", "splitview", "navigation"], - ["navbar"] = ["navigationview", "menubar"], - ["drawer"] = ["navigationview", "splitview"], - ["breadcrumbs"] = ["breadcrumbbar"], - ["crumbs"] = ["breadcrumbbar"], - - // ─── Tabs ─── - ["tabbar"] = ["selectorbar", "segmented"], - - // ─── Inputs ─── - ["select"] = ["combobox"], - ["picker"] = ["combobox", "calendarpicker", "datepicker", "timepicker"], - ["stepper"] = ["numberbox"], - ["radiogroup"] = ["radiobuttons"], - ["chip"] = ["tokenizingtextbox", "token"], - ["chips"] = ["tokenizingtextbox", "token"], - ["pill"] = ["tokenizingtextbox", "segmented"], - ["searchbox"] = ["autosuggestbox"], - ["typeahead"] = ["autosuggestbox"], - ["mention"] = ["richsuggestbox"], - ["hashtag"] = ["richsuggestbox"], - - // ─── Text ─── - ["textarea"] = ["textbox", "richeditbox"], - ["multiline"] = ["textbox", "richeditbox"], - ["wysiwyg"] = ["richeditbox"], - ["heading"] = ["textblock"], - ["link"] = ["hyperlinkbutton", "hyperlink"], - - // ─── Layout ─── - ["flex"] = ["stackpanel", "wrappanel", "grid"], - ["flexbox"] = ["stackpanel", "wrappanel"], - ["container"] = ["border", "grid", "stackpanel"], - ["divider"] = ["appbarseparator", "menubarseparator", "rectangle"], - ["resizable"] = ["gridsplitter", "contentsizer"], - ["wrap"] = ["wrappanel", "wraplayout"], - ["masonry"] = ["staggeredpanel", "staggeredlayout"], - - // ─── Scrolling / virtualization ─── - ["scrollview"] = ["scrollviewer"], - ["lazy"] = ["listview", "itemsrepeater"], - ["infinite"] = ["incrementalloadingcollection"], - - // ─── Tree / hierarchy ─── - ["folder"] = ["treeview"], - ["hierarchy"] = ["treeview"], - ["outline"] = ["treeview"], - - // ─── Progress / loading ─── - ["loading"] = ["progressring", "progressbar"], - ["loader"] = ["progressring", "progressbar"], - - // ─── Commands / buttons ─── - ["fab"] = ["button"], - ["iconbutton"] = ["button", "appbarbutton"], - ["ribbon"] = ["tabbedcommandbar"], - ["contextmenu"] = ["menuflyout"], - ["rightclick"] = ["menuflyout"], - - // ─── Media ─── - ["audio"] = ["mediaplayerelement"], - ["iframe"] = ["webview2"], - ["cropping"] = ["imagecropper"], - ["thumbnail"] = ["image"], - - // ─── Date / time / color ─── - - // ─── Settings / forms ─── - ["form"] = ["settingscard", "stackpanel"], - ["preferences"] = ["settingscard", "settingsexpander"], - ["options"] = ["settingscard", "combobox", "radiobuttons"], - - // ─── System / shell ─── - ["taskbar"] = ["jumplist", "appbadge"], - ["recent"] = ["jumplist"], - ["tray"] = ["systemtray"], - ["systemtray"] = ["system", "tray", "icon", "minimize"], - ["share"] = ["sharecontract"], - ["filepicker"] = ["file", "picker"], - ["openfile"] = ["filepicker"], - ["savefile"] = ["filepicker"], - ["dragdrop"] = ["drag", "drop"], - - // ─── Abbreviations ─── - ["btn"] = ["button"], - ["txt"] = ["textbox", "textblock"], - ["img"] = ["image"], - ["lv"] = ["listview"], - ["gv"] = ["gridview"], - - // ─── Plurals → singular alias to actual control ─── - ["buttons"] = ["button"], - ["lists"] = ["listview"], - ["dialogs"] = ["contentdialog"], - - // ─── Accessibility / screen reader / automation ─── - // Maps the various ways an agent may phrase a11y needs to the gallery - // sample controls that demonstrate them. Both `accessibilityscreenreader` - // (the controlId, indexed as one token) and `screenreader` / `accessibility` - // (separate tag tokens after CamelCase split) are useful targets. - ["a11y"] = ["accessibility", "screenreader", "accessibilityscreenreader"], - ["accessibility"] = ["accessibilityscreenreader", "accessibilitykeyboard", "screenreader", "accessible"], - ["accessible"] = ["accessibility", "screenreader", "accessibilityscreenreader"], - ["screenreader"] = ["accessibilityscreenreader", "accessibility", "screen", "reader"], - ["narrator"] = ["accessibilityscreenreader", "screenreader", "accessibility"], - ["automationproperties"] = ["accessibilityscreenreader", "screenreader", "accessibility", "automation", "name"], - ["automationid"] = ["accessibilityscreenreader", "screenreader", "accessibility", "automation"], - ["liveregion"] = ["accessibilityscreenreader", "screenreader", "accessibility"], - }; - - /// - /// Expand a tokenized query by appending synonyms for each known term. - /// Returns the original tokens plus any synonym tokens. - /// - /// Compound-suffix guard: if the query already contains a more-specific compound - /// ending with the current token (e.g. "file picker" → tokens [file, picker, filepicker]), - /// we skip synonym expansion for the bare token. The compound form already pins - /// the user's intent; expanding the bare suffix would pull in unrelated controls - /// (e.g. "picker" → ComboBox/DatePicker/TimePicker, which all dilute "file picker" - /// when the user clearly wants the file picker pattern). - /// - public static string[] Expand(string[] queryWords) - { - var result = new List(queryWords); - var seen = new HashSet(queryWords, StringComparer.OrdinalIgnoreCase); - var queryWordSet = new HashSet(queryWords, StringComparer.OrdinalIgnoreCase); - foreach (var w in queryWords) - { - if (Map.TryGetValue(w, out var syns)) - { - bool hasCompoundParent = queryWordSet.Any(other => - other.Length > w.Length && other.EndsWith(w, StringComparison.OrdinalIgnoreCase)); - if (hasCompoundParent) continue; - - foreach (var s in syns) - { - if (seen.Add(s)) result.Add(s); - } - } - } - return result.ToArray(); - } -} diff --git a/src/tools/winui-search/ToolkitFetcher.cs b/src/tools/winui-search/ToolkitFetcher.cs deleted file mode 100644 index 9ab4f4fc..00000000 --- a/src/tools/winui-search/ToolkitFetcher.cs +++ /dev/null @@ -1,1026 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using System.Net.Http; -using System.Text.Json; -using System.Text.RegularExpressions; - -internal static partial class ToolkitFetcher -{ - private const string TreeApiUrl = - "https://api.github.com/repos/CommunityToolkit/Windows/git/trees/main?recursive=1"; - private const string RawBase = - "https://raw.githubusercontent.com/CommunityToolkit/Windows/main/"; - - private static readonly HttpClient Http = new() - { - DefaultRequestHeaders = { { "User-Agent", "winui-search/1.0" } }, - Timeout = TimeSpan.FromSeconds(30) - }; - - private const int MaxXamlChars = 1000; - private const int MaxCSharpChars = 2500; - - /// Components/samples that aren't visual controls — skip them. - private static readonly HashSet SkippedComponents = new(StringComparer.OrdinalIgnoreCase) - { - "Triggers", "Converters", "Behaviors", "Extensions", "Helpers", - "Media", "DeveloperTools", "Animations", "CameraPreview", - "LayoutTransformControl" - }; - - /// Sample-file → (controlId, controlName) overrides. Falls back to derived name. - private static readonly Dictionary SampleOverrides = - new(StringComparer.OrdinalIgnoreCase) - { - // SettingsControls - ["SettingsCardSample"] = ("settingscard", "SettingsCard"), - ["ClickableSettingsCardSample"] = ("settingscard", "SettingsCard"), - ["SettingsExpanderSample"] = ("settingsexpander", "SettingsExpander"), - ["SettingsExpanderDragHandleSample"] = ("settingsexpander", "SettingsExpander"), - ["SettingsExpanderItemsSourceSample"] = ("settingsexpander", "SettingsExpander"), - ["SettingsPageExample"] = ("settingscard", "SettingsCard"), - // Sizers - ["ContentSizerLeftShelfPage"] = ("contentsizer", "ContentSizer"), - ["ContentSizerTopShelfPage"] = ("contentsizer", "ContentSizer"), - ["GridSplitterPage"] = ("gridsplitter", "GridSplitter"), - ["PropertySizerNavigationViewPage"] = ("propertysizer", "PropertySizer"), - ["SizerCursorPage"] = ("contentsizer", "ContentSizer"), - // Segmented - ["SegmentedBasicSample"] = ("segmented", "Segmented"), - ["SegmentedStylesSample"] = ("segmented", "Segmented"), - ["SegmentedSwitchPresenterSample"] = ("segmented", "Segmented"), - // HeaderedControls - ["HeaderedContentControlSample"] = ("headeredcontentcontrol", "HeaderedContentControl"), - ["HeaderedContentControlComplexSample"] = ("headeredcontentcontrol", "HeaderedContentControl"), - ["HeaderedContentControlImageSample"] = ("headeredcontentcontrol", "HeaderedContentControl"), - ["HeaderedContentControlTextSample"] = ("headeredcontentcontrol", "HeaderedContentControl"), - ["HeaderedItemsControlSample"] = ("headereditemscontrol", "HeaderedItemsControl"), - ["HeaderedTreeViewSample"] = ("headeredtreeview", "HeaderedTreeView"), - // Collections - ["AdvancedCollectionViewSample"] = ("advancedcollectionview", "AdvancedCollectionView"), - ["IncrementalLoadingCollectionSample"] = ("incrementalloadingcollection", "IncrementalLoadingCollection"), - // ColorPicker - ["ColorPickerSample"] = ("colorpicker", "ColorPicker"), - ["ColorPickerButtonSample"] = ("colorpickerbutton", "ColorPickerButton"), - // ImageCropper - ["ImageCropperSample"] = ("imagecropper", "ImageCropper"), - ["ImageCropperOverlaySample"] = ("imagecropper", "ImageCropper"), - // RichSuggestBox - ["RichSuggestBoxPlainText"] = ("richsuggestbox", "RichSuggestBox"), - ["RichSuggestBoxMultiplePrefixesSample"] = ("richsuggestbox", "RichSuggestBox"), - // Primitives - ["DockPanelSample"] = ("dockpanel", "DockPanel"), - ["StaggeredLayoutSample"] = ("staggeredlayout", "StaggeredLayout"), - ["StaggeredPanelSample"] = ("staggeredpanel", "StaggeredPanel"), - ["UniformGridSample"] = ("uniformgrid", "UniformGrid"), - ["WrapLayoutSample"] = ("wraplayout", "WrapLayout"), - ["WrapPanelSample"] = ("wrappanel", "WrapPanel"), - }; - - /// - /// Default xmlns declarations for visual controls. The "controls" prefix is virtually - /// always needed; "ui" is added when a sample's XAML actually references it. - /// - private const string XmlnsControls = "xmlns:controls=\"using:CommunityToolkit.WinUI.Controls\""; - private const string XmlnsUi = "xmlns:ui=\"using:CommunityToolkit.WinUI\""; - private const string XmlnsAnimations = "xmlns:animations=\"using:CommunityToolkit.WinUI.Animations\""; - private const string XmlnsBehaviors = "xmlns:behaviors=\"using:CommunityToolkit.WinUI.Behaviors\""; - private const string XmlnsConverters = "xmlns:converters=\"using:CommunityToolkit.WinUI.Converters\""; - - /// - /// Scan a XAML body for which Toolkit-related xmlns prefixes are actually used, - /// so we only emit the namespaces an agent really needs to add. - /// - private static string[] DetectXmlnsImports(string xaml) - { - var imports = new List(); - // controls is always required for any toolkit sample we keep - imports.Add(XmlnsControls); - if (UsesPrefix(xaml, "ui")) imports.Add(XmlnsUi); - if (UsesPrefix(xaml, "animations")) imports.Add(XmlnsAnimations); - if (UsesPrefix(xaml, "behaviors")) imports.Add(XmlnsBehaviors); - if (UsesPrefix(xaml, "converters")) imports.Add(XmlnsConverters); - return imports.ToArray(); - } - - private static bool UsesPrefix(string xaml, string prefix) - { - // Match either an element start `Markdown filename → controlId for tag generation. - private static readonly Dictionary MdControlMap = - new(StringComparer.OrdinalIgnoreCase) - { - ["SettingsCard.md"] = "settingscard", - ["SettingsExpander.md"] = "settingsexpander", - ["ContentSizer.md"] = "contentsizer", - ["GridSplitter.md"] = "gridsplitter", - ["PropertySizer.md"] = "propertysizer", - ["SizerControls.md"] = null, - ["ConstrainedBox.md"] = "constrainedbox", - ["DockPanel.md"] = "dockpanel", - ["StaggeredLayout.md"] = "staggeredlayout", - ["StaggeredPanel.md"] = "staggeredpanel", - ["SwitchPresenter.md"] = "switchpresenter", - ["UniformGrid.md"] = "uniformgrid", - ["WrapLayout.md"] = "wraplayout", - ["WrapPanel.md"] = "wrappanel", - ["AdvancedCollectionView.md"] = "advancedcollectionview", - ["IncrementalLoadingCollection.md"] = "incrementalloadingcollection", - ["ColorPicker.md"] = "colorpicker", - ["HeaderedContentControl.md"] = "headeredcontentcontrol", - ["HeaderedItemsControl.md"] = "headereditemscontrol", - ["HeaderedTreeView.md"] = "headeredtreeview", - ["ImageCropper.md"] = "imagecropper", - ["MetadataControl.md"] = "metadatacontrol", - ["RadialGauge.md"] = "radialgauge", - ["RangeSelector.md"] = "rangeselector", - ["RichSuggestBox.md"] = "richsuggestbox", - ["Segmented.md"] = "segmented", - ["TabbedCommandBar.md"] = "tabbedcommandbar", - ["TokenizingTextBox.md"] = "tokenizingtextbox", - }; - - // Stop words come from shared StopWords.Common - - /// Embedded snapshot baked into the exe at build time — the offline - /// fallback served when the on-disk cache is missing or stale. - internal static (Scenario[] scenarios, Dictionary tags, Dictionary keywords) LoadEmbedded() - => (DataLoader.LoadToolkitScenarios(), - global::StopWords.CleanTagDictionary(DataLoader.LoadToolkitTags()), - DataLoader.LoadToolkitKeywords()); - - /// Fetch fresh scenarios, tags, and keywords from GitHub (used by - /// the `update` command). Tags are stop-word-cleaned before return. - internal static async Task<(Scenario[] scenarios, Dictionary tags, Dictionary keywords)> FetchAsync() - { - var (scenarios, tags, keywords) = await FetchFromGitHub(); - if (scenarios.Length > 0) tags = global::StopWords.CleanTagDictionary(tags); - return (scenarios, tags, keywords); - } - - private static async Task<(Scenario[], Dictionary, Dictionary)> FetchFromGitHub() - { - // Step 1: Get full file tree - var treeJson = await Http.GetStringAsync(TreeApiUrl); - using var doc = JsonDocument.Parse(treeJson); - var tree = doc.RootElement.GetProperty("tree"); - - var xamlSamples = new List(); // paths like components/X/samples/Y.xaml - var mdDocs = new List(); // paths like components/X/samples/Y.md - - // Auto-discover NuGet package names from components//src/.csproj. - // The csproj filename equals the canonical NuGet package id for every component. - var nugetByComponent = new Dictionary(StringComparer.OrdinalIgnoreCase); - - foreach (var entry in tree.EnumerateArray()) - { - var path = entry.GetProperty("path").GetString() ?? ""; - if (!path.StartsWith("components/", StringComparison.Ordinal)) continue; - var parts = path.Split('/'); - - // components//src/.csproj → package mapping - if (parts.Length == 4 && parts[2].Equals("src", StringComparison.OrdinalIgnoreCase) - && parts[3].EndsWith(".csproj", StringComparison.OrdinalIgnoreCase)) - { - nugetByComponent[parts[1]] = parts[3][..^".csproj".Length]; - continue; - } - - // components//samples/ → sample / md - if (parts.Length != 4 || !parts[2].Equals("samples", StringComparison.OrdinalIgnoreCase)) continue; - if (SkippedComponents.Contains(parts[1])) continue; - - var file = parts[3]; - if (file.EndsWith(".xaml", StringComparison.OrdinalIgnoreCase) && - !file.EndsWith(".xaml.cs", StringComparison.OrdinalIgnoreCase)) - { - xamlSamples.Add(path); - } - else if (file.EndsWith(".md", StringComparison.OrdinalIgnoreCase)) - { - mdDocs.Add(path); - } - } - - // Sort sample / md paths so downstream processing (and the per-control - // renumbering below) is deterministic regardless of GitHub tree ordering. - xamlSamples.Sort(StringComparer.OrdinalIgnoreCase); - mdDocs.Sort(StringComparer.OrdinalIgnoreCase); - - // Step 2: Fetch all md docs FIRST (parallel) — gives us tags + descriptions - // before processing samples, so each scenario can be enriched with prose. - var sem = new SemaphoreSlim(10); - var mdTasks = mdDocs.Select(p => FetchMdAsync(p, sem)).ToArray(); - var mdResults = await Task.WhenAll(mdTasks); - var tags = new Dictionary(); - var keywords = new Dictionary(); - var controlDescByCid = new Dictionary(StringComparer.OrdinalIgnoreCase); - var sampleDescByName = new Dictionary(StringComparer.OrdinalIgnoreCase); - foreach (var md in mdResults) - { - if (md.ControlId != null && md.Tags != null) tags[md.ControlId] = md.Tags; - if (md.ControlId != null && md.Keywords != null && md.Keywords.Length > 0) - keywords[md.ControlId] = md.Keywords; - if (md.ControlId != null && md.ControlDescription != null) - controlDescByCid[md.ControlId] = md.ControlDescription; - if (md.SampleDescriptions != null) - { - foreach (var (k, v) in md.SampleDescriptions) sampleDescByName[k] = v; - } - } - // ColorPickerButton has no separate md - if (tags.ContainsKey("colorpicker") && !tags.ContainsKey("colorpickerbutton")) - { - tags["colorpickerbutton"] = ["colorpickerbutton","color","picker","button","dropdown","communitytoolkit"]; - } - if (keywords.ContainsKey("colorpicker") && !keywords.ContainsKey("colorpickerbutton")) - { - keywords["colorpickerbutton"] = keywords["colorpicker"]; - } - if (controlDescByCid.TryGetValue("colorpicker", out var cpDesc) && !controlDescByCid.ContainsKey("colorpickerbutton")) - { - controlDescByCid["colorpickerbutton"] = cpDesc; - } - - // Step 3: Fetch all sample XAML + C# (parallel) — pass NuGet map and description - // maps down so each FetchSampleAsync can stamp packaging + prose on its scenarios. - var sampleTasks = xamlSamples.Select(p => FetchSampleAsync(p, sem, nugetByComponent, controlDescByCid, sampleDescByName)).ToArray(); - var sampleResults = await Task.WhenAll(sampleTasks); - var allScenarios = sampleResults.Where(s => s != null).SelectMany(s => s!).ToArray(); - - // Renumber scenario IDs per controlId to {controlId}-{N} (1-indexed) for - // a uniform short ID scheme across Gallery and Toolkit. Order follows the - // sample-path sort above (Task.WhenAll + SelectMany + GroupBy all preserve - // input order), so {controlId}-{N} is stable across fetches as long as - // the underlying sample file paths don't change. - var byControl = allScenarios - .GroupBy(s => s.ControlId, StringComparer.OrdinalIgnoreCase); - foreach (var grp in byControl) - { - var idx = 0; - foreach (var s in grp) - { - idx++; - s.Id = $"{grp.Key}-{idx}"; - } - } - - return (allScenarios, tags, keywords); - } - - private static async Task?> FetchSampleAsync( - string path, - SemaphoreSlim sem, - Dictionary nugetByComponent, - Dictionary controlDescByCid, - Dictionary sampleDescByName) - { - await sem.WaitAsync(); - try - { - var sampleName = Path.GetFileNameWithoutExtension(path); - var componentName = path.Split('/')[1]; - - var (controlId, controlName) = GetControlInfo(componentName, sampleName); - - var xamlText = await TryGetString(RawBase + path); - if (xamlText == null) return null; - - var csPath = path + ".cs"; - var csText = await TryGetString(RawBase + csPath) ?? ""; - - // Strip Page wrapper from XAML - var pageContent = ExtractPageContent(xamlText); - var cleanedXaml = CleanXaml(pageContent); - - // Try splitting StackPanel children - var splits = SplitStackPanelChildren(cleanedXaml, controlName); - - var scenarios = new List(); - - // NuGet package id is auto-discovered from the component's src/*.csproj filename. - // xmlns is auto-detected from which prefixes the cleaned XAML actually references. - var nuget = nugetByComponent.TryGetValue(componentName, out var pkg) - ? pkg - : "CommunityToolkit.WinUI"; - var xmlns = DetectXmlnsImports(cleanedXaml); - - // Look up descriptions: prefer the per-sample paragraph from the .md (most specific), - // fall back to the control-level frontmatter description. - string? controlDesc = controlDescByCid.TryGetValue(controlId, out var cd) ? cd : null; - string? sampleDesc = sampleDescByName.TryGetValue(sampleName, out var sd) ? sd : null; - - if (splits.Count > 1) - { - // Multiple instances → split each into its own scenario. - // All splits come from the same sample file, so they share its description - // (from the .md preceding [!SAMPLE PageName]). Fall back to the per-sample - // XAML attribute when no .md paragraph is present; - // this avoids the previous behaviour of jamming Header + Description into - // one string and then ALSO appending the .md paragraph (visible duplication). - foreach (var (slugLabel, label, xamlDesc, xml) in splits) - { - var sid = MakeScenarioId(controlId, slugLabel); - scenarios.Add(new Scenario - { - Id = sid, - ControlId = controlId, - ControlName = controlName, - HeaderText = label, - Xaml = xml, - CSharp = null, - Source = "toolkit", - NuGetPackage = nuget, - XmlnsImports = xmlns, - Description = sampleDesc ?? xamlDesc, - ControlDescription = controlDesc, - }); - } - } - else - { - // Single sample - var friendly = DeriveFriendlyName(sampleName, controlName); - if (string.IsNullOrEmpty(friendly)) friendly = "Basic usage"; - var sid = MakeScenarioId(controlId, friendly); - var cs = IsEmptyCodeBehind(csText) ? "" : CleanCSharp(csText, sampleName); - - // Smart truncation: if the cleaned XAML is too big, try to extract just - // the core element(s) so we don't lose the actual usage. - var xamlOut = cleanedXaml; - if (xamlOut.Length > MaxXamlChars) - { - var focused = ExtractCoreControl(xamlOut, controlName); - if (focused != null) xamlOut = focused; - } - xamlOut = TruncateXaml(xamlOut, MaxXamlChars); - - scenarios.Add(new Scenario - { - Id = sid, - ControlId = controlId, - ControlName = controlName, - HeaderText = friendly, - Xaml = xamlOut, - CSharp = string.IsNullOrEmpty(cs) ? null : TruncateCSharp(cs, MaxCSharpChars), - Source = "toolkit", - NuGetPackage = nuget, - XmlnsImports = xmlns, - Description = sampleDesc, - ControlDescription = controlDesc, - }); - } - - return scenarios; - } - catch { return null; } - finally { sem.Release(); } - } - - /// Per-.md aggregated extract: tags (mapped only) + descriptions (frontmatter + per-sample). - private sealed record MdData( - string? ControlId, - string[]? Tags, - string[]? Keywords, - string? ControlDescription, - Dictionary? SampleDescriptions); - - private static async Task FetchMdAsync(string path, SemaphoreSlim sem) - { - await sem.WaitAsync(); - try - { - var fileName = Path.GetFileName(path); - var text = await TryGetString(RawBase + path); - if (text == null) return new MdData(null, null, null, null, null); - - // Normalize newlines once: downstream parsers (ParseFrontmatter, - // ExtractSampleDescriptions, ExtractTags) split on "\n" / "\n\n", - // which breaks on CRLF. Toolkit repo is LF today but raw bytes - // could change; fix at the source. - text = text.Replace("\r\n", "\n").Replace('\r', '\n'); - - // Frontmatter description (control-level intro, e.g. "The ContentSizer is a control...") - var fm = ParseFrontmatter(text); - string? controlDesc = null; - if (fm.TryGetValue("description", out var d) && !string.IsNullOrWhiteSpace(d)) - controlDesc = CleanProse(d); - - // Per-sample description: paragraph immediately preceding each [!SAMPLE PageName] marker - var sampleDescs = ExtractSampleDescriptions(text); - - // Tags + curated keywords only for .md files explicitly mapped to a controlId - string? cid = null; - string[]? tags = null; - string[]? keywords = null; - if (MdControlMap.TryGetValue(fileName, out var mapped) && mapped != null) - { - cid = mapped; - tags = ExtractTags(text, mapped); - keywords = ExtractKeywords(text); - } - - return new MdData(cid, tags, keywords, controlDesc, sampleDescs); - } - catch { return new MdData(null, null, null, null, null); } - finally { sem.Release(); } - } - - /// Parse `> [!SAMPLE PageName]` markers and grab the text between this marker - /// and the previous SAMPLE / section header / doc start (whichever is closest), filtered - /// to non-header / non-blockquote prose. Section-header boundaries keep multi-section - /// overview .md files (like SizerControls.md) from polluting per-sample descriptions. - private static Dictionary ExtractSampleDescriptions(string md) - { - var result = new Dictionary(StringComparer.OrdinalIgnoreCase); - // Strip frontmatter - var body = Regex.Replace(md, @"^---\s*\n.*?\n---\s*", "", RegexOptions.Singleline); - var matches = Regex.Matches(body, @">\s*\[!SAMPLE\s+(\w+)\]", RegexOptions.IgnoreCase); - int lastEnd = 0; - foreach (Match m in matches) - { - var name = m.Groups[1].Value; - var preceding = body.Substring(lastEnd, m.Index - lastEnd); - // Take paragraphs since most recent section header (## or deeper) — keeps - // descriptions scoped to the local section in multi-section overview docs. - var paras = preceding.Split(new[] { "\n\n" }, StringSplitOptions.RemoveEmptyEntries) - .Select(p => p.Trim()) - .Where(p => !string.IsNullOrEmpty(p)) - .ToList(); - int sectionStart = 0; - for (int i = paras.Count - 1; i >= 0; i--) - { - if (paras[i].StartsWith("#")) { sectionStart = i + 1; break; } - } - var local = paras.Skip(sectionStart) - .Where(p => !p.StartsWith("#") && !p.StartsWith(">")) // strip headers / blockquotes - .ToArray(); - if (local.Length > 0) - { - var clean = CleanProse(string.Join(" ", local)); - if (clean.Length > 10) result[name] = clean; - } - lastEnd = m.Index + m.Length; - } - return result; - } - - /// Strip markdown noise (links, inline code) and collapse whitespace; cap at ~240 chars. - private static string CleanProse(string text) - { - var s = Regex.Replace(text, @"\[([^\]]+)\]\([^)]+\)", "$1"); // [text](link) → text - s = Regex.Replace(s, @"`([^`]+)`", "$1"); // `code` → code - s = Regex.Replace(s, @"\s+", " ").Trim(); - if (s.Length > 240) - { - int dot = s.IndexOf('.', 100); - s = (dot > 0 && dot < 240) ? s.Substring(0, dot + 1) : s.Substring(0, 237) + "..."; - } - return s; - } - - private static async Task TryGetString(string url) - { - try - { - var resp = await Http.GetAsync(url); - if (!resp.IsSuccessStatusCode) return null; - return await resp.Content.ReadAsStringAsync(); - } - catch { return null; } - } - - private static (string id, string name) GetControlInfo(string componentName, string sampleName) - { - if (SampleOverrides.TryGetValue(sampleName, out var hit)) return hit; - // Default: derive from component name - return (componentName.ToLowerInvariant(), componentName); - } - - [GeneratedRegex(@"]*>(.*)", RegexOptions.Singleline)] - private static partial Regex PageRegex(); - - private static string ExtractPageContent(string xaml) - { - // Remove license comment - xaml = Regex.Replace(xaml, @"\s*", "", RegexOptions.Singleline); - var m = PageRegex().Match(xaml); - return m.Success ? m.Groups[1].Value.Trim() : xaml; - } - - private static string CleanXaml(string xaml) - { - // Demo bindings + names - xaml = Regex.Replace(xaml, @"\s+IsEnabled=""\{x:Bind\s+\w+,\s*Mode=OneWay\}""", ""); - xaml = Regex.Replace(xaml, @"\s+IsExpanded=""\{x:Bind\s+\w+,\s*Mode=OneWay\}""", ""); - xaml = Regex.Replace(xaml, @"\s+x:Name=""\w+""", ""); - xaml = Regex.Replace(xaml, @"\s+AutomationProperties\.\w+=""[^""]*""", ""); - xaml = Regex.Replace(xaml, @"", "", RegexOptions.Singleline); - xaml = Regex.Replace(xaml, @"", "", RegexOptions.Singleline); - // Demo sizes - xaml = Regex.Replace(xaml, @"\s+(?:Min|Max)?Height=""\d+""", ""); - xaml = Regex.Replace(xaml, @"\s+(?:Min|Max)?Width=""\d+""", ""); - // Demo positioning / spacing on demo containers - xaml = Regex.Replace(xaml, @"\s+Padding=""\d+(?:,\d+)*""", ""); - xaml = Regex.Replace(xaml, @"\s+Margin=""[\d,\-]+""", ""); - xaml = Regex.Replace(xaml, @"\s+Spacing=""\d+""", ""); - // Demo defaults - xaml = Regex.Replace(xaml, @"\s+SelectedIndex=""\d+""", ""); - xaml = Regex.Replace(xaml, @"\s+(?:Horizontal|Vertical)Alignment=""(?:Stretch|Center|Top|Left)""", ""); - // Theme/system resource references — keep useful ones, drop generic CardStyle etc. - xaml = Regex.Replace(xaml, @"\s+Background=""\{ThemeResource\s+\w+\}""", ""); - xaml = Regex.Replace(xaml, @"\s+BorderBrush=""\{ThemeResource\s+\w+\}""", ""); - xaml = Regex.Replace(xaml, @"\s+BorderThickness=""[\d,]+""", ""); - xaml = Regex.Replace(xaml, @"\s+CornerRadius=""\d+""", ""); - xaml = Regex.Replace(xaml, @"\s+Style=""\{StaticResource\s+(?:CardStyle|EmployeeDataTemplate|EmailTemplate|StaggeredTemplate|PhotoTemplate|SuggestionTemplate)\}""", ""); - // Drop Page.Resources / Style / VisualStateManager / Resources blocks - xaml = Regex.Replace(xaml, @".*?\s*", "", RegexOptions.Singleline); - xaml = Regex.Replace(xaml, @"<\w+\.Resources>.*?\s*", "", RegexOptions.Singleline); - xaml = Regex.Replace(xaml, @".*?\s*", "", RegexOptions.Singleline); - // Drop standalone descriptive TextBlocks (Text > 60 chars, only Text attribute, no x:Bind) - xaml = Regex.Replace( - xaml, - @"\s*", - "", - RegexOptions.Singleline); - // Drop TextBlock with only Run children (descriptive Run blocks) - xaml = Regex.Replace( - xaml, - @"\s*(?:]*?(?:>[^<]*|/>)\s*){1,}\s*", - "", - RegexOptions.Singleline); - // Drop empty Border placeholders - xaml = Regex.Replace(xaml, @"]*?/>\s*", ""); - xaml = Regex.Replace(xaml, @"]*?>\s*\s*", ""); - // Drop empty Grid cells used as demo placeholders - xaml = Regex.Replace(xaml, @"]*?>\s*\s*", ""); - // Compress whitespace - var lines = xaml.Split('\n').Where(l => !string.IsNullOrWhiteSpace(l)); - return string.Join('\n', lines); - } - - /// - /// When a sample is too large, try to extract just the core control element(s) - /// (e.g., for a GridSplitterSample, find <controls:GridSplitter> blocks). - /// Returns the focused subset if found and shorter; otherwise returns null. - /// - private static string? ExtractCoreControl(string xaml, string controlName) - { - var name = Regex.Escape(controlName); - // Match self-closing or paired controls:Name elements - var selfClose = $@"]*/>"; - var paired = $@"]*?>[\s\S]*?"; - var matches = Regex.Matches(xaml, $@"({selfClose}|{paired})", RegexOptions.Singleline); - if (matches.Count == 0) return null; - - var sb = new System.Text.StringBuilder(); - foreach (Match m in matches) - { - sb.AppendLine(m.Value.Trim()); - sb.AppendLine(); - } - var focused = sb.ToString().TrimEnd(); - // Only use if it actually saves space (otherwise full context is better) - if (focused.Length < xaml.Length * 0.8) return focused; - return null; - } - - private static List<(string slugKey, string label, string? xamlDescription, string xaml)> SplitStackPanelChildren(string xaml, string targetControl) - { - var trimmed = xaml.TrimStart(); - if (!Regex.IsMatch(trimmed, @"^]")) return new(); - - var name = Regex.Escape(targetControl); - var pattern = $@"(]*/>|]*?>.*?)"; - var matches = Regex.Matches(xaml, pattern, RegexOptions.Singleline); - if (matches.Count <= 1) return new(); - - var results = new List<(string, string, string?, string)>(); - int i = 0; - foreach (Match m in matches) - { - i++; - var block = m.Groups[1].Value; - var open = Regex.Match(block, $@"|>)", RegexOptions.Singleline); - string? rawHeader = null; - string? rawDescription = null; - if (open.Success) - { - var attrs = open.Groups[1].Value; - var hm = Regex.Match(attrs, @"\bHeader=""([^""]*)"""); - var dm = Regex.Match(attrs, @"\bDescription=""([^""]*)"""); - if (hm.Success) rawHeader = hm.Groups[1].Value.Trim(); - if (dm.Success) rawDescription = dm.Groups[1].Value.Trim(); - } - // Pick a SHORT label for the URL slug (max 6 words from header or description). - string slugLabel = PickSlugLabel(rawHeader, rawDescription, targetControl, i); - // Header label: short, suitable as the row's "title" — falls back to description - // or "Example N" only when Header is missing/placeholder. - string label = BuildScenarioLabel(rawHeader, rawDescription, targetControl, i); - // XAML Description attribute kept separately so callers can use it as a - // fallback when the .md doesn't have a per-sample paragraph; truncated to - // ~120 chars for display. - string? xamlDesc = TrimDescription(rawDescription); - results.Add((slugLabel, label, xamlDesc, block.Trim())); - } - return results; - } - - /// - /// Pick the short label used to build the URL slug. Avoid slugs longer than ~6 words. - /// - private static string PickSlugLabel(string? header, string? description, string controlName, int index) - { - // Prefer header if it's not a placeholder - if (!IsPlaceholderHeader(header, controlName)) - return TruncateWords(header!, 6); - // Otherwise use the first few words of the description - if (!string.IsNullOrWhiteSpace(description) && !IsPlaceholderHeader(description, controlName)) - return TruncateWords(description!, 6); - // Last resort: index - return $"example-{index}"; - } - - private static string TruncateWords(string text, int maxWords) - { - var words = text.Split(' ', StringSplitOptions.RemoveEmptyEntries); - if (words.Length <= maxWords) return text; - return string.Join(' ', words.Take(maxWords)); - } - - /// - /// Pick a SHORT label for the row (typically the Sample's Header attribute). - /// Falls back to a truncated Description / "Example N" when Header is a - /// generic placeholder. The XAML Description attribute is NOT concatenated - /// here — callers keep it separately so it can be presented (or replaced - /// by a richer .md paragraph) without duplicating the label. - /// - private static string BuildScenarioLabel(string? header, string? description, string controlName, int index) - { - if (!IsPlaceholderHeader(header, controlName)) return header!; - var desc = TrimDescription(description); - if (!string.IsNullOrEmpty(desc)) return desc!; - return $"Example {index}"; - } - - /// Cap a Description attribute at the first sentence under ~120 chars. - private static string? TrimDescription(string? description) - { - var d = description?.Trim(); - if (string.IsNullOrWhiteSpace(d)) return null; - if (d!.Length <= 120) return d; - int dot = d.IndexOf('.', 60); - return (dot > 0 && dot < 120) ? d.Substring(0, dot + 1) : d.Substring(0, 117) + "..."; - } - - /// - /// Return true if a Header attribute is a generic demo placeholder (not informative). - /// - private static bool IsPlaceholderHeader(string? header, string controlName) - { - if (string.IsNullOrWhiteSpace(header)) return true; - var h = header.Trim(); - var hNorm = Regex.Replace(h.ToLowerInvariant(), @"[^a-z0-9]", ""); - var cNorm = Regex.Replace(controlName.ToLowerInvariant(), @"[^a-z0-9]", ""); - // Identical / "X control" / "X sample" - if (hNorm == cNorm) return true; - if (hNorm == cNorm + "control" || hNorm == cNorm + "sample") return true; - // Generic single-word "Header" or "Sample" - if (h.Equals("Header", StringComparison.OrdinalIgnoreCase)) return true; - // "Example N" / "Sample N" - if (Regex.IsMatch(h, @"^Example\s*\d*$", RegexOptions.IgnoreCase)) return true; - if (Regex.IsMatch(h, @"^Sample\s*\d*$", RegexOptions.IgnoreCase)) return true; - // Specific demo placeholders ("This is the Header", "This is a Header", etc.) - // — keep narrow so real descriptions starting with "This is..." aren't dropped. - if (Regex.IsMatch(h, @"^This is (the|a|an) (Header|Description|Sample|Example|Control|Card)\b", RegexOptions.IgnoreCase)) return true; - return false; - } - - private static string DeriveFriendlyName(string sampleName, string controlName) - { - var name = sampleName; - if (name.EndsWith("Sample", StringComparison.Ordinal)) name = name[..^"Sample".Length]; - if (name.EndsWith("Page", StringComparison.Ordinal)) name = name[..^"Page".Length]; - // Strip control name prefix BEFORE spacing, so "ColorPickerSample" → "ColorPicker" → "" - var bare = controlName.Replace(" ", ""); - if (name.StartsWith(bare, StringComparison.OrdinalIgnoreCase)) - name = name[bare.Length..]; - // If nothing distinctive remains, call it "Basic usage" (don't echo the control name). - if (string.IsNullOrEmpty(name)) return "Basic usage"; - // Insert spaces before uppercase letters for readability - name = Regex.Replace(name, @"(?<=[a-z])(?=[A-Z])", " "); - return name.Trim(); - } - - private static bool IsEmptyCodeBehind(string cs) - { - var stripped = cs.Trim(); - if (string.IsNullOrEmpty(stripped)) return true; - var s = Regex.Replace(stripped, @"namespace\s+\S+;?\s*", ""); - s = Regex.Replace(s, @"(?:public\s+)?sealed\s+partial\s+class\s+\w+\s*:\s*Page\s*\{", ""); - s = Regex.Replace(s, @"public\s+\w+\(\)\s*\{\s*this\.InitializeComponent\(\);\s*\}", ""); - s = Regex.Replace(s, @"[{}]", "").Trim(); - return s.Length < 20; - } - - private static string CleanCSharp(string cs, string sampleName) - { - // License header - cs = Regex.Replace(cs, @"^//\s*Licensed to.*?(?=\n[^/])", "", RegexOptions.Singleline); - cs = Regex.Replace(cs, @"^//\s*The \.NET Foundation.*?\n", "", RegexOptions.Multiline); - cs = Regex.Replace(cs, @"^//\s*See the LICENSE.*?\n", "", RegexOptions.Multiline); - // Fold platform #if/#else/#endif: agents target WinAppSDK, so keep only the - // WINAPPSDK branch and discard UWP/Uno fallbacks. Done before the rest of the - // cleanup so we don't waste work on text that's about to be stripped. - cs = FoldPreprocessorDirectives(cs); - // [ToolkitSample(...)] and related docs-build attributes (single-line + multi-line, balanced brackets) - cs = Regex.Replace(cs, @"\[Toolkit(?:Sample|SampleOptionsPane|SampleMultiChoiceOption|SampleNumericOption|SampleBoolOption|SampleTextOption)\b[^\]]*\][\r\n]*", "", RegexOptions.Singleline); - cs = Regex.Replace(cs, @"\[SuppressMessage[^\]]*\][\r\n]*", "", RegexOptions.Singleline); - // Original namespace declaration → replace with placeholder so the class wrapper compiles - cs = Regex.Replace(cs, @"namespace\s+[\w.]+\s*(?:;|\{)\s*", "namespace YourApp;\n\n"); - // Rename the sample class to a clearer placeholder name so agents know to rename - if (!string.IsNullOrEmpty(sampleName)) - { - cs = Regex.Replace(cs, - $@"\b{Regex.Escape(sampleName)}\b", - "YourPage"); - } - // Drop docs-only converter helpers (back the [ToolkitSample*Option] attributes we just stripped). - // Pattern: `public static T ConvertStringTo(string ...) => ... switch { ... };` — single statement - // followed by a switch expression body. These only exist to wire up the docs option pane. - cs = Regex.Replace(cs, - @"public\s+static\s+[\w?<>]+\s+ConvertString\w+\s*\([^)]*\)\s*=>\s*\w+\s+switch\s*\{[^}]*\}\s*;", - "", - RegexOptions.Singleline); - // Drop trailing blank lines - cs = Regex.Replace(cs, @"\n\s*\n\s*\n+", "\n\n"); - return cs.Trim(); - } - - /// - /// Compile-time preprocessor folding for toolkit samples. Agents target WinAppSDK, - /// so we evaluate #if WINAPPSDK as true (and HAS_UNO / WINUI2 / - /// UWP / NETFX_CORE as false), keep the live branch's lines, and drop - /// the directives + dead branches. Unknown symbols are treated as true (conservative: - /// keep code rather than silently delete it). Supports #if, #elif, - /// #else, #endif, single ! negation, and nested blocks. - /// - private static string FoldPreprocessorDirectives(string cs) - { - if (cs.IndexOf("#if", StringComparison.Ordinal) < 0) return cs; - - // Treat WinAppSDK-targeting symbols as true; UWP/Uno/legacy as false. - // Anything else: true (preserve code we don't recognize). - static bool Eval(string expr) - { - expr = expr.Trim(); - bool negate = false; - if (expr.StartsWith('!')) - { - negate = true; - expr = expr[1..].Trim(); - } - bool value = expr switch - { - "WINAPPSDK" or "WINUI3" or "NET" => true, - "HAS_UNO" or "WINUI2" or "UWP" or "NETFX_CORE" => false, - _ => true, - }; - return negate ? !value : value; - } - - var lines = cs.Replace("\r\n", "\n").Split('\n'); - var output = new List(lines.Length); - // Stack frame: (anyBranchTakenYet, currentlyEmittingThisBranch). - // Parent's emitting state is tracked separately via parentEmit. - var stack = new Stack<(bool taken, bool emit)>(); - - bool ParentEmitting() - { - foreach (var f in stack) - if (!f.emit) return false; - return true; - } - - foreach (var rawLine in lines) - { - var line = rawLine; - var trimmed = line.TrimStart(); - - if (trimmed.StartsWith("#if ", StringComparison.Ordinal) || trimmed == "#if") - { - var expr = trimmed.Length > 3 ? trimmed[3..].Trim() : ""; - bool parentEmit = ParentEmitting(); - bool take = parentEmit && Eval(expr); - stack.Push((take, take)); - continue; - } - if (trimmed.StartsWith("#elif ", StringComparison.Ordinal)) - { - if (stack.Count == 0) continue; // malformed, drop - var (taken, _) = stack.Pop(); - var expr = trimmed[5..].Trim(); - bool parentEmit = ParentEmitting(); - bool take = parentEmit && !taken && Eval(expr); - stack.Push((taken || take, take)); - continue; - } - if (trimmed.StartsWith("#else", StringComparison.Ordinal)) - { - if (stack.Count == 0) continue; - var (taken, _) = stack.Pop(); - bool parentEmit = ParentEmitting(); - bool take = parentEmit && !taken; - stack.Push((true, take)); - continue; - } - if (trimmed.StartsWith("#endif", StringComparison.Ordinal)) - { - if (stack.Count > 0) stack.Pop(); - continue; - } - - if (ParentEmitting()) output.Add(line); - } - - return string.Join('\n', output); - } - - [GeneratedRegex(@"<(/?)([A-Za-z_][\w:.\-]*)\b([^>]*?)(/?)>")] - private static partial Regex AnyTagRegex(); - - private static string TruncateXaml(string xaml, int maxChars) - { - bool needsTrunc = xaml.Length > maxChars; - string head; - if (needsTrunc) - { - int cut = maxChars; - while (cut > 0) - { - cut = xaml.LastIndexOf('>', cut - 1); - if (cut < 0) return ""; - cut += 1; - int lastLt = xaml.LastIndexOf('<', cut - 1); - int lastGt = xaml.LastIndexOf('>', cut - 1); - if (lastLt < lastGt) break; - cut = lastLt; - } - if (cut <= 0) return ""; - head = xaml.Substring(0, cut); - } - else - { - head = xaml; - } - - var stack = new Stack(); - bool sawMismatch = false; - foreach (Match m in AnyTagRegex().Matches(head)) - { - bool isClose = m.Groups[1].Value == "/"; - bool isSelf = m.Groups[4].Value == "/"; - string nm = m.Groups[2].Value; - if (isSelf) continue; - if (isClose) - { - if (stack.Count > 0 && stack.Peek() == nm) stack.Pop(); - else sawMismatch = true; - } - else - { - stack.Push(nm); - } - } - - if (!needsTrunc && stack.Count == 0 && !sawMismatch) return xaml; - - var sb = new System.Text.StringBuilder(head.TrimEnd()); - while (stack.Count > 0) sb.Append("'); - if (needsTrunc) sb.Append("\n"); - return sb.ToString(); - } - - private static string TruncateCSharp(string code, int maxChars) - { - if (code.Length <= maxChars) return code; - int cut = code.LastIndexOf('\n', maxChars - 1); - if (cut < 0) cut = maxChars; - return code.Substring(0, cut).TrimEnd() + "\n// ...truncated"; - } - - private static string MakeScenarioId(string controlId, string header) - { - var slug = Regex.Replace(header.ToLowerInvariant(), @"[^a-z0-9]+", "-").Trim('-'); - if (slug.Length > 50) slug = slug.Substring(0, 50).TrimEnd('-'); - return $"{controlId}-{slug}"; - } - - // ─── Markdown frontmatter / tag extraction ───────────────────────── - - /// - /// Extract author-curated keywords from the md frontmatter `keywords:` - /// comma-separated list. These are the highest-quality intent signal - /// available (hand-picked by toolkit authors) so they're surfaced as a - /// separate, higher-weighted BM25 field — distinct from auto-extracted - /// description tags which are noisier. Stop-word filtering still applies. - /// - private static string[] ExtractKeywords(string mdText) - { - var fm = ParseFrontmatter(mdText); - if (!fm.TryGetValue("keywords", out var raw) || string.IsNullOrWhiteSpace(raw)) - return []; - var list = new List(); - var seen = new HashSet(); - foreach (var k in raw.Split(',')) - { - var t = k.Trim().ToLowerInvariant(); - if (string.IsNullOrEmpty(t)) continue; - if (global::StopWords.IsTagNoise(t)) continue; - if (seen.Add(t)) list.Add(t); - } - return list.ToArray(); - } - - private static string[] ExtractTags(string mdText, string controlId) - { - var fm = ParseFrontmatter(mdText); - var tags = new List { controlId }; - - // Title → split CamelCase - if (fm.TryGetValue("title", out var title)) - { - foreach (Match m in Regex.Matches(title, @"[A-Z]?[a-z]+|[A-Z]+")) - { - var p = m.Value.ToLowerInvariant(); - if (p.Length >= 3 && !global::StopWords.IsTagNoise(p)) tags.Add(p); - } - } - // keywords (comma-separated) - if (fm.TryGetValue("keywords", out var keywords)) - { - foreach (var kw in keywords.Split(',')) - { - var t = kw.Trim().ToLowerInvariant(); - if (!string.IsNullOrEmpty(t) && !global::StopWords.IsTagNoise(t)) tags.Add(t); - } - } - // subcategory - if (fm.TryGetValue("subcategory", out var sub)) - { - var s = sub.Trim().ToLowerInvariant(); - if (!string.IsNullOrEmpty(s) && !global::StopWords.IsTagNoise(s)) tags.Add(s); - } - // Description text keywords - var descText = Regex.Replace(mdText, @"^---.*?---\s*", "", RegexOptions.Singleline); - var paras = descText.Trim().Split("\n\n").Take(2); - var desc = string.Join(' ', paras); - desc = Regex.Replace(desc, @"\[([^\]]+)\]\([^)]+\)", "$1"); // links - desc = Regex.Replace(desc, @"`[^`]+`", ""); // inline code - desc = Regex.Replace(desc, @"[>#*_\[\]]", ""); - var words = Regex.Matches(desc.ToLowerInvariant(), @"[a-z]{4,}"); - var seen = new HashSet(tags); - int descAdded = 0; - foreach (Match m in words) - { - if (descAdded >= 8) break; - var w = m.Value; - if (global::StopWords.IsTagNoise(w) || !seen.Add(w)) continue; - tags.Add(w); - descAdded++; - } - tags.Add("communitytoolkit"); - // Final dedup - var final = new List(); - var fseen = new HashSet(); - foreach (var t in tags) - { - if (fseen.Add(t)) final.Add(t); - } - return final.ToArray(); - } - - private static Dictionary ParseFrontmatter(string md) - { - var result = new Dictionary(StringComparer.OrdinalIgnoreCase); - var m = Regex.Match(md, @"^---\s*\n(.*?)\n---", RegexOptions.Singleline); - if (!m.Success) return result; - foreach (var line in m.Groups[1].Value.Split('\n')) - { - var trimmed = line.Trim(); - if (trimmed.StartsWith('-')) continue; - int colon = trimmed.IndexOf(':'); - if (colon <= 0) continue; - var key = trimmed.Substring(0, colon).Trim(); - var val = trimmed.Substring(colon + 1).Trim(); - result[key] = val; - } - return result; - } -} - - diff --git a/src/tools/winui-search/ToolkitProvider.cs b/src/tools/winui-search/ToolkitProvider.cs deleted file mode 100644 index 2d86b212..00000000 --- a/src/tools/winui-search/ToolkitProvider.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -/// -/// Windows Community Toolkit scenarios (CommunityToolkit/Windows). Parse -/// logic lives in . Toolkit cleans its tag -/// dictionary on write, so it re-cleans on cache read too. -/// -internal sealed class ToolkitProvider : CachedProviderBase -{ - public override string Id => "toolkit"; - public override string DisplayName => "CommunityToolkit"; - - protected override Dictionary NormalizeTagsOnRead( - Dictionary tags) => global::StopWords.CleanTagDictionary(tags); - - protected override ProviderData LoadEmbedded() - { - var (scenarios, tags, keywords) = ToolkitFetcher.LoadEmbedded(); - return new ProviderData(scenarios, tags, keywords); - } - - protected override async Task FetchAsync() - { - var (scenarios, tags, keywords) = await ToolkitFetcher.FetchAsync(); - return scenarios.Length > 0 - ? new ProviderData(scenarios, tags, keywords) - : ProviderData.Empty; - } -} diff --git a/src/tools/winui-search/winui-search.csproj b/src/tools/winui-search/winui-search.csproj deleted file mode 100644 index 0b97b0f5..00000000 --- a/src/tools/winui-search/winui-search.csproj +++ /dev/null @@ -1,34 +0,0 @@ - - - Exe - winui-search - net10.0 - enable - enable - true - true - - - Microsoft - Microsoft - winui-search - Native-AOT search over WinUI 3 Gallery, Windows Community Toolkit, and microsoft-ui-reactor scenarios with embedded snapshots and on-demand GitHub fetch. - © Microsoft Corporation. All rights reserved. - https://github.com/microsoft/win-dev-skills - git - https://github.com/microsoft/win-dev-skills - MIT - winui;winui3;windowsappsdk;gallery;communitytoolkit;reactor;search;aot - - - - - - - - - - - -