Remove legacy WPF app, flatten WinUI project to repo root, rename namespace
The repo carried two parallel UIs (WPF + WinUI) sharing Models/Services via
cross-directory Link includes. Now that WinUI is the only frontend, collapse
the structure so the WinUI project IS the repo root instead of a nested
sibling folder:
- Delete the WPF project entirely (App.xaml, MainWindow.xaml, csproj) and its
bin/obj output
- Move AmiReel.WinUI/* up to the repo root (App, MainWindow, MainPage,
DialogHelper, Assets, Package.appxmanifest, app.manifest, Properties,
.github/instructions, AGENTS.md) via git mv, preserving history
- Rename AmiReel.WinUI.csproj -> AmiReel.csproj; regenerate the solution as
AmiReel.slnx (the newer XML solution format) with a single project
- Rename namespace AmigaDB.VideoRenderer.{Models,Services} -> AmiReel.{...}
and AmiReel_WinUI -> AmiReel across all files, including the embedded
ffmpeg/ffprobe resource logical names in the csproj and ToolExtractor
- Models/ and Services/ no longer need the Link-based cross-directory
<Compile Include>; they're picked up by the SDK's default globbing now
that they live under the project directory
- Rename assets/ -> branding/ (source icon art) to avoid a case-insensitive
collision with Assets/ (packaged tile art) once both sit at repo root
- Merge the two .gitignore files into one; track the PublishProfiles pubxml
files instead of ignoring them (no secrets, and they keep publish
reproducible across machines) as branding, gitignore, etc.
- Simplify publish-win-x64.ps1 (drop the -Target Wpf/WinUI switch, there's
only one target now) and rewrite README.md to describe the single-project
layout, build/run/publish commands, and file structure
Verified: dotnet build succeeds for both AmiReel.csproj and AmiReel.slnx, and
the built exe launches and renders identically to before the move.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
---
|
||||
description: 'Accessibility requirements for interactive controls, keyboard navigation, screen readers, and contrast'
|
||||
applyTo: '**/*.cs, **/*.xaml'
|
||||
---
|
||||
|
||||
# Accessibility
|
||||
|
||||
These rules apply to **every UI change**. They are not optional add-ons.
|
||||
|
||||
---
|
||||
|
||||
## Rules
|
||||
|
||||
- **Every interactive control** must have an `AutomationProperties.Name` or `AutomationProperties.LabeledBy`.
|
||||
- Add a stable, unique `AutomationProperties.AutomationId` for controls targeted by UI automation tests (and for key interactive elements).
|
||||
- Use semantic XAML controls — prefer `Button`, `HyperlinkButton`, `ListView` over styled `Border`/`Grid` with click handlers.
|
||||
- Ensure **keyboard navigation** works for all features:
|
||||
- Logical tab order via `TabIndex`.
|
||||
- `AccessKey` bindings for frequently used actions.
|
||||
- `KeyboardAccelerator` for shortcut keys.
|
||||
- Maintain **minimum contrast ratios** (4.5:1 for normal text, 3:1 for large text) — test in High Contrast mode.
|
||||
- Support **screen readers** (Narrator / NVDA): test that all content is announced correctly.
|
||||
- Images must have `AutomationProperties.Name` describing the image purpose (or `AutomationProperties.AccessibilityView="Raw"` for decorative images).
|
||||
- Do not rely on colour alone to convey meaning — add icons, text, or patterns.
|
||||
|
||||
## Anti-patterns
|
||||
|
||||
- Clickable `TextBlock` or `Image` without `AutomationProperties`.
|
||||
- Custom controls that are not keyboard-focusable.
|
||||
- Using `Visibility.Collapsed` to "hide" content from screen readers (use `AccessibilityView` instead).
|
||||
|
||||
## Validation
|
||||
|
||||
- Build & register the MSIX package — see **Build, Run & Deploy** in `.github/agents/Agents.md`.
|
||||
- Test keyboard navigation: tab through every new/changed UI area.
|
||||
- Test High Contrast: switch to Windows High Contrast theme and verify readability.
|
||||
- Run Accessibility Insights for Windows on the app.
|
||||
|
||||
### Verification Checklist
|
||||
|
||||
- [ ] All interactive controls have `AutomationProperties.Name`
|
||||
- [ ] Keyboard navigation works for the changed area
|
||||
- [ ] Tested with High Contrast theme enabled
|
||||
- [ ] Tab through the entire UI with keyboard only.
|
||||
- [ ] Verify key interactive controls have stable, unique `AutomationProperties.AutomationId` values (especially controls used by UI automation tests).
|
||||
- [ ] Switch to Windows High Contrast theme and verify readability.
|
||||
- [ ] Run Narrator and verify all controls are announced correctly.
|
||||
- [ ] Run **Accessibility Insights for Windows** on the app.
|
||||
|
||||
## Must Read & Research
|
||||
|
||||
> **Agent Rule:** Before any accessibility-related change, you **must** fetch and review these references using `fetch_webpage`. Apply what you learn.
|
||||
|
||||
| # | Reference | When to consult |
|
||||
|---|---|---|
|
||||
| 1 | [Accessibility in WinUI](https://learn.microsoft.com/en-us/windows/apps/design/accessibility/accessibility) | Any UI change — verify accessibility approach |
|
||||
| 2 | [AutomationProperties](https://learn.microsoft.com/en-us/windows/apps/design/accessibility/basic-accessibility-information) | Adding or modifying interactive controls |
|
||||
| 3 | [Accessibility Insights](https://accessibilityinsights.io/docs/windows/overview/) | Testing tool — run before finalizing UI changes |
|
||||
| 4 | [Keyboard Accessibility](https://learn.microsoft.com/en-us/windows/apps/design/accessibility/keyboard-accessibility) | Adding navigation, focus management, or shortcut keys |
|
||||
| 5 | [High Contrast Themes](https://learn.microsoft.com/en-us/windows/apps/design/accessibility/high-contrast-themes) | Adding custom styles, colours, or theme resources |
|
||||
|
||||
|
||||
@@ -0,0 +1,170 @@
|
||||
---
|
||||
description: 'Static analysis, StyleCop, EditorConfig, naming conventions, and code cleanup rules'
|
||||
applyTo: '**/*.cs, **/*.editorconfig, **/stylecop.json'
|
||||
---
|
||||
|
||||
# Code Quality — Static Analysis, StyleCop & Code Cleanup
|
||||
|
||||
Maintain strict code quality through automated analysis and consistent style enforcement.
|
||||
|
||||
---
|
||||
|
||||
## 1. Static Analysis (Roslyn Analyzers)
|
||||
|
||||
### Required Analyzer Packages
|
||||
|
||||
Add these to the `.csproj` if not already present:
|
||||
|
||||
```xml
|
||||
<ItemGroup>
|
||||
<!-- Use the latest stable versions; do not hard-code version numbers in instructions -->
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="*" />
|
||||
<PackageReference Include="StyleCop.Analyzers" Version="*">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
```
|
||||
|
||||
### Analysis Configuration in `.csproj`
|
||||
|
||||
```xml
|
||||
<PropertyGroup>
|
||||
<EnableNETAnalyzers>true</EnableNETAnalyzers>
|
||||
<AnalysisLevel>latest-recommended</AnalysisLevel>
|
||||
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
|
||||
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
```
|
||||
|
||||
### Rule Enforcement
|
||||
|
||||
Follow **all** CA* (quality) and IDE* (code style) analyzer rules at their configured severity. Do not cherry-pick — obey every warning the analyzers report. When encountering a specific rule violation, fetch the corresponding documentation from the **Must Read & Research** references below to understand and apply the correct fix.
|
||||
|
||||
### `.editorconfig`
|
||||
|
||||
The project's `.editorconfig` in the solution root is the source of truth for code style. Obey all rules defined there. When creating or modifying `.editorconfig`, fetch the [EditorConfig Reference](https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/code-style-rule-options) for the full list of available settings.
|
||||
|
||||
Key project conventions enforced via `.editorconfig`:
|
||||
- Private fields use `_camelCase` prefix (SA1101 suppressed, SA1309 suppressed).
|
||||
- File-scoped namespaces are required.
|
||||
- `this.` qualification is not used.
|
||||
|
||||
---
|
||||
|
||||
## 2. StyleCop Rules
|
||||
|
||||
### StyleCop Configuration (`stylecop.json`)
|
||||
|
||||
Place this file in the project root alongside the `.csproj`:
|
||||
|
||||
```json
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json",
|
||||
"settings": {
|
||||
"documentationRules": {
|
||||
"companyName": "YourProjectName",
|
||||
"copyrightText": "Copyright (c) {companyName}. All rights reserved.",
|
||||
"xmlHeader": false,
|
||||
"documentInterfaces": true,
|
||||
"documentExposedElements": true,
|
||||
"documentInternalElements": false,
|
||||
"documentPrivateElements": false,
|
||||
"documentPrivateFields": false
|
||||
},
|
||||
"orderingRules": {
|
||||
"usingDirectivesPlacement": "outsideNamespace",
|
||||
"systemUsingDirectivesFirst": true
|
||||
},
|
||||
"layoutRules": {
|
||||
"newlineAtEndOfFile": "require"
|
||||
},
|
||||
"namingRules": {
|
||||
"allowCommonHungarianPrefixes": false
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Rule Enforcement
|
||||
|
||||
Follow **all** SA* (StyleCop) rules at their configured severity. When encountering a specific SA* violation, fetch the [StyleCop Rules Reference](https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/DOCUMENTATION.md) to understand the rule and apply the correct fix. Do not suppress rules without justification in a code comment.
|
||||
|
||||
---
|
||||
|
||||
## 3. Code Cleanup Rules (Always Enforced)
|
||||
|
||||
### After Every Edit
|
||||
|
||||
1. **Remove unused `using` statements** — No unused imports should remain.
|
||||
2. **Remove commented-out code** — Version control tracks history; dead code is noise.
|
||||
3. **Remove unused variables and fields** — If it's declared but never read, delete it.
|
||||
4. **Remove empty methods** — If an event handler or override does nothing, remove it.
|
||||
5. **Simplify code** — Apply IDE suggestions (IDE0001–IDE0090) for:
|
||||
- Removing unnecessary casts
|
||||
- Simplifying `default` expressions
|
||||
- Using pattern matching
|
||||
- Using null-coalescing operators
|
||||
|
||||
### Naming Conventions
|
||||
|
||||
| Element | Convention | Example |
|
||||
|---|---|---|
|
||||
| Class / Struct | PascalCase | `MainViewModel` |
|
||||
| Interface | I + PascalCase | `INavigationService` |
|
||||
| Public method | PascalCase | `LoadDataAsync()` |
|
||||
| Private method | PascalCase | `ValidateInput()` |
|
||||
| Public property | PascalCase | `CurrentPage` |
|
||||
| Private field | _camelCase | `_settingsService` |
|
||||
| Parameter | camelCase | `userName` |
|
||||
| Local variable | camelCase | `itemCount` |
|
||||
| Constant | PascalCase | `MaxRetryCount` |
|
||||
| Async method | Suffix `Async` | `FetchDataAsync()` |
|
||||
| Boolean | Prefix `Is/Has/Can` | `IsLoading`, `HasAccess` |
|
||||
|
||||
### File Organization
|
||||
|
||||
Each `.cs` file should follow this order:
|
||||
|
||||
1. `using` directives (System first, then others, alphabetically)
|
||||
2. Namespace declaration (file-scoped)
|
||||
3. Class/struct/interface declaration
|
||||
4. Inside the type:
|
||||
1. Constants
|
||||
2. Static fields
|
||||
3. Instance fields
|
||||
4. Constructors
|
||||
5. Properties
|
||||
6. Public methods
|
||||
7. Private/internal methods
|
||||
8. Event handlers
|
||||
9. Nested types
|
||||
|
||||
---
|
||||
|
||||
## Validation
|
||||
|
||||
- Build & register the MSIX package — see **Build, Run & Deploy** in `.github/agents/Agents.md`.
|
||||
- Fix **all** warnings — do not suppress without justification in a code comment.
|
||||
- Verify no unused `using` statements remain after every edit.
|
||||
- Verify no commented-out code remains.
|
||||
- Confirm naming conventions match the table above for every new symbol.
|
||||
|
||||
---
|
||||
|
||||
## Must Read & Research
|
||||
|
||||
> **Agent Rule:** Before configuring analyzers, fixing warnings, or adjusting code style, you **must** fetch and review the relevant references below using `fetch_webpage`. Apply what you learn — do not skip this step.
|
||||
|
||||
| # | Reference | When to consult |
|
||||
|---|---|---|
|
||||
| 1 | [.NET Code Analysis Overview](https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/overview) | Setting up or modifying analyzer configuration |
|
||||
| 2 | [Code Style Rules (IDE0001–IDE0090)](https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/) | Resolving IDE* warnings or adjusting `.editorconfig` |
|
||||
| 3 | [Quality Rules (CA*)](https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/) | Resolving CA* warnings or suppressing with justification |
|
||||
| 4 | [StyleCop.Analyzers GitHub](https://github.com/DotNetAnalyzers/StyleCopAnalyzers) | Adding/updating StyleCop package or configuration |
|
||||
| 5 | [StyleCop Rules Reference](https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/DOCUMENTATION.md) | Understanding specific SA* rule violations |
|
||||
| 6 | [EditorConfig Reference](https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/code-style-rule-options) | Modifying `.editorconfig` style or severity settings |
|
||||
| 7 | [.NET Naming Conventions](https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/coding-style/identifier-names) | Verifying naming patterns for types, members, parameters |
|
||||
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
---
|
||||
description: 'Design principles (DRY, KISS, SOLID, YAGNI) enforced in every code change'
|
||||
applyTo: '**/*.cs, **/*.xaml'
|
||||
---
|
||||
|
||||
# Design Principles
|
||||
|
||||
Apply these principles in **every change** you make to this codebase. When in doubt, favour simplicity and clarity over cleverness.
|
||||
|
||||
---
|
||||
|
||||
## 1. DRY — Don't Repeat Yourself
|
||||
|
||||
> *"Every piece of knowledge must have a single, unambiguous, authoritative representation within a system."*
|
||||
|
||||
### Rules
|
||||
- Before writing new code, **search** the codebase for existing implementations that solve the same problem.
|
||||
- Extract shared logic into helper methods, base classes, or services.
|
||||
- If you find duplicated code during a task, **refactor it** as part of the same change.
|
||||
- Prefer generic/reusable components over copy-paste variations.
|
||||
|
||||
### Anti-patterns to avoid
|
||||
- Copy-pasting code between classes/files instead of extracting a shared method.
|
||||
- Creating multiple converters/helpers that do the same thing.
|
||||
- Duplicating validation logic across ViewModel and Model layers.
|
||||
|
||||
---
|
||||
|
||||
## 2. KISS — Keep It Simple, Stupid
|
||||
|
||||
> *"Simplicity is the ultimate sophistication."*
|
||||
|
||||
### Rules
|
||||
- Choose the **simplest approach** that meets the requirement.
|
||||
- Avoid unnecessary abstractions, inheritance hierarchies, or patterns that add complexity without clear benefit.
|
||||
- Write code that **reads like plain English** — favour descriptive names over comments.
|
||||
- If a method is longer than ~30 lines, consider splitting it.
|
||||
- If a class does more than one thing, split it (see SRP below).
|
||||
|
||||
### Anti-patterns to avoid
|
||||
- Over-engineering with factories/builders/strategies for simple object creation.
|
||||
- Creating deep inheritance trees when composition would suffice.
|
||||
- Using complex LINQ chains when a simple `foreach` is clearer.
|
||||
|
||||
---
|
||||
|
||||
## 3. SOLID Principles
|
||||
|
||||
### 3.1 SRP — Single Responsibility Principle
|
||||
> *"A class should have only one reason to change."*
|
||||
|
||||
- Each class/file should have **one clear responsibility**.
|
||||
- ViewModels handle UI state & commands. Services handle business logic. Models hold data.
|
||||
- If a class name contains "And" or "Manager", it likely violates SRP.
|
||||
|
||||
### 3.2 OCP — Open/Closed Principle
|
||||
> *"Software entities should be open for extension, but closed for modification."*
|
||||
|
||||
- Use interfaces and abstract classes so behaviour can be extended without modifying existing code.
|
||||
- Prefer adding new implementations over modifying existing ones.
|
||||
- Use dependency injection to swap implementations.
|
||||
|
||||
### 3.3 LSP — Liskov Substitution Principle
|
||||
> *"Objects of a superclass should be replaceable with objects of its subclasses without altering correctness."*
|
||||
|
||||
- Derived classes must honour the contracts of their base classes.
|
||||
- Never throw `NotImplementedException` in overridden methods — if a subclass can't fulfil the contract, the inheritance is wrong.
|
||||
|
||||
### 3.4 ISP — Interface Segregation Principle
|
||||
> *"No client should be forced to depend on methods it does not use."*
|
||||
|
||||
- Keep interfaces small and focused.
|
||||
- Prefer multiple small interfaces over one large one.
|
||||
- Example: `INavigationService`, `IDialogService`, `ISettingsService` — not `IAppService`.
|
||||
|
||||
### 3.5 DIP — Dependency Inversion Principle
|
||||
> *"Depend upon abstractions, not concretions."*
|
||||
|
||||
- High-level modules must not depend on low-level modules. Both should depend on abstractions.
|
||||
- Use constructor injection for dependencies.
|
||||
- Register services in a DI container (e.g., `Microsoft.Extensions.DependencyInjection`).
|
||||
|
||||
---
|
||||
|
||||
## 4. YAGNI — You Aren't Gonna Need It
|
||||
|
||||
> *"Don't add functionality until it is necessary."*
|
||||
|
||||
### Rules
|
||||
- Only implement what is **explicitly requested** or **clearly needed right now**.
|
||||
- Do not add "just in case" parameters, methods, or abstractions.
|
||||
- If you're unsure whether something is needed, **leave it out** — it can always be added later.
|
||||
|
||||
### Anti-patterns to avoid
|
||||
- Adding unused interface methods "for future use".
|
||||
- Building a generic framework when a single concrete class suffices.
|
||||
- Creating configuration options nobody has asked for.
|
||||
|
||||
---
|
||||
|
||||
## Quick Reference Checklist
|
||||
|
||||
Before submitting any code change, verify:
|
||||
|
||||
- [ ] No duplicated code exists (DRY)
|
||||
- [ ] The solution is as simple as possible (KISS)
|
||||
- [ ] Each class has one responsibility (SRP)
|
||||
- [ ] New behaviour is added via extension, not modification (OCP)
|
||||
- [ ] Derived types can substitute their base types (LSP)
|
||||
- [ ] Interfaces are small and focused (ISP)
|
||||
- [ ] Dependencies point toward abstractions (DIP)
|
||||
- [ ] No speculative features were added (YAGNI)
|
||||
|
||||
## Validation
|
||||
|
||||
- Review every new/changed class for SRP violations — ask "does this class have more than one reason to change?"
|
||||
- Search the codebase for duplicate logic before adding new helpers: `grep_search` for similar method names or patterns.
|
||||
- Verify no speculative code was added — every line must trace back to the original request.
|
||||
- Build & register the MSIX package — see **Build, Run & Deploy** in `.github/agents/Agents.md`.
|
||||
|
||||
---
|
||||
|
||||
## Must Read & Research
|
||||
|
||||
> **Agent Rule:** Before making any code change related to design principles, you **must** fetch and review the relevant references below using `fetch_webpage`. Apply what you learn — do not skip this step.
|
||||
|
||||
| # | Reference | When to consult |
|
||||
|---|---|---|
|
||||
| 1 | [SOLID Principles in C# — Microsoft Learn](https://learn.microsoft.com/en-us/archive/msdn-magazine/2014/may/csharp-best-practices-dangers-of-violating-solid-principles-in-csharp) | Adding/refactoring classes, interfaces, or inheritance |
|
||||
| 2 | [.NET Design Guidelines](https://learn.microsoft.com/en-us/dotnet/standard/design-guidelines/) | Designing public APIs, naming, type design |
|
||||
| 3 | [Framework Design Guidelines (Book)](https://learn.microsoft.com/en-us/dotnet/standard/design-guidelines/) | Deep-dive on member design, exception patterns, collections |
|
||||
| 4 | [Clean Code Summary](https://gist.github.com/wojteklu/73c6914cc446146b8b533c0988cf8d29) | Code readability, function size, naming clarity |
|
||||
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
---
|
||||
description: 'Globalization & Localization requirements for user-facing strings, resource files, and culture-aware formatting'
|
||||
applyTo: '**/*.cs, **/*.xaml, **/*.resw'
|
||||
---
|
||||
|
||||
# Globalization & Localization
|
||||
|
||||
These rules apply to **every feature and change** involving user-facing text. They are not optional add-ons.
|
||||
|
||||
---
|
||||
|
||||
## Rules
|
||||
|
||||
- **All user-facing strings** (UI text, error messages, tooltips) must come from `.resw` resource files — never hard-code them in XAML or C#.
|
||||
- Resource file location: `Strings/en-us/Resources.resw` (default locale).
|
||||
- Use `x:Uid` in XAML to bind controls to resource keys:
|
||||
```xml
|
||||
<TextBlock x:Uid="WelcomeMessage" />
|
||||
```
|
||||
With a matching `.resw` entry: `WelcomeMessage.Text` = "Welcome!"
|
||||
- In code-behind / ViewModels, use the `ResourceLoader`:
|
||||
```csharp
|
||||
var loader = new Microsoft.Windows.ApplicationModel.Resources.ResourceLoader();
|
||||
string message = loader.GetString("ErrorFileNotFound");
|
||||
```
|
||||
- **Format dates, numbers, and currencies** using `CultureInfo.CurrentCulture` or `DateTimeFormatter` — never assume a specific regional format.
|
||||
- Avoid concatenating translated strings — use format placeholders (`{0}`, `{1}`).
|
||||
- Design UI layouts to accommodate text expansion (~30-40% longer for German vs. English).
|
||||
|
||||
## Anti-patterns
|
||||
|
||||
- Hard-coded strings in `.xaml` or `.cs` files (e.g., `Content="Save"`).
|
||||
- Using `string.Format` with hard-coded ordinal assumptions.
|
||||
- Fixed-width UI elements that clip translated text.
|
||||
|
||||
## Validation
|
||||
|
||||
- Build & register the MSIX package — see **Build, Run & Deploy** in `.github/agents/Agents.md`.
|
||||
- Check for hard-coded strings: search `Content="` and `Text="` in `.xaml` files — replace with `x:Uid`.
|
||||
|
||||
### Verification Checklist
|
||||
|
||||
- [ ] All user-facing strings are in `.resw` resource files
|
||||
|
||||
## Must Read & Research
|
||||
|
||||
> **Agent Rule:** Before any localization-related change, you **must** fetch and review these references using `fetch_webpage`. Apply what you learn.
|
||||
|
||||
| # | Reference | When to consult |
|
||||
|---|---|---|
|
||||
| 1 | [Globalize your WinUI app](https://learn.microsoft.com/en-us/windows/apps/design/globalizing/guidelines-and-checklist-for-globalizing-your-app) | Adding any new user-facing strings or culture-aware formatting |
|
||||
| 2 | [Resource Management System](https://learn.microsoft.com/en-us/windows/apps/windows-app-sdk/mrtcore/localize-strings) | Setting up or modifying `.resw` files and `ResourceLoader` usage |
|
||||
| 3 | [WinUI Localization with x:Uid](https://learn.microsoft.com/en-us/windows/apps/develop/ui-input/localizing-strings) | Binding XAML controls to localized resources via `x:Uid` |
|
||||
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
---
|
||||
description: 'Performance requirements for data binding, layout, threading, and collection virtualization'
|
||||
applyTo: '**/*.cs, **/*.xaml'
|
||||
---
|
||||
|
||||
# Performance
|
||||
|
||||
These rules apply to **every feature and change**. They are not optional add-ons.
|
||||
|
||||
---
|
||||
|
||||
## Rules
|
||||
|
||||
- **Use `x:Bind`** (compiled bindings) instead of `{Binding}` — it's faster and type-safe.
|
||||
- Use **`x:Load`** (or `x:DeferLoadStrategy`) to defer loading of UI elements not immediately visible.
|
||||
- Avoid heavy work on the UI thread — use `Task.Run` for CPU-bound work and `async/await` for I/O.
|
||||
- Use **virtualizing panels** (`ItemsRepeater` with `StackLayout`, or `ListView`) for long lists — never use `StackPanel` with hundreds of items.
|
||||
- **Cache** expensive computations and HTTP responses when appropriate.
|
||||
- Minimize XAML visual tree depth — deep nesting hurts layout performance.
|
||||
- Use **incremental loading** (`ISupportIncrementalLoading`) for large data sets.
|
||||
- Profile with **Visual Studio Diagnostics Tools** and **PerfView** before and after optimizations.
|
||||
- Be cautious with `DispatcherQueue.TryEnqueue` — don't flood the dispatcher queue.
|
||||
|
||||
## Anti-patterns
|
||||
|
||||
- Blocking the UI thread with `.Result` or `.GetAwaiter().GetResult()`.
|
||||
- Loading all data upfront when only a subset is needed.
|
||||
- Creating new `HttpClient` instances per request (use `IHttpClientFactory`).
|
||||
- Using `FindName()` or `VisualTreeHelper` in tight loops.
|
||||
|
||||
## Validation
|
||||
|
||||
- Build & register the MSIX package — see **Build, Run & Deploy** in `.github/agents/Agents.md`.
|
||||
|
||||
### Verification Checklist
|
||||
|
||||
- [ ] No blocking calls on the UI thread
|
||||
- [ ] `x:Bind` is used instead of `{Binding}`
|
||||
- [ ] Large lists use virtualization
|
||||
|
||||
## Must Read & Research
|
||||
|
||||
> **Agent Rule:** Before any performance-sensitive change (data binding, layout, collections, async), you **must** fetch and review these references using `fetch_webpage`. Apply what you learn.
|
||||
|
||||
| # | Reference | When to consult |
|
||||
|---|---|---|
|
||||
| 1 | [Performance best practices for WinUI 3](https://learn.microsoft.com/en-us/windows/apps/performance/) | Any change touching UI rendering, data loading, or threading |
|
||||
| 2 | [x:Bind markup extension](https://learn.microsoft.com/en-us/windows/uwp/xaml-platform/x-bind-markup-extension) | Adding or modifying XAML data bindings |
|
||||
| 3 | [x:Load attribute](https://learn.microsoft.com/en-us/windows/uwp/xaml-platform/x-load-attribute) | Deferring UI element loading |
|
||||
| 4 | [Optimize XAML layout](https://learn.microsoft.com/en-us/windows/apps/performance/optimize-xaml-layout) | Restructuring XAML panels, reducing visual tree depth |
|
||||
| 5 | [ListView optimization](https://learn.microsoft.com/en-us/windows/apps/performance/optimize-listview) | Working with lists, collections, or `ItemsRepeater` |
|
||||
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
---
|
||||
description: 'Security requirements for secrets management, input validation, permissions, and secure coding'
|
||||
applyTo: '**/*.cs, **/*.appxmanifest'
|
||||
---
|
||||
|
||||
# Security
|
||||
|
||||
These rules apply to **every feature and change**. They are not optional add-ons.
|
||||
|
||||
---
|
||||
|
||||
## Rules
|
||||
|
||||
- **Never hard-code secrets** (API keys, passwords, connection strings) — use environment variables, Windows Credential Manager, or Azure Key Vault.
|
||||
- Validate and sanitize **all external input** (user input, file content, network responses).
|
||||
- Use `SecureString` or `PasswordVault` for sensitive data in memory when practical.
|
||||
- Follow the **principle of least privilege** — request only the permissions the app actually needs in `Package.appxmanifest`.
|
||||
- Keep NuGet packages up to date — run `dotnet list package --outdated` regularly.
|
||||
- Enable **code signing** for published MSIX packages. Use the `winapp` CLI rather than hand-rolling `signtool`:
|
||||
- Generate a development certificate matching the manifest publisher: `winapp cert generate --manifest .\Package.appxmanifest --install`.
|
||||
- Inspect a cert before signing: `winapp cert info .\devcert.pfx`.
|
||||
- Sign an existing file: `winapp sign .\MyApp.msix --cert .\devcert.pfx`.
|
||||
- Build + sign in one step: `winapp pack .\bin\<Platform>\Release\<TFM>\win-<rid> --cert .\devcert.pfx`.
|
||||
- Production releases must be signed by a trusted certificate authority -- never ship the development cert.
|
||||
- When using `HttpClient`, always validate TLS certificates and use HTTPS.
|
||||
- Never log sensitive data (PII, tokens, passwords).
|
||||
|
||||
## Anti-patterns
|
||||
|
||||
- Storing secrets in `appsettings.json` committed to source control.
|
||||
- Disabling TLS validation for debugging and forgetting to re-enable it.
|
||||
- Using `Process.Start` with unsanitized user input.
|
||||
- Broad `try { } catch (Exception) { }` that swallows errors silently without any logging.
|
||||
|
||||
## Validation
|
||||
|
||||
- Build & register the MSIX package — see **Build, Run & Deploy** in `.github/agents/Agents.md`.
|
||||
- Check for hard-coded secrets: search for `password`, `apikey`, `secret`, `connectionstring` in `.cs` files.
|
||||
|
||||
### Verification Checklist
|
||||
|
||||
- [ ] No secrets are hard-coded
|
||||
|
||||
## Must Read & Research
|
||||
|
||||
> **Agent Rule:** Before any security-related change (auth, input handling, permissions, HTTP), you **must** fetch and review these references using `fetch_webpage`. Apply what you learn.
|
||||
|
||||
| # | Reference | When to consult |
|
||||
|---|---|---|
|
||||
| 1 | [.NET Security Best Practices](https://learn.microsoft.com/en-us/dotnet/standard/security/) | Any code handling credentials, tokens, or sensitive data |
|
||||
| 2 | [Secure coding guidelines for .NET](https://learn.microsoft.com/en-us/dotnet/standard/security/secure-coding-guidelines) | Input validation, exception handling, type safety |
|
||||
| 3 | [MSIX Security](https://learn.microsoft.com/en-us/windows/msix/msix-container) | Packaging, signing, or distribution changes |
|
||||
| 4 | [Package.appxmanifest capabilities](https://learn.microsoft.com/en-us/windows/uwp/packaging/app-capability-declarations) | Adding or modifying app capabilities/permissions |
|
||||
|
||||
|
||||
@@ -0,0 +1,284 @@
|
||||
---
|
||||
description: 'Unit testing standards, test project setup, naming, build & run commands'
|
||||
applyTo: '**/*Tests.cs, **/*Test.cs, **/*.Tests.csproj'
|
||||
---
|
||||
|
||||
# Testing — Unit Tests, Build & Run
|
||||
|
||||
Every public method and class must have corresponding unit tests. Tests are not optional.
|
||||
|
||||
---
|
||||
|
||||
## 1. Test Framework & Project Setup
|
||||
|
||||
### Recommended Stack
|
||||
|
||||
| Component | Package | Purpose |
|
||||
|---|---|---|
|
||||
| Test Framework | `MSTest` | Test runner & assertions |
|
||||
| Mocking | `Moq` | Mock dependencies |
|
||||
| UI Testing | `Microsoft.Windows.Apps.Test` | WinUI UI automation (optional) |
|
||||
|
||||
### Test Project Setup
|
||||
|
||||
Create a test project alongside the main project:
|
||||
|
||||
```
|
||||
<SolutionRoot>/
|
||||
<ProjectName>/ ← Main app project
|
||||
<ProjectName>.Tests/ ← Unit test project
|
||||
```
|
||||
|
||||
Test project `.csproj` should reference the main project:
|
||||
|
||||
```xml
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<!-- Match TargetFramework to the main project's .csproj -->
|
||||
<TargetFramework><!-- same as the main project's .csproj TargetFramework --></TargetFramework>
|
||||
<UseWinUI>true</UseWinUI>
|
||||
<Nullable>enable</Nullable>
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<!-- Use latest stable versions; do not hard-code version numbers in instructions -->
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="*" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="*" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="*" />
|
||||
<PackageReference Include="Moq" Version="*" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\<ProjectName>\<ProjectName>.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. Test Writing Rules
|
||||
|
||||
### What to Test
|
||||
- **All public methods** in ViewModels, Services, Helpers, and Models.
|
||||
- **Edge cases** — null inputs, empty collections, boundary values.
|
||||
- **Error paths** — exception handling, invalid state transitions.
|
||||
- **Business logic** — calculations, transformations, state management.
|
||||
|
||||
### What NOT to Test (Directly)
|
||||
- XAML layout / visual rendering (use UI tests for that).
|
||||
- Framework internals (e.g., `InitializeComponent()`).
|
||||
- Private methods — test them indirectly through public methods.
|
||||
|
||||
### Test Naming Convention
|
||||
|
||||
Use the pattern: `MethodName_Scenario_ExpectedResult`
|
||||
|
||||
```csharp
|
||||
[TestMethod]
|
||||
public void CalculateTotal_WithEmptyCart_ReturnsZero() { }
|
||||
|
||||
[TestMethod]
|
||||
public void LoadDataAsync_WhenServiceThrows_SetsErrorState() { }
|
||||
|
||||
[TestMethod]
|
||||
public async Task SaveAsync_WithValidInput_ReturnsTrue() { }
|
||||
```
|
||||
|
||||
### Test Structure (AAA Pattern)
|
||||
|
||||
Every test follows **Arrange → Act → Assert**:
|
||||
|
||||
```csharp
|
||||
[TestMethod]
|
||||
public void Add_TwoPositiveNumbers_ReturnsSum()
|
||||
{
|
||||
// Arrange
|
||||
var calculator = new Calculator();
|
||||
|
||||
// Act
|
||||
int result = calculator.Add(2, 3);
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual(5, result);
|
||||
}
|
||||
```
|
||||
|
||||
### ViewModel Testing Example
|
||||
|
||||
```csharp
|
||||
[TestMethod]
|
||||
public async Task LoadItemsAsync_OnSuccess_PopulatesItems()
|
||||
{
|
||||
// Arrange
|
||||
var mockService = new Mock<IDataService>();
|
||||
mockService
|
||||
.Setup(s => s.GetItemsAsync())
|
||||
.ReturnsAsync(new List<Item> { new("Test") });
|
||||
|
||||
var viewModel = new MainViewModel(mockService.Object);
|
||||
|
||||
// Act
|
||||
await viewModel.LoadItemsAsync();
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual(1, viewModel.Items.Count);
|
||||
Assert.IsFalse(viewModel.IsLoading);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Test Organization
|
||||
|
||||
### File Structure
|
||||
|
||||
Mirror the main project's folder structure (defined in [winui-best-practices](winui-best-practices.instructions.md)) in the test project. As the main project grows with subfolders under `ViewModels/`, `Services/`, `Views/`, etc., the test project must grow organically in the same way. This alignment enables on-demand test runs scoped to the area you changed:
|
||||
|
||||
```
|
||||
<ProjectName>/ <ProjectName>.Tests/
|
||||
Models/ Models/
|
||||
User.cs UserTests.cs
|
||||
ViewModels/ ViewModels/
|
||||
MainViewModelTests.cs MainViewModelTests.cs
|
||||
Settings/ Settings/
|
||||
ThemeViewModel.cs ThemeViewModelTests.cs
|
||||
Services/ Services/
|
||||
DataService.cs DataServiceTests.cs
|
||||
Auth/ Auth/
|
||||
AuthService.cs AuthServiceTests.cs
|
||||
Helpers/ Helpers/
|
||||
StringHelper.cs StringHelperTests.cs
|
||||
Converters/ Converters/
|
||||
BoolToVisibilityConverter.cs BoolToVisibilityConverterTests.cs
|
||||
```
|
||||
|
||||
### One Test Class per Class Under Test
|
||||
|
||||
```csharp
|
||||
namespace <RootNamespace>.Tests.ViewModels;
|
||||
|
||||
[TestClass]
|
||||
public class MainViewModelTests
|
||||
{
|
||||
// All tests for MainViewModel go here
|
||||
}
|
||||
```
|
||||
|
||||
### Running Tests On-Demand
|
||||
|
||||
After a change, run only the tests related to the affected area instead of the full suite. Detect the platform first (matching the convention in `.github/agents/Agents.md`):
|
||||
|
||||
```powershell
|
||||
# Run from the test project folder
|
||||
cd <ProjectName>.Tests
|
||||
|
||||
# Detect platform once per session (AMD64 -> x64; ARM64/x86 unchanged)
|
||||
$arch = $env:PROCESSOR_ARCHITECTURE
|
||||
$Platform = if ($arch -eq 'AMD64') { 'x64' } else { $arch }
|
||||
|
||||
# Run tests for a specific class
|
||||
dotnet test -c Debug -p:Platform=$Platform --filter "FullyQualifiedName~MainViewModelTests"
|
||||
|
||||
# Run a single test
|
||||
dotnet test -c Debug -p:Platform=$Platform --filter "FullyQualifiedName~MainViewModelTests.LoadItemsAsync_OnSuccess_PopulatesItems"
|
||||
|
||||
# Run all tests in a namespace (e.g., all ViewModel tests)
|
||||
dotnet test -c Debug -p:Platform=$Platform --filter "FullyQualifiedName~Tests.ViewModels"
|
||||
|
||||
# Run tests in a subfolder namespace (e.g., only Settings ViewModels)
|
||||
dotnet test -c Debug -p:Platform=$Platform --filter "FullyQualifiedName~Tests.ViewModels.Settings"
|
||||
|
||||
# Run the full suite (for cross-cutting changes)
|
||||
dotnet test -c Debug -p:Platform=$Platform
|
||||
```
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Test-Specific Commands
|
||||
|
||||
For general build and register commands, see **Build, Run & Deploy** in `.github/agents/Agents.md`.
|
||||
For on-demand test filtering, see **Running Tests On-Demand** above.
|
||||
|
||||
Below are additional test commands:
|
||||
|
||||
### Build Only the Test Project
|
||||
|
||||
```powershell
|
||||
cd <ProjectName>.Tests
|
||||
$arch = $env:PROCESSOR_ARCHITECTURE
|
||||
$Platform = if ($arch -eq 'AMD64') { 'x64' } else { $arch }
|
||||
dotnet build -c Debug -p:Platform=$Platform
|
||||
```
|
||||
|
||||
### Run Tests with Verbose Output
|
||||
|
||||
```powershell
|
||||
dotnet test -c Debug -p:Platform=$Platform --verbosity normal
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Agent Workflow for Tests
|
||||
|
||||
When you write or modify code, follow this sequence:
|
||||
|
||||
1. **Implement the feature or fix** in the main project.
|
||||
2. **Write unit tests** for every new/changed public method.
|
||||
3. **Build** — see **Build, Run & Deploy** in `.github/agents/Agents.md`. Fix all errors and warnings.
|
||||
4. **Run tests** — `dotnet test -c Debug -p:Platform=$Platform` (from the test project folder; detect `$Platform` as shown above) and ensure all pass.
|
||||
5. **Review** — Confirm tests cover the happy path, edge cases, and error cases.
|
||||
|
||||
### When Modifying Existing Code
|
||||
|
||||
1. **Run existing tests first** to establish a baseline.
|
||||
2. Make the code change.
|
||||
3. **Run tests again** — fix any failures.
|
||||
4. **Add new tests** if the change introduces new behaviour.
|
||||
|
||||
### Coverage Goals
|
||||
|
||||
- Aim for **80%+ code coverage** on business logic (ViewModels, Services).
|
||||
- 100% coverage of utility/helper methods.
|
||||
- UI code-behind is exempt from unit test coverage (tested via integration/UI tests).
|
||||
|
||||
---
|
||||
|
||||
## 6. Common Test Pitfalls
|
||||
|
||||
| Pitfall | Fix |
|
||||
|---|---|
|
||||
| Test depends on another test's state | Each test must be fully independent |
|
||||
| Testing multiple things in one test | One assertion per logical concept |
|
||||
| Tests pass but don't actually verify anything | Always have meaningful assertions |
|
||||
| Mocking too much | Mock only external dependencies, not the class under test |
|
||||
| Testing implementation details | Test behaviour and outcomes, not internal method calls |
|
||||
| Async tests without `await` | Always `await` async methods and use `async Task` return type |
|
||||
|
||||
---
|
||||
|
||||
## Validation
|
||||
|
||||
- Build & run tests — see **Build, Run & Deploy** in `.github/agents/Agents.md`.
|
||||
- Verify all tests pass — zero failures, zero skipped without justification.
|
||||
- Verify naming follows `MethodName_Scenario_ExpectedResult` pattern.
|
||||
- Verify AAA structure (Arrange/Act/Assert) in every test method.
|
||||
- Confirm coverage goals: 80%+ on ViewModels/Services, 100% on helpers.
|
||||
|
||||
---
|
||||
|
||||
## Must Read & Research
|
||||
|
||||
> **Agent Rule:** Before writing or modifying tests, you **must** fetch and review the relevant references below using `fetch_webpage`. Apply what you learn — do not skip this step.
|
||||
|
||||
| # | Reference | When to consult |
|
||||
|---|---|---|
|
||||
| 1 | [Unit testing C# with MSTest](https://learn.microsoft.com/en-us/dotnet/core/testing/unit-testing-with-mstest) | Setting up test project, writing first tests, MSTest attributes |
|
||||
| 2 | [Unit testing best practices .NET](https://learn.microsoft.com/en-us/dotnet/core/testing/unit-testing-best-practices) | Every time you write tests — naming, structure, AAA pattern |
|
||||
| 3 | [Moq Quickstart](https://github.com/devlooped/moq/wiki/Quickstart) | Mocking interfaces, setting up `Returns`/`Throws`, verifying calls |
|
||||
| 4 | [FluentAssertions Documentation](https://fluentassertions.com/introduction) | Writing expressive assertions (`Should().Be()`, collections, exceptions) |
|
||||
| 5 | [dotnet test CLI](https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-test) | Running tests from terminal, filtering, verbosity options |
|
||||
| 6 | [Test Explorer in Visual Studio](https://learn.microsoft.com/en-us/visualstudio/test/run-unit-tests-with-test-explorer) | Debugging tests, viewing coverage, understanding test output |
|
||||
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
---
|
||||
description: 'WinAppSDK & Windows Platform SDK -- API namespace catalog and lookup guidance'
|
||||
applyTo: '**/*.cs, **/*.xaml, **/*.csproj'
|
||||
---
|
||||
|
||||
# Windows APIs -- WinAppSDK & Windows Platform SDK
|
||||
|
||||
## Sample-First Rule
|
||||
|
||||
> **Agent Rule -- MANDATORY:** Before implementing **any** WinAppSDK or Windows Platform SDK API you have not used before, you **must** search the sample repositories below for a working example first. **Do not guess API usage patterns from documentation alone** -- the docs often omit critical details that only the sample code reveals. Search **all** of the following repos, not just one:
|
||||
|
||||
| # | Repository | What it covers |
|
||||
|---|---|---|
|
||||
| 1 | [WindowsAppSDK-Samples](https://github.com/microsoft/WindowsAppSDK-Samples) | All WinAppSDK features (AI, windowing, lifecycle, notifications, etc.) |
|
||||
| 2 | [AI Dev Gallery](https://github.com/microsoft/ai-dev-gallery) | On-device AI/ML patterns, model usage examples |
|
||||
| 3 | [WinUI-Gallery](https://github.com/microsoft/WinUI-Gallery) | UI control patterns and XAML examples |
|
||||
|
||||
### How to apply
|
||||
|
||||
1. **Find the right API** -- Translate the user's scenario/requirement into common API/programming keywords, then search the API references (Part A-B below) using those keywords to identify which API fits.
|
||||
2. **Search for samples** -- Once you know which API to use, search each sample repo above for the class name to find a working example.
|
||||
3. **Study the sample** -- Read the sample's Model / ViewModel / Service layer to understand how the API is actually called -- object lifetime, required parameters, data preparation, error handling.
|
||||
4. **Adapt** the sample pattern into our MVVM architecture -- don't copy the sample structure wholesale, but match its API call sequence exactly.
|
||||
|
||||
---
|
||||
|
||||
> **Agent Rule:** Before implementing any feature that involves a platform capability, **consult this file** to check whether a built-in API already exists. Always verify exact class names, method signatures, and availability by following the reference links -- do not guess API shapes.
|
||||
|
||||
---
|
||||
|
||||
## Part A -- Windows App SDK APIs
|
||||
|
||||
**Full API reference:** <https://learn.microsoft.com/en-us/windows/windows-app-sdk/api/winrt/>
|
||||
|
||||
> **Agent Rule:** Do not rely on a hardcoded namespace list -- the SDK is updated frequently. Instead, **search** the API reference above by converting the user's scenario into common programming keywords.
|
||||
|
||||
### How to search
|
||||
|
||||
1. **Translate** the user's request into API/programming terms. Examples:
|
||||
- "I want to describe an image" -> search for: `image description`, `ImageDescription`, `describe image`
|
||||
- "Add a notification" -> search for: `notification`, `toast`, `AppNotification`
|
||||
- "Pick a file" -> search for: `file picker`, `StoragePicker`, `FileOpenPicker`
|
||||
- "Make the window always on top" -> search for: `AppWindow`, `presenter`, `compact overlay`
|
||||
2. **Search** the [WinAppSDK API reference](https://learn.microsoft.com/en-us/windows/windows-app-sdk/api/winrt/) using `web_search` or `web_fetch` with those keywords.
|
||||
3. **Verify** the class/method exists in the SDK version used by this project (check `.csproj` `<PackageReference>` for `Microsoft.WindowsAppSDK` version).
|
||||
|
||||
### Key reference links
|
||||
|
||||
| # | Link | When to consult |
|
||||
|---|---|---|
|
||||
| 1 | [WinAppSDK API Reference (full)](https://learn.microsoft.com/en-us/windows/windows-app-sdk/api/winrt/) | **Always** -- search and look up exact class/method signatures here |
|
||||
| 2 | [Windows App SDK overview](https://learn.microsoft.com/en-us/windows/apps/windows-app-sdk/) | Feature overview, architecture |
|
||||
| 3 | [Release notes (stable)](https://learn.microsoft.com/en-us/windows/apps/windows-app-sdk/stable-channel) | API availability, version support, breaking changes |
|
||||
| 4 | [Windows AI overview](https://learn.microsoft.com/en-us/windows/ai/) | All AI options: Windows AI APIs, Windows ML, Foundry Local |
|
||||
| 5 | [Get started with Windows AI APIs](https://learn.microsoft.com/en-us/windows/ai/apis/get-started) | Prerequisites, project setup, first AI call |
|
||||
| 6 | [Windows ML overview](https://learn.microsoft.com/en-us/windows/ai/new-windows-ml/overview) | Custom ONNX model inference |
|
||||
| 7 | [Foundry Local](https://learn.microsoft.com/en-us/windows/ai/foundry-local/get-started) | Run OSS LLMs locally |
|
||||
|
||||
---
|
||||
|
||||
## Part B -- Windows Platform SDK (UWP / WinRT APIs)
|
||||
|
||||
**Full API reference:** <https://learn.microsoft.com/en-us/uwp/api/>
|
||||
|
||||
> **Agent Rule:** The Platform SDK (`Windows.*` namespaces) is very large and constantly evolving. Do not rely on a hardcoded list. **Search** the API reference by translating the user's requirement into programming keywords.
|
||||
|
||||
### How to search
|
||||
|
||||
1. **Translate** the user's request into API/programming terms. Examples:
|
||||
- "Send a Bluetooth message" -> search for: `Bluetooth`, `RFCOMM`, `BluetoothDevice`
|
||||
- "Get the user's location" -> search for: `geolocation`, `Geolocator`, `position`
|
||||
- "Read text from an image" -> search for: `OCR`, `text recognition`, `OcrEngine`
|
||||
- "Copy to clipboard" -> search for: `clipboard`, `DataTransfer`, `DataPackage`
|
||||
2. **Search** the [Platform SDK API reference](https://learn.microsoft.com/en-us/uwp/api/) using `web_search` or `web_fetch` with those keywords.
|
||||
3. **Check for WinAppSDK equivalent** -- some Platform SDK APIs have newer equivalents in Part A. Always prefer the WinAppSDK version when both exist.
|
||||
|
||||
### Key reference links
|
||||
|
||||
| # | Link | When to consult |
|
||||
|---|---|---|
|
||||
| 1 | [Platform SDK API Reference (full)](https://learn.microsoft.com/en-us/uwp/api/) | **Search here** for any Windows capability not in WinAppSDK |
|
||||
| 2 | [Windows SDK downloads](https://developer.microsoft.com/windows/downloads/windows-sdk/) | SDK versions and downloads |
|
||||
|
||||
---
|
||||
|
||||
## Validation
|
||||
|
||||
- Before implementing any platform feature, confirm the API is available in the current Windows App SDK version by checking the [release notes](https://learn.microsoft.com/en-us/windows/apps/windows-app-sdk/stable-channel).
|
||||
- For features requiring specific hardware (NPU), provide a graceful fallback for unsupported devices.
|
||||
- When both WinAppSDK and Platform SDK offer a similar API, prefer the WinAppSDK version.
|
||||
|
||||
|
||||
@@ -0,0 +1,420 @@
|
||||
---
|
||||
description: 'WinUI 3 / WinAppSDK architecture, MVVM, XAML patterns, DI, theming, and controls guidance'
|
||||
applyTo: '**/*.cs, **/*.xaml, **/*.csproj'
|
||||
---
|
||||
|
||||
# WinUI 3 / WinAppSDK -- Best Practices & Patterns
|
||||
|
||||
This file covers WinUI 3-specific patterns, conventions, and architecture guidance for this project.
|
||||
|
||||
---
|
||||
|
||||
## 1. Architecture -- MVVM Pattern
|
||||
|
||||
### Overview
|
||||
|
||||
Use **Model-View-ViewModel (MVVM)** for all UI features:
|
||||
|
||||
| Layer | Responsibility | Example |
|
||||
|---|---|---|
|
||||
| **Model** | Data structures & business entities | `Item.cs`, `UserProfile.cs` |
|
||||
| **View** | XAML UI -- layout, styles, animations | `MainPage.xaml` |
|
||||
| **ViewModel** | UI state, commands, data transformation | `MainViewModel.cs` |
|
||||
| **Service** | Business logic, data access, navigation | `IDataService.cs`, `NavigationService.cs` |
|
||||
|
||||
### Project Folder Structure
|
||||
|
||||
```
|
||||
<ProjectName>/
|
||||
Models/ -> Data classes
|
||||
ViewModels/ -> ViewModels (one per page/dialog)
|
||||
Views/ -> XAML pages and windows
|
||||
Services/ -> Business logic & platform services
|
||||
Converters/ -> IValueConverter implementations
|
||||
Helpers/ -> Static utility methods
|
||||
Controls/ -> Custom/reusable controls
|
||||
Strings/
|
||||
en-us/
|
||||
Resources.resw
|
||||
Assets/ -> Images, icons, splash screens
|
||||
```
|
||||
|
||||
### ViewModel Base
|
||||
|
||||
Use `CommunityToolkit.Mvvm` (recommended) for boilerplate-free ViewModels:
|
||||
|
||||
```xml
|
||||
<!-- Use latest stable version; do not hard-code version numbers in instructions -->
|
||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="*" />
|
||||
```
|
||||
|
||||
```csharp
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
|
||||
public partial class MainViewModel : ObservableObject
|
||||
{
|
||||
[ObservableProperty]
|
||||
private string _title = string.Empty;
|
||||
|
||||
[ObservableProperty]
|
||||
private bool _isLoading;
|
||||
|
||||
[RelayCommand]
|
||||
private async Task LoadDataAsync()
|
||||
{
|
||||
IsLoading = true;
|
||||
try
|
||||
{
|
||||
// Load data
|
||||
}
|
||||
finally
|
||||
{
|
||||
IsLoading = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### View-ViewModel Binding
|
||||
|
||||
```xml
|
||||
<Page
|
||||
x:Class="<RootNamespace>.Views.MainPage"
|
||||
xmlns:vm="using:<RootNamespace>.ViewModels">
|
||||
|
||||
<Page.DataContext>
|
||||
<vm:MainViewModel />
|
||||
</Page.DataContext>
|
||||
|
||||
<Grid>
|
||||
<TextBlock Text="{x:Bind ViewModel.Title, Mode=OneWay}" />
|
||||
<Button Command="{x:Bind ViewModel.LoadDataCommand}" Content="Load" />
|
||||
</Grid>
|
||||
</Page>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. XAML Best Practices
|
||||
|
||||
### Use `x:Bind` Over `{Binding}`
|
||||
|
||||
| Feature | `x:Bind` | `{Binding}` |
|
||||
|---|---|---|
|
||||
| Compile-time check | Yes | No |
|
||||
| Performance | Faster (compiled) | Slower (reflection) |
|
||||
| Default mode | OneTime | OneWay |
|
||||
| IntelliSense | Yes | No |
|
||||
|
||||
```xml
|
||||
<!-- GOOD -->
|
||||
<TextBlock Text="{x:Bind ViewModel.Name, Mode=OneWay}" />
|
||||
|
||||
<!-- AVOID -->
|
||||
<TextBlock Text="{Binding Name}" />
|
||||
```
|
||||
|
||||
### Use `x:Load` for Deferred Loading
|
||||
|
||||
```xml
|
||||
<StackPanel x:Load="{x:Bind ViewModel.ShowAdvancedOptions, Mode=OneWay}">
|
||||
<!-- Heavy content loaded only when needed -->
|
||||
</StackPanel>
|
||||
```
|
||||
|
||||
### Use WinUI Controls from the SDK
|
||||
|
||||
Prefer the WinUI 3 controls from `Microsoft.UI.Xaml.Controls`, **not** the older UWP `Windows.UI.Xaml.Controls`:
|
||||
|
||||
```csharp
|
||||
// GOOD -- WinUI 3
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
// AVOID -- UWP (won't work in WinUI 3 desktop)
|
||||
// using Windows.UI.Xaml.Controls;
|
||||
```
|
||||
|
||||
### XAML Formatting Convention
|
||||
|
||||
```xml
|
||||
<Button
|
||||
x:Name="SaveButton"
|
||||
x:Uid="SaveButton"
|
||||
AutomationProperties.Name="Save"
|
||||
Command="{x:Bind ViewModel.SaveCommand}"
|
||||
Style="{StaticResource AccentButtonStyle}" />
|
||||
```
|
||||
|
||||
- One attribute per line for controls with 3+ attributes.
|
||||
- Order: `x:Name` -> `x:Uid` -> `AutomationProperties` -> layout -> data -> style.
|
||||
|
||||
---
|
||||
|
||||
## 3. Dependency Injection
|
||||
|
||||
### Setup with `Microsoft.Extensions.DependencyInjection`
|
||||
|
||||
```xml
|
||||
<!-- Use latest stable version; do not hard-code version numbers in instructions -->
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="*" />
|
||||
```
|
||||
|
||||
```csharp
|
||||
// App.xaml.cs
|
||||
public partial class App : Application
|
||||
{
|
||||
public static IServiceProvider Services { get; private set; } = null!;
|
||||
|
||||
public App()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
Services = ConfigureServices();
|
||||
}
|
||||
|
||||
private static IServiceProvider ConfigureServices()
|
||||
{
|
||||
var services = new ServiceCollection();
|
||||
|
||||
// Services
|
||||
services.AddSingleton<INavigationService, NavigationService>();
|
||||
services.AddTransient<IDataService, DataService>();
|
||||
|
||||
// ViewModels
|
||||
services.AddTransient<MainViewModel>();
|
||||
|
||||
return services.BuildServiceProvider();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Navigation
|
||||
|
||||
### Frame-based Navigation
|
||||
|
||||
```csharp
|
||||
public interface INavigationService
|
||||
{
|
||||
bool CanGoBack { get; }
|
||||
void NavigateTo<TPage>() where TPage : Page;
|
||||
void GoBack();
|
||||
}
|
||||
```
|
||||
|
||||
Use a `NavigationView` with a `Frame`:
|
||||
|
||||
```xml
|
||||
<NavigationView SelectionChanged="OnNavigationChanged">
|
||||
<NavigationView.MenuItems>
|
||||
<NavigationViewItem Content="Home" Tag="Home" />
|
||||
<NavigationViewItem Content="Settings" Tag="Settings" />
|
||||
</NavigationView.MenuItems>
|
||||
<Frame x:Name="ContentFrame" />
|
||||
</NavigationView>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Windowing & Title Bar
|
||||
|
||||
### Custom Title Bar
|
||||
|
||||
```csharp
|
||||
// In Window constructor or Activated handler
|
||||
ExtendsContentIntoTitleBar = true;
|
||||
SetTitleBar(AppTitleBar); // AppTitleBar is a UIElement in your XAML
|
||||
```
|
||||
|
||||
```xml
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="48" /> <!-- Title bar -->
|
||||
<RowDefinition Height="*" /> <!-- Content -->
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Grid x:Name="AppTitleBar" Grid.Row="0">
|
||||
<TextBlock Text="My App" VerticalAlignment="Center" Margin="16,0" />
|
||||
</Grid>
|
||||
|
||||
<Frame Grid.Row="1" x:Name="ContentFrame" />
|
||||
</Grid>
|
||||
```
|
||||
|
||||
### Window Sizing
|
||||
|
||||
```csharp
|
||||
var hwnd = WinRT.Interop.WindowNative.GetWindowHandle(this);
|
||||
var windowId = Win32Interop.GetWindowIdFromWindow(hwnd);
|
||||
var appWindow = AppWindow.GetFromWindowId(windowId);
|
||||
appWindow.Resize(new SizeInt32(1280, 720));
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. Theming
|
||||
|
||||
### Support Light/Dark/High Contrast
|
||||
|
||||
```xml
|
||||
<!-- In App.xaml -->
|
||||
<Application.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</Application.Resources>
|
||||
```
|
||||
|
||||
### Detect Theme Changes
|
||||
|
||||
```csharp
|
||||
if (Content is FrameworkElement rootElement)
|
||||
{
|
||||
rootElement.ActualThemeChanged += (s, e) =>
|
||||
{
|
||||
// React to theme change
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### Use Theme Resources, Not Hard-coded Colors
|
||||
|
||||
```xml
|
||||
<!-- GOOD -->
|
||||
<TextBlock Foreground="{ThemeResource TextFillColorPrimaryBrush}" />
|
||||
|
||||
<!-- AVOID -->
|
||||
<TextBlock Foreground="#000000" />
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. System Backdrop (Mica / Acrylic)
|
||||
|
||||
This project uses **Mica** backdrop (already configured in `MainWindow.xaml`):
|
||||
|
||||
```xml
|
||||
<Window.SystemBackdrop>
|
||||
<MicaBackdrop />
|
||||
</Window.SystemBackdrop>
|
||||
```
|
||||
|
||||
Alternatives:
|
||||
```xml
|
||||
<DesktopAcrylicBackdrop /> <!-- Acrylic -->
|
||||
<MicaBackdrop Kind="BaseAlt" /> <!-- Mica Alt -->
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. Community Toolkit
|
||||
|
||||
### Recommended Packages
|
||||
|
||||
```xml
|
||||
<!-- Use latest stable versions; do not hard-code version numbers in instructions -->
|
||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="*" />
|
||||
<PackageReference Include="CommunityToolkit.WinUI.Controls.SettingsControls" Version="*" />
|
||||
<PackageReference Include="CommunityToolkit.WinUI.Helpers" Version="*" />
|
||||
<PackageReference Include="CommunityToolkit.WinUI.Animations" Version="*" />
|
||||
```
|
||||
|
||||
### Useful Toolkit Features
|
||||
|
||||
| Feature | Package | Use Case |
|
||||
|---|---|---|
|
||||
| `ObservableObject` | CommunityToolkit.Mvvm | ViewModel base class |
|
||||
| `RelayCommand` | CommunityToolkit.Mvvm | Command implementation |
|
||||
| `ObservableProperty` | CommunityToolkit.Mvvm | Auto INotifyPropertyChanged |
|
||||
| `SettingsCard` | CommunityToolkit.WinUI.Controls | Settings pages |
|
||||
| `IncrementalLoadingCollection` | CommunityToolkit.WinUI | Lazy-loading lists |
|
||||
|
||||
---
|
||||
|
||||
## 9. Common Pitfalls
|
||||
|
||||
| Pitfall | Solution |
|
||||
|---|---|
|
||||
| Using `Windows.UI.Xaml` namespace | Use `Microsoft.UI.Xaml` for WinUI 3 |
|
||||
| Calling `Window.Current` | Not available in WinUI 3 -- pass window reference explicitly |
|
||||
| Using `CoreDispatcher` | Use `DispatcherQueue` instead |
|
||||
| `REGDB_E_CLASSNOTREG` error | Ensure Developer Mode is enabled, then re-register: run `winapp unregister` followed by `dotnet run` (or `winapp run <build-output>`) to refresh the loose-layout registration |
|
||||
| Stale package state after manifest changes | Run `winapp unregister`, then `dotnet run` -- using `winapp run --clean` additionally wipes `LocalState`/settings to test first-run behavior |
|
||||
| XAML Designer crashes | Clean & rebuild; ensure platform matches (x64 vs AnyCPU) |
|
||||
| `{Binding}` not updating | Switch to `x:Bind` with `Mode=OneWay` or `Mode=TwoWay` |
|
||||
|
||||
---
|
||||
|
||||
## 10. Validation
|
||||
|
||||
Build & register the MSIX package -- see **Build, Run & Deploy** in `.github/agents/Agents.md`.
|
||||
|
||||
### Verify
|
||||
|
||||
- Run the app and verify the changed UI renders correctly on x64.
|
||||
- Search XAML for `{Binding` -- replace with `x:Bind`.
|
||||
- Search XAML for `Foreground="#` or `Background="#` -- replace with `{ThemeResource}`.
|
||||
- Search C# for `Windows.UI.Xaml` -- replace with `Microsoft.UI.Xaml`.
|
||||
- Search C# for `Window.Current` -- replace with explicit window reference.
|
||||
- Search C# for `CoreDispatcher` -- replace with `DispatcherQueue`.
|
||||
- Test Light, Dark, and High Contrast themes.
|
||||
|
||||
---
|
||||
|
||||
## 11. Must Read & Research
|
||||
|
||||
> **Agent Rule:** Before making any WinUI/WinAppSDK-related change, you **must** fetch and review the relevant references below using `fetch_webpage`. Consult the appropriate section based on the type of change. Apply what you learn -- do not skip this step.
|
||||
|
||||
### Official Documentation
|
||||
|
||||
| # | Reference | When to consult |
|
||||
|---|---|---|
|
||||
| 1 | [WinUI 3 Overview](https://learn.microsoft.com/en-us/windows/apps/winui/winui3/) | Starting new features, onboarding to the project |
|
||||
| 2 | [Windows App SDK](https://learn.microsoft.com/en-us/windows/apps/windows-app-sdk/) | Using SDK-specific APIs (windowing, lifecycle, activation) |
|
||||
| 3 | [WinUI 3 API Reference](https://learn.microsoft.com/en-us/windows/windows-app-sdk/api/winrt/) | Looking up specific class/method signatures |
|
||||
| 4 | [WinUI 3 Gallery App](https://learn.microsoft.com/en-us/windows/apps/design/controls/) | Choosing controls, reviewing control patterns |
|
||||
| 5 | [AI Dev Gallery](https://github.com/microsoft/ai-dev-gallery) | On-device AI/ML integration patterns, model usage examples in WinUI |
|
||||
| 6 | [Windows App SDK Release Notes](https://learn.microsoft.com/en-us/windows/apps/windows-app-sdk/stable-channel) | Checking for breaking changes, new APIs, known issues |
|
||||
|
||||
### Architecture & Patterns
|
||||
|
||||
| # | Reference | When to consult |
|
||||
|---|---|---|
|
||||
| 7 | [CommunityToolkit.Mvvm Docs](https://learn.microsoft.com/en-us/dotnet/communitytoolkit/mvvm/) | Implementing ViewModels, commands, `ObservableProperty` |
|
||||
| 8 | [Dependency Injection in .NET](https://learn.microsoft.com/en-us/dotnet/core/extensions/dependency-injection) | Registering services, constructor injection, lifetime management |
|
||||
| 9 | [Template Studio for WinUI](https://github.com/microsoft/TemplateStudio) | Scaffolding pages, navigation, project structure patterns |
|
||||
|
||||
### Controls & Design
|
||||
|
||||
| # | Reference | When to consult |
|
||||
|---|---|---|
|
||||
| 10 | [WinUI 3 Gallery (GitHub)](https://github.com/microsoft/WinUI-Gallery) | Example implementations of any WinUI control |
|
||||
| 11 | [Windows Community Toolkit (GitHub)](https://github.com/CommunityToolkit/Windows) | Before building custom controls -- check if the toolkit already has one |
|
||||
| 12 | [Fluent Design System](https://learn.microsoft.com/en-us/windows/apps/design/) | Spacing, typography, colour, motion, layout decisions |
|
||||
| 13 | [XAML Controls Gallery](https://apps.microsoft.com/store/detail/winui-3-gallery/9P3JFPWWDZRC) | Interactive demo of all controls and their properties |
|
||||
|
||||
### Windows APIs & AI
|
||||
|
||||
| # | Reference | When to consult |
|
||||
|---|---|---|
|
||||
| 14 | [Windows APIs instruction file](windows-apis.instructions.md) | **First stop** -- check if a built-in API already exists for the capability you need (AI, windowing, notifications, widgets, lifecycle, etc.) |
|
||||
| 15 | [Windows AI APIs](https://learn.microsoft.com/en-us/windows/ai/apis/) | On-device AI: Phi Silica (text gen), OCR, imaging (super-res, description, object extract, erase) |
|
||||
| 16 | [Windows ML](https://learn.microsoft.com/en-us/windows/ai/new-windows-ml/overview) | Custom ONNX model inference on CPU/GPU/NPU |
|
||||
| 17 | [Foundry Local](https://learn.microsoft.com/en-us/windows/ai/foundry-local/get-started) | Run OSS LLMs (Llama, Mistral, Phi) locally via REST API |
|
||||
| 18 | [Windows AI on Windows](https://learn.microsoft.com/en-us/windows/ai/) | AI landing page -- all AI options for Windows apps |
|
||||
|
||||
### Samples
|
||||
|
||||
> **Agent Rule -- MANDATORY:** Before implementing any WinAppSDK or Platform SDK API you have not used before, **search the samples repo first** and study the working example. Do not guess API usage from docs alone -- see the [Sample-First Rule](windows-apis.instructions.md#sample-first-rule) for details and known pitfalls.
|
||||
|
||||
| # | Reference | When to consult |
|
||||
|---|---|---|
|
||||
| 19 | [Windows App SDK Samples](https://github.com/microsoft/WindowsAppSDK-Samples) | **Always search here first** before implementing any SDK API for the first time |
|
||||
| 20 | [WinUI 3 Demos](https://github.com/microsoft/WinUI-Gallery) | Reference implementations and patterns |
|
||||
| 21 | [Windows AI API Samples](https://github.com/microsoft/WindowsAppSDK-Samples/tree/main/Samples/WindowsAIFoundry/cs-winui) | AI API usage with WinUI (ImageDescription, TextRecognizer, LanguageModel, etc.) |
|
||||
|
||||
|
||||
Reference in New Issue
Block a user