Starter Architecture
Start with a packaged C# WinUI 3 app and one testable core library. Do not begin with modular architecture, custom installers, WebView2, or background features unless the product already needs them.
MyApp/
MyApp.sln
src/
MyApp/
App.xaml
App.xaml.cs
MainWindow.xaml
MainWindow.xaml.cs
Package.appxmanifest
Services/
AppSettings.cs
NavigationService.cs
Views/
HomePage.xaml
SettingsPage.xaml
ViewModels/
HomeViewModel.cs
SettingsViewModel.cs
MyApp.Core/
Models/
Services/
Storage/
tests/
MyApp.Core.Tests/
MyApp.WinUITests/
Responsibilities
| Area | Owns | Should not own |
|---|---|---|
App.xaml.cs | Startup, activation routing, top-level service wiring | Business rules or direct UI details |
MainWindow | Window creation, root navigation frame, title bar hooks | Data access or long-running jobs |
| Views | XAML layout and control events forwarded to view models | Package/runtime decisions |
| View models | UI state, commands, validation, service calls | Window.Current, direct HWND logic, platform bootstrap |
| Core library | Business logic, parsing, storage abstractions, pure tests | Microsoft.UI.Xaml types |
| WinUI test app | XAML/UI-thread tests using [UITestMethod] | Pure business logic tests that can run faster in Core tests |
| Package manifest | Identity, capabilities, activation, file/protocol associations | Secrets or environment-specific config |
Project File Shape
Keep version values fresh from official docs or the generated template. This is a shape, not a pinned version prescription:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net10.0-windows10.0.19041.0</TargetFramework>
<TargetPlatformMinVersion>10.0.17763.0</TargetPlatformMinVersion>
<UseWinUI>true</UseWinUI>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.WindowsAppSDK" Version="RECHECK_CURRENT_STABLE" />
</ItemGroup>
</Project>
Gotcha: Do not copy this
TargetFrameworkor package version blindly. The official quickstart and generated templates are the authority at implementation time.
Minimal Service Wiring
Manual wiring is enough for v1:
public sealed class AppServices
{
public AppServices()
{
Settings = new AppSettings();
Navigation = new NavigationService();
}
public AppSettings Settings { get; }
public NavigationService Navigation { get; }
}
Move to a dependency injection container only when construction becomes repetitive or tests need too many manual replacements.
Windows Integration Boundaries
| Feature | Starter stance |
|---|---|
| Settings | Use packaged app storage or a small settings service; do not assume unpackaged storage behavior |
| Notifications | Add only when the app has a concrete notification scenario and manifest activation plan |
| Windowing | Centralize AppWindow and HWND interop in one service |
| WebView2 | Keep optional; isolate navigation policy and user data folder choices |
| Background work | Do not port UWP IBackgroundTask; use Windows App SDK lifecycle/activation patterns or a separate service model |
| Store | Keep manifest identity clean from day one, even before submission |
What To Exclude From V1
- Custom installer.
- Sparse package.
- Self-contained runtime output.
- WebView2 unless web content is core to the product.
- Full MVVM framework unless the app already has enough screens to justify it.
- Multi-project modularization beyond one UI project and one core/testable library.