Software Architecture

What Is MVVM? A Modern Approach to App Architecture

What Is MVVM? A Modern Approach to App Architecture

Put a ViewModel between the View and the Model and you have MVVM, an architectural pattern for user interface applications. The screen binds to observable state and commands that the ViewModel exposes, and it never calls business logic directly.

Microsoft architect John Gossman announced Model-View-ViewModel on his blog in October 2005, aimed at WPF. Martin Fowler’s earlier Presentation Model had made developers write the synchronization code by hand, and WPF’s data binding engine replaced it (Gossman, Microsoft blog, 2005).

These days the pattern shows up on WPF, .NET MAUI, Android Jetpack and SwiftUI. Each of them ships observable state and bindings, which is really all MVVM asks of a platform.

What Is MVVM?

YouTube player

The name is short for Model-View-ViewModel. The ViewModel exposes observable state and commands, the View connects to them through data binding, and no View code talks to the Model directly.

The aim is to split UI code into roles with separate jobs and keep it decoupled from the rest of the app. Microsoft’s UWP guide puts data binding at the core of the pattern.

It isn’t a framework or a library. Toolkits implement the pattern, but they aren’t the pattern, and there’s no fixed recipe for it either. Like any software design pattern, MVVM can be implemented more than one way, and Microsoft’s UWP documentation says the exact definition gets blurry once frameworks bundle extra services into it.

The .NET MAUI documentation is plain about the direction of dependencies. A model is ignorant of the viewmodel, and a viewmodel is ignorant of the view.

What Does Each MVVM Component Do?

Dependencies only run one way, from View to ViewModel to Model. The Model holds data and business rules, and the View draws the interface. Everything in between, meaning Model state adapted into observable properties and commands, is the ViewModel’s job.

Model

Everything the app knows, regardless of screen, lives in the Model. That means domain entities, such as a Product with a name and a price, along with the services and repositories that load and save them. Business rules go here too.

Microsoft’s UWP data binding guide (last updated October 2022) notes that a fully built model layer can serve several clients, for example a UWP app and a web app on the same data.

What drives the global software industry?

Uncover software development statistics: industry growth, methodology trends, developer demographics, and the data behind modern software creation.

Discover Software Insights →

View

The View is the UI layer. It owns the layout and the controls, and it decides how everything looks. On XAML platforms it’s written as markup, with binding expressions that point at ViewModel members.

Code-behind still exists. Ideally it holds little more than the constructor and the line that sets the data context.

The usual way this goes wrong is a click handler that reaches into the database. Microsoft’s UWP guide describes code-behind files that pile up data access code, which then gets duplicated on other pages.

ViewModel

Observable properties live here, the values the View binds to, like a name or a loading flag. So do commands, which let the View trigger actions without a click handler.

View state belongs to the ViewModel too, things like selection and modes, or the display order of a list. The screen needs that data and the Model doesn’t. Converters end up here as well, the logic that turns Model types into types the View can show.

Gossman’s October 2005 description is shorter. It covers view state and data transformation, with commands on top.

The ViewModel holds no reference to the View. That one rule is what lets its logic run without a UI.

In a small project you can skip the Model layer entirely and let the ViewModel hold all the data the screen needs (Microsoft Learn, UWP data binding guide).

How Do the View, ViewModel and Model Communicate?

Input travels from View to ViewModel to Model, and state changes come back the other way. The View hands actions to the ViewModel through command bindings. The ViewModel pushes new values back through change notifications, which the binding engine picks up.

Take a single Save click.

  1. The user taps Save. The button’s Command property is bound to a SaveCommand on the ViewModel.
  2. The binding engine calls the command’s Execute method, and no click handler runs in the View.
  3. The ViewModel hands the edited data to the Model, usually a service or repository, to persist it.
  4. The ViewModel then sets a StatusMessage property, which raises PropertyChanged.
  5. The binding engine receives that event and updates the bound label. Neither the Model nor the ViewModel touches the label.

Data binding and data context

YouTube player

A binding ties a property on a control to a property on the ViewModel. The link between a View and its ViewModel is the data context, called DataContext in WPF and BindingContext in .NET MAUI.

Bindings run one way or both ways. One-way goes from ViewModel to View only, which suits display values such as a label showing the current time. Two-way sends changes in both directions, so editable fields, sliders and toggles use it.

Microsoft’s .NET MAUI guide says MVVM is often used with two-way bindings for interactive views. The same guide notes that .NET MAUI marshals binding updates to the UI thread, so ViewModel properties can change from any thread.

