Skip to content

Repository files navigation

SimpleViewModel

A lightweight WPF ViewModel framework with automatic source generation that eliminates boilerplate code while maintaining full control over your view models.

NuGet VersionNuGet DownloadsLicense: MIT

Features

  • Zero Boilerplate Commands: Transform methods into ICommand properties with a simple [Command] attribute
  • Automatic Property Binding: Generate observable properties from fields using [Bind] attribute
  • Source Generation: All code generation happens at compile time with no runtime reflection
  • Lightweight: Minimal dependencies and overhead
  • Type Safe: Full IntelliSense support and compile-time validation
  • WPF Optimized: Built specifically for WPF applications with proper CommandManager integration

Table of Contents

Quick Start

Installation

<PackageReferenceInclude="SimpleViewModel"Version="0.9.7" />

Basic Usage

  1. Create a ViewModel:
usingSimpleViewModel;usingSimpleViewModel.BaseClasses;[ViewModel]publicpartialclassMainViewModel{[Command]publicvoidSaveData(){// Your save logic hereMessageBox.Show("Data saved!");}[Command]publicvoidLoadData(){// Your load logic hereMessageBox.Show("Data loaded!");}}
  1. Bind to XAML:
<Windowx:Class="MyApp.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StackPanel>
<ButtonContent="Save"Command="{Binding SaveDataCommand}" />
<ButtonContent="Load"Command="{Binding LoadDataCommand}" />
</StackPanel>
</Window>
  1. Set DataContext:
publicpartialclassMainWindow:Window{publicMainWindow(){InitializeComponent();DataContext=newMainViewModel();}}

That's it! The source generator automatically creates SaveDataCommand and LoadDataCommand properties for you.

Advanced Features

Observable Properties

Use the [Bind] attribute to automatically generate observable properties:

[ViewModel]publicpartialclassUserViewModel{[Bind]privatestring_firstName="";[Bind]privatestring_lastName="";[Bind]privateint_age;}

Generated code includes proper INotifyPropertyChanged implementation:

publicstringFirstName{
get =>_firstName;
set =>SetProperty(ref_firstName,value);}

Property Change Callbacks

Add custom logic when properties change:

[ViewModel]publicpartialclassUserViewModel{[Bind(OnChangeMethodName=nameof(OnNameChanged))]privatestring_name="";privatevoidOnNameChanged(){// Custom logic when name changesConsole.WriteLine($"Name changed to: {_name}");}}

Command with CanExecute

Commands can include conditional execution logic:

[ViewModel]publicpartialclassDocumentViewModel{[Bind]privatestring_selectedItem="";[Command(CanExecuteMethodName=nameof(CanDelete))]publicvoidDelete(){// Delete logic hereConsole.WriteLine($"Deleting {_selectedItem}");}publicboolCanDelete(){return!string.IsNullOrEmpty(_selectedItem);}}

Command with Parameters

Commands automatically support parameters through the Execute method:

[ViewModel]publicpartialclassDocumentViewModel{[Command]publicvoidDeleteItem(){// Note: Parameter handling is done in the generated command class// The method itself doesn't need to accept parameters}}

How It Works

SimpleViewModel uses Roslyn source generators to analyze your code at compile time and automatically generate:

  1. Partial ViewModel Class: Extends your class to inherit from BaseViewModel
  2. Command Classes: Each [Command] method gets a corresponding command class that inherits from BaseCommand
  3. Command Properties: Properties that expose the commands for data binding (lazily initialized)
  4. Observable Properties: Properties with INotifyPropertyChanged support for [Bind] fields

All generated code is available in IntelliSense and can be debugged normally.

Generated Code Example

Your Code:

[ViewModel]publicpartialclassMyViewModel{[Command]publicvoidDoSomething()=>Console.WriteLine("Done!");}

Generated ViewModel Extension:

publicpartialclassMyViewModel:BaseViewModel{privateCommand_DoSomething?_DoSomethingCommand{get;set;}publicCommand_DoSomethingDoSomethingCommand=>_DoSomethingCommand??=new(this);}

Generated Command Class:

publicsealedclassCommand_DoSomething:BaseCommand{privatereadonlyMyViewModelvm;publicCommand_DoSomething(MyViewModelvm){this.vm=vm;}publicoverridevoidExecute(object?parameter){vm.DoSomething();}}

Best Practices

  1. Use Partial Classes: Always mark your view models as partial to allow source generation
  2. Apply ViewModel Attribute: Use [ViewModel] on your class - the generator automatically makes it inherit from BaseViewModel
  3. Field Naming: Use underscore prefixes for fields marked with [Bind] (e.g., _title becomes Title property)
  4. Async Commands: For async operations, use async void in command methods
  5. Parameter Validation: Commands receive parameters through the Execute(object? parameter) method in the generated class
  6. Dependency Injection: Use constructor injection for services and dependencies

Troubleshooting

Generator Not Running

If the source generator isn't creating commands:

  1. Ensure you have the [ViewModel] attribute on your class
  2. Make sure the class is marked as partial
  3. Check that methods have the [Command] attribute and are public
  4. Verify fields have the [Bind] attribute for observable properties
  5. Clean and rebuild your solution

Missing Commands in XAML

If commands aren't appearing in XAML IntelliSense:

  1. Rebuild the project to trigger source generation
  2. Check that the generated files are created (enable <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles> to see them)
  3. Ensure proper namespace imports in XAML

Common Issues

  • Fields not generating properties: Make sure fields are marked with [Bind] and are private
  • Commands not working: Ensure methods are public and marked with [Command]
  • CanExecute not working: Verify the method name in CanExecuteMethodName exists and is public with bool return type

Requirements

  • .NET 8.0 or .NET 9.0 (Windows targets only)
  • Windows (WPF applications only)
  • C# 10.0 or later

License

MIT License - see LICENSE file for details.

Contributing

Contributions are welcome! Please feel free to submit issues and pull requests.

Repository


Built with ❤️ for the WPF community

About

Lightweight WPF MVVM framework with source generation - automatic commands and observable properties from attributes. Zero boilerplate, full type safety.

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Contributors

Languages