A modern Avalonia UI desktop application showcasing best practices for building .NET cross-platform apps with the MVVM pattern, AOT compilation, and internationalization.
| Category | Library | Version |
|---|---|---|
| UI Framework | Avalonia | 12.0 |
| MVVM | ReactiveUI + Source Generators | 12.0 / 3.x |
| DI | Splat | 19.4 |
| Theme | Semi.Avalonia + Ursa | 12.0 / 2.0 |
| Icons | Optris.Icons.Avalonia (Material Design) | 12.0 |
| Markdown | LiveMarkdown.Avalonia | 2.2 |
| Logging | NLog via Splat.NLog | 5.x |
| Runtime | .NET 10 / AOT (PublishAot) |
Program.cs ← Composition root (DI registration)
├── App.axaml ← Theme, styles, ViewLocator
├── Services/
│ ├── ILocalizationService ← Interface (testable)
│ ├── LocalizationService ← en-US / zh-Hans via .resx
│ └── LocalizationSource ← INotifyPropertyChanged bridge for XAML bindings
├── ViewModels/
│ ├── ViewModelBase ← ReactiveObject + activation lifecycle
│ ├── MainWindowViewModel ← Injects MainViewModel
│ ├── MainViewModel ← Injects IEnumerable<IPageViewModel>
│ └── Pages/
│ ├── IPageViewModel ← Page contract (testable)
│ ├── PageViewModel ← Base class with locale-aware Name
│ ├── HomePageViewModel ← Markdown welcome page
│ └── BindingPageViewModel ← Binding demo (commands, collections)
├── Views/
│ ├── MainWindow ← Title bar, language toggle, theme toggle
│ ├── MainView ← NavMenu sidebar + page host
│ └── Pages/
│ ├── HomePageView ← LiveMarkdown renderer
│ └── BindingPageView ← Compiled AXAML bindings demo
└── Utils/
└── PageExtensions ← Page registration into DI
- Constructor injection — all dependencies declared explicitly; composition root in
Program.cs - AOT-safe ViewLocator — type dictionary mapping instead of
Type.GetType()reflection - Compiled bindings —
<AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>, bindings declared in AXAML withx:DataType - Interface-based —
ILocalizationService,IPageViewModelfor testability - Activation lifecycle — all event subscriptions managed by
WhenActivated/DisposeWith - Localization — real-time English/Simplified Chinese switching; satellite assemblies relocated for AOT
- Sidebar navigation — Ursa
NavMenuwithViewModelViewHostpage switching - ReactiveUI binding showcase — Two-way, Command, Boolean, and Collection bindings
- Light/Dark/System theme — Semi.Avalonia + Ursa
ThemeToggleButton - Live language switching — CultureChanged propagates to all Views via
INotifyPropertyChanged - Markdown home page — Locale-aware content rendered with LiveMarkdown
cd src
dotnet runPublish with AOT:
dotnet publish -c Release -r win-x64src/
└── AvaloniaProject/ ← Single .NET 10 project
├── Program.cs ← Entry point
├── App.axaml/.cs ← Application definition
├── ViewLocator.cs ← ViewModel→View resolution
├── Services/ ← Business services + interfaces
├── ViewModels/ ← MVVM ViewModels (Pages/)
├── Views/ ← AXAML Views (Pages/)
├── Utils/ ← Extension methods
├── Resources/ ← .resx (EN + zh-Hans)
└── Assets/ ← logo.ico