Gossman wrote in October 2005 that WPF’s binding engine automates the Observer-style wiring earlier UI frameworks left to developers, where the Model published change events and the View subscribed to them. He called that hand-written code repetitive and a source of bugs and performance problems.

Commands and change notification

YouTube player

Most of the traffic between a ViewModel and its View runs through a handful of .NET types.

TypeJobFires or runs when
INotifyPropertyChangedTells binding clients a property value changedThe ViewModel changes a property (PropertyChanged event)
ObservableCollection<T>Tells binding clients a list changedItems are added, removed or the list is refreshed (CollectionChanged event)
ICommandExposes an action the View can invokeThe user triggers a bound control (Execute, with CanExecute deciding if it is enabled)

A plain list does not implement the collection notification interface. That’s why a ViewModel exposes lists as ObservableCollection, and Microsoft’s API documentation states that a collection must implement INotifyCollectionChanged for insertions and deletions to update the UI automatically.

One catch, and it’s easy to miss. Unlike WPF, .NET MAUI does not automatically detect when the return value of CanExecute changes (as of the current .NET MAUI commanding documentation). A bound button can keep its old enabled state until the ViewModel signals the change itself.

Where Did MVVM Come From?

John Gossman, a Microsoft WPF architect, announced MVVM on his blog in October 2005 as a variation of Model-View-Controller for WPF. It descends from Martin Fowler’s Presentation Model, published on 19 July 2004.

Gossman built it for UI platforms where the View belongs to a designer rather than a classic developer.

  • On 19 July 2004, Fowler published Presentation Model and called view synchronization its most annoying part.
  • Gossman posted his introduction to Model/View/ViewModel for WPF apps on 8 October 2005.
  • Three days later, on 11 October 2005, he replied to Fowler’s complaint and said WPF’s data binding engine does the synchronization work.
  • Josh Smith published “WPF Apps with the Model-View-ViewModel Design Pattern” in MSDN Magazine in February 2009.

Read together, Fowler’s 2004 page and Gossman’s 2005 reply show where the practical difference sits. Presentation Model needed synchronization code, and WPF’s binding engine removed it.

Sources don’t agree on credit or on lineage. Wikipedia and O’Reilly’s Hands-On Design Patterns with C# and .NET Core name Microsoft architects Ken Cooper and Ted Peters as the inventors and say Gossman announced it, while DeviQ simply credits Gossman with introducing it in 2005. On the relationship to Presentation Model, Fowler’s page lists MVVM as an alternate name, Wikipedia calls it a variation, and Gossman called the two very similar.

Part of the divergence comes down to what counts as invention. Building the pattern inside Microsoft, publishing it and tying it to one platform’s UI technology are three different things. None of the sources I checked give a date for Cooper and Peters’s work, so Gossman’s October 2005 post is the earliest verifiable public description.

That post also shows the pattern in daily use. Gossman wrote that the whole Sparkle UI at Microsoft was defined with it, including the Library Panel.

How Does MVVM Differ From MVC and MVP?

YouTube player

What changes between them is the thing in the middle and how the View finds out about updates. MVC has a Controller. MVP has a Presenter, which holds a reference to the View. MVVM swaps that for a ViewModel with no View reference at all, and the binding engine updates the View automatically.

AspectMVCMVPMVVM
MediatorControllerPresenterViewModel
How the View updatesController pushes updatesPresenter pushes updates through a view interfaceBinding engine updates it automatically
Mediator holds a View referenceNoYesNo
Typical platformsServer-rendered webWinForms, WebFormsWPF, WinUI, .NET MAUI, Blazor, Angular, Vue

Table values follow DeviQ’s pattern comparison (page dated March 2026) and Wikipedia’s definition of the presenter.

Fowler’s description of MVP, quoted in Gossman’s October 2005 post, has the View handle mouse and keyboard events and delegate them to the presenter right away. In WPF, controls trigger Commands instead, and the ViewModel exposes those Commands.

Gossman’s reasoning for the whole family of variations is that the Controller in classic Model-View-Controller was always the odd one out. As UI technology advanced, the Controller got absorbed into the View or the framework itself.

Binding is the dividing line. On a platform without declarative data binding, Wikipedia notes that MVVM needs generated or hand-written glue, and MVP or MVC usually fits better.

For a longer side-by-side, see this MVC vs MVVM vs MVP breakdown.

Which Platforms and Frameworks Support MVVM?

Native support comes from .NET XAML platforms like WPF and .NET MAUI. Android, SwiftUI and JavaScript libraries such as Knockout.js have working equivalents. Whatever the platform, it has to supply observable state and some way to bind to it.

