Skip to main content

Model-View-ViewModel (MVVM)

MVVM separates UI from logic with a bindable view-model that exposes state and commands, kept in sync with the view by data binding. It suits binding-first frameworks like WPF, MAUI, Angular, and Vue and makes presentation logic unit-testable.

Type
Architectural
When to Use
Data Binding Frameworks, Testable Presentation Logic, Rich Stateful Uis, Separate View From State

Model-View-ViewModel (MVVM) is an architectural pattern for UIs built on data binding. It splits an application into a model (data and business rules), a view (the UI markup), and a view-model (an abstraction of the view that exposes bindable properties and commands). The view-model holds presentation state and logic but knows nothing about specific view controls, making the presentation layer independently testable.

How It Works

The view binds its controls to properties and commands on the view-model. With two-way data binding, edits in the view flow into the view-model and changes in the view-model push back to the view automatically — no manual wiring of widget values. The view-model raises change notifications (e.g. INotifyPropertyChanged in .NET) so the binding engine knows what to update. Commands (such as ICommand) replace event handlers, exposing user actions as bindable objects.

The model supplies data; the view-model translates it into view-friendly shapes (formatted strings, enabled/disabled flags, validation messages). Because the view-model has no reference to UI controls, you can test it with plain unit tests.

When to Use It

MVVM is the natural fit for frameworks with first-class data binding: WPF, .NET MAUI, Xamarin, and JavaScript frameworks like Angular and Vue that bind templates to component state. It excels in rich, stateful client UIs where keeping widget state synchronized by hand would be error-prone, and where teams want to unit-test presentation logic without driving the UI.

Trade-offs

Data binding can hide complexity: debugging why a binding failed silently is frustrating, and overuse of binding magic obscures data flow. View-models can grow large and accumulate logic that belongs in the model. For very simple screens the binding infrastructure is overkill. Two-way binding also risks subtle update loops if not designed carefully. The pattern depends heavily on framework support; without a binding engine it is cumbersome to implement.

Related Patterns

MVVM is a sibling of MVC and MVP, differing in how the mediating layer connects to the view — through binding rather than direct manipulation. It relies on the observer pattern for change notification, and observable stores extend the same idea app-wide. Migrations such as Xamarin.Forms → .NET MAUI and Android Views → Jetpack Compose carry MVVM forward to newer UI toolkits (Compose pairs naturally with view-models and unidirectional state).

Example

public class LoginViewModel : INotifyPropertyChanged {
    private string _email = "";
    public string Email {
        get => _email;
        set { _email = value; OnChanged(nameof(Email)); OnChanged(nameof(CanSubmit)); }
    }
    public bool CanSubmit => Email.Contains('@');
    public ICommand SubmitCommand { get; }
    // ... INotifyPropertyChanged plumbing
}

The view binds a text box to Email and a button to SubmitCommand; the button enables automatically via CanSubmit, with no code-behind manipulating controls.