Install
$ agentstack add skill-linuxdevel-avalonia-skills-avalonia-mvvm ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
Avalonia MVVM
Overview
MVVM: Model (data/business), View (.axaml), ViewModel (presentation logic, bindable state). ViewModel knows nothing about View. Views bind to ViewModel properties and commands.
INotifyPropertyChanged (Manual)
public class PersonViewModel : INotifyPropertyChanged
{
private string _name = "";
public string Name
{
get => _name;
set { _name = value; PropertyChanged?.Invoke(this, new(nameof(Name))); }
}
public event PropertyChangedEventHandler? PropertyChanged;
}
CommunityToolkit.Mvvm (Recommended)
Source-generator based, no reflection, clean code.
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
public partial class MainViewModel : ObservableObject
{
[ObservableProperty]
private string _name = "";
[ObservableProperty]
[NotifyCanExecuteChangedFor(nameof(SaveCommand))]
private bool _isDirty;
[RelayCommand(CanExecute = nameof(CanSave))]
private async Task SaveAsync()
{
// save logic
}
private bool CanSave() => IsDirty && !string.IsNullOrEmpty(Name);
}
NuGet: CommunityToolkit.Mvvm
Generated: Name property with change notification, NameChanged partial method hook, SaveCommand as AsyncRelayCommand.
ReactiveUI (Alternative)
using ReactiveUI;
public class MainViewModel : ReactiveObject
{
private string _name = "";
public string Name
{
get => _name;
set => this.RaiseAndSetIfChanged(ref _name, value);
}
public ReactiveCommand SaveCommand { get; }
public MainViewModel()
{
var canSave = this.WhenAnyValue(x => x.Name, n => !string.IsNullOrEmpty(n));
SaveCommand = ReactiveCommand.CreateFromTask(SaveAsync, canSave);
}
private async Task SaveAsync() { /* ... */ }
}
NuGet: Avalonia.ReactiveUI App setup: .UseReactiveUI() in Program.cs
ICommand (Manual)
public class RelayCommand : ICommand
{
private readonly Action _execute;
private readonly Func? _canExecute;
public RelayCommand(Action execute, Func? canExecute = null)
{ _execute = execute; _canExecute = canExecute; }
public event EventHandler? CanExecuteChanged;
public bool CanExecute(object? p) => _canExecute?.Invoke() ?? true;
public void Execute(object? p) => _execute();
public void RaiseCanExecuteChanged() => CanExecuteChanged?.Invoke(this, EventArgs.Empty);
}
ViewLocator Pattern
Auto-maps ViewModels → Views by naming convention (FooViewModel → FooView):
public class ViewLocator : IDataTemplate
{
public Control? Build(object? data)
{
if (data is null) return null;
var name = data.GetType().FullName!.Replace("ViewModel", "View");
var type = Type.GetType(name);
return type != null
? (Control)Activator.CreateInstance(type)!
: new TextBlock { Text = $"Not Found: {name}" };
}
public bool Match(object? data) => data is ViewModelBase;
}
Register in App.axaml:
ViewModel-First Navigation
Pattern: Router/NavigationViewModel holds current page ViewModel, ContentControl displays it:
public partial class MainViewModel : ObservableObject
{
[ObservableProperty]
private ViewModelBase _currentPage = new HomeViewModel();
public void NavigateTo(ViewModelBase page) => CurrentPage = page;
}
Design-Time DataContext
ObservableCollection for Lists
public ObservableCollection People { get; } = new();
Use ObservableCollection (not List) so UI updates on add/remove.
Community Libraries
| Library | NuGet / Repo | Purpose | |---|---|---| | CommunityToolkit.Mvvm | CommunityToolkit.Mvvm | Source-generator MVVM (ObservableObject, RelayCommand) — recommended | | ReactiveUI | Avalonia.ReactiveUI | Reactive MVVM with Rx.NET observables | | Prism | Prism.Avalonia | Full MVVM framework with regions, modules, DI, dialogs | | Epoxy | Epoxy.Avalonia | Lightweight multi-platform MVVM | | FuncUI | Avalonia.FuncUI | F# MVU pattern with view DSL | | ReactiveElmish.Avalonia | GitHub: JordanMarr/ReactiveElmish.Avalonia | F# MVU with XAML views | | Stylet.Avalonia | Stylet.Avalonia | Lightweight ViewModel-first MVVM (Caliburn.Micro-inspired) | | HanumanInstitute.MvvmDialogs | HanumanInstitute.MvvmDialogs.Avalonia | Open dialogs from ViewModel in pure MVVM | | ReactiveValidation | ReactiveValidation | Fluent-style property validation with UI messages | | Markup Declarative | Avalonia.Markup.Declarative | Declarative C# UI and MVU helpers | | Lemon.ModuleNavigation | GitHub: NeverMorewd/Lemon.ModuleNavigation | .NET Generic Host + module navigation | | AsyncNavigation | GitHub: NeverMorewd/AsyncNavigation | Async navigation via Microsoft.Extensions.DI |
Common Mistakes
- Using
Listinstead ofObservableCollection— list changes not reflected in UI - Not calling
PropertyChangedwith exact property name — usenameof() - Doing UI work in ViewModel (creating controls, accessing
DataContext) - Async command without
AsyncRelayCommand— exceptions swallowed, UI blocks - Forgetting
partialkeyword on CommunityToolkit ViewModel class — source gen fails silently
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: linuxdevel
- Source: linuxdevel/Avalonia-skills
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.