PlatformViewModel isBinding mechanismLanguage
WPF, .NET MAUIA class implementing INotifyPropertyChangedXAML bindingsC#
Android JetpackA ViewModel subclass exposing LiveData or StateFlowData Binding Library in layouts, or state collection in ComposeKotlin, Java
SwiftUIAn @Observable class (iOS 17 and later)Views read observable properties and SwiftUI re-rendersSwift
Knockout.jsA plain object with ko.observable propertiesdata-bind attributesJavaScript

.NET

WPF is where the pattern started, and .NET MAUI carries it forward. Microsoft ended Xamarin support, Xamarin.Forms included, on 1 May 2024 and points new projects to .NET MAUI, which it calls the evolution of Xamarin.Forms.

Android

YouTube player

The Jetpack ViewModel is a screen-level state holder. It caches state and keeps it through configuration changes such as rotation. LiveData is a lifecycle-aware observable holder that only updates observers in an active lifecycle state, and Kotlin StateFlow is the coroutine-based alternative, exposed from the ViewModel and collected by the UI. The Data Binding Library binds layout components to data sources declaratively and supports two-way binding.

In a Jetpack Compose app, the Android documentation calls ViewModel the primary way to expose screen UI state to composables. StateFlow comes from the Kotlin flows API, and the UI collects it with lifecycle awareness.

Android’s guidance says a ViewModel should not hold references to Context or Resources, because it can outlive its owner and leak memory.

SwiftUI

Apple describes SwiftUI’s mechanism as observable model data, and the ViewModel role maps onto it directly. Per Apple’s documentation (iOS 17 and macOS 14 onward, Xcode 15), you apply the Observable macro to a model class and a view updates when its body reads a property that changes.

The tracking is per property. In Apple’s State example, a subview refreshes when title changes but not when isAvailable changes, because its body reads only title.

Apps with a lower minimum deployment target use the ObservableObject protocol with published properties instead.

JavaScript

Knockout.js is built on observables, declarative bindings and templating. A property has to be declared with ko.observable before the view can react to its changes.

Sources split on Vue.js. DeviQ lists Vue among MVVM platforms, while Vue’s own v2 guide says the framework is not strictly associated with MVVM and was only partly inspired by it.

Why Is MVVM Easier to Test and Maintain?

YouTube player

A ViewModel needs no View type to run, so its logic can be exercised in a plain unit test with no window, no UI automation and no UI framework. Gossman gave the reason in March 2006. The ViewModel is more Model-like than View-like.

A typical unit test builds the ViewModel, runs a command and asserts on the exposed properties. DeviQ’s example runs a load command and checks that the Products collection holds one item.

The service behind the command is swapped for a mocked stand-in, so the test never touches a database or a network.

The benefits go beyond testing. Presentation logic becomes testable without UI automation, and isolated code is less likely to cause regressions when a bug is fixed (Microsoft’s UWP guide). Separate people or teams can build the View and the ViewModel against agreed interfaces and integrate later. Change stays local, which makes exploratory coding less risky.

Gossman’s 2006 post adds the maintenance angle. Abstracting the View cuts the business logic and glue code that piles up in code-behind.

The gain disappears the moment a ViewModel holds a View reference. One reference brings the UI framework back into every test, which is why Android’s guidance tells ViewModels to stay ignorant of UI implementation details.

How to Set Up MVVM in an App

YouTube player

Build the Model first, then the ViewModel, then the View, and test the ViewModel before any screen exists. The steps below use .NET, because Microsoft documents each of them first-hand.

  1. Define the Model: entities, plus a service interface that loads and saves them.
  2. Create the ViewModel class. Derive from ObservableObject or implement INotifyPropertyChanged by hand, and expose lists as ObservableCollection.
  3. Add a command for each user action, using RelayCommand or its generated version.
  4. Register the ViewModel and its services in a container so constructor parameters resolve on their own.
  5. Set the data context (BindingContext in .NET MAUI) and write the bindings in the View.
  6. Write a unit test that runs each command against a mocked service.

Most of the boilerplate in steps two and three goes away with CommunityToolkit.Mvvm, formerly Microsoft.Toolkit.Mvvm. The Microsoft Learn page was updated on 7 November 2024, and the package targets below were checked on NuGet (version 8.4.x). It targets .NET Standard 2.0, .NET Standard 2.1 and .NET 8, independent of any UI framework, although the Microsoft Learn page still lists .NET 6. It runs on WinUI 3, UWP, WinForms, WPF, Xamarin, Uno and more.

Microsoft maintains it as part of the .NET Foundation. The core types are ObservableObject, RelayCommand and AsyncRelayCommand, and Microsoft’s documentation says first-party Windows apps such as the Microsoft Store use the toolkit.

Its source generators remove most of the repetitive code. A private field marked ObservableProperty becomes a public property that raises PropertyChanged, and a method marked RelayCommand becomes a command (DeviQ’s sample declares the ViewModel as a partial class for this).

A dependency injection container is the natural way to build ViewModels, and the .NET MAUI documentation calls it ideal for creating ViewModel instances. If a ViewModel has constructor dependencies, the container creates and injects the services.

A view that takes a ViewModel parameter needs the view, the ViewModel and all of its dependencies registered. The same documentation cautions that dependency injection containers are not always suitable for a .NET MAUI app.

Two mistakes come up a lot. Passing a View or UI type into the ViewModel constructor is one. Registering the ViewModel but forgetting the page that consumes it is the other.

Many projects mirror the roles in folders named Models, Views and ViewModels. DeviQ’s sample uses a MyApp.ViewModels namespace for the same reason.

When MVVM Is the Wrong Choice

YouTube player

When the UI is simple, or when binding overhead outweighs the benefit, skip it. Its creator said as much. John Gossman wrote in March 2006 that for simple UI, MVVM can be overkill.

In bigger apps, designing a ViewModel up front with the right amount of generality is hard. Declarative bindings are also harder to debug than imperative code where you can set breakpoints, though Gossman adds that heavy event use may not be much different.

Then there’s the testing blind spot. A ViewModel test never loads the View, so a misspelled binding path passes the test and only shows up as a View that displays nothing. That one has cost me more time than I’d like to admit.

Gossman described a WPF build where loading a large file created 50,000 bindings at nearly 2K each, so the bindings outweighed the objects they bound. Replacing them with a single static callback saved nearly 100MB (Gossman, 4 March 2006).

He called ordinary binding performance quite good and said normal UI creates far fewer bindings. The cost shows up at volume.

Android adds a platform limit. Its documentation says not to use ViewModels as state holders for reusable UI components such as chip groups or forms.

Microsoft’s UWP guide makes the same argument from the other side. Every pattern has an adoption cost, and the guide suggests taking only the techniques with a clear benefit, since data binding plus layered code works with the Windows SDK alone.

Read together, the two sources point to a simple split. That split is my reading of their advice, not a rule either one states.

Screens that carry state such as selection, modes or loading flags are a good fit, and so are apps where several screens share services. If presentation logic needs unit tests, that settles it. A one-screen app with no tests planned can stay with code-behind, and honestly I wouldn’t bother with MVVM there.

Microsoft’s Traffic App sample ships a code-behind version and an MVVM version side by side, with notes describing the conversion.

MVVM FAQ

Is MVVM a design pattern or an architecture?

Both labels fit, at different scopes. Microsoft’s UWP guide calls MVVM a UI architectural design pattern, and Android’s data binding codelab calls it a presentation layer pattern, so it structures the UI layer rather than the whole app.

Does MVVM require two-way data binding?

No. MVVM needs a binding mechanism, and direction is a per-property choice. Android’s Data Binding Library, for example, offers two-way binding through its own notation alongside plain one-way expressions.

Is code-behind forbidden in MVVM?

No. Microsoft’s UWP guide says code-behind can still hold UI-only code, such as pulling data out of event handler arguments before calling a ViewModel method.

Business logic and data access stay out of it.

How many ViewModels does an MVVM app need?

Usually one per screen, not one per control. Android’s guidance treats the ViewModel as a screen-level state holder, and it warns that reusing one for several instances of the same component returns the same instance unless each gets its own key.

Can MVVM work without a framework or toolkit?

Yes. Microsoft’s UWP guide says to adopt only the techniques with a clear benefit.

CommunityToolkit.Mvvm is built a la carte with no mandatory patterns, so even with the toolkit you pick only the parts you use.

Moving a Code-Behind App to MVVM Screen by Screen

An existing code-behind app moves to MVVM one screen at a time. Start with the screen whose logic most needs tests and leave every other screen untouched.

On that screen, pull the commands and state out into a ViewModel first. Then move data access behind a service. Only after that do you bind the View and delete the handlers.

That order puts testable logic in place before any binding exists, so each step can be checked without a running screen.

Write each ViewModel for one screen, and extract shared logic only after a second screen repeats it. Treat every screen as its own code refactoring task, closed by a passing test.

The trade-off is mixed conventions. Code-behind screens and MVVM screens share the project until the last migration lands.

As of 30 October 2026, this sequence still holds as long as the UI framework supplies declarative data binding.

Bogdan Sandu

Stay sharp. Ship better code.

Every week: one curated article, one tool worth knowing, one tip you can use tomorrow. No noise, no padding.