Raise an event whenever a property's value changed?
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.
Introduction
In C#, the standard way to raise an event when a property changes is to implement the INotifyPropertyChanged interface. This interface defines a PropertyChanged event that fires whenever a property's value is set to a new value. It is the foundation of data binding in WPF, WinForms, and MAUI. For custom events beyond INotifyPropertyChanged, you can define your own event delegates. The pattern involves comparing the old and new values in the property setter, updating the backing field, and then invoking the event.
INotifyPropertyChanged (Standard Pattern)
The [CallerMemberName] attribute automatically fills in the property name, eliminating magic strings. The if (_name != value) check prevents unnecessary event firing when the same value is assigned.
Generic SetProperty Helper
The SetProperty helper reduces boilerplate to a single line per property. It returns true if the value changed, useful for triggering additional logic.
Custom Event with Old and New Values
Custom events can carry the old and new values, enabling undo/redo systems, validation, and logging.
WPF Data Binding Example
WPF's binding system listens for PropertyChanged events and updates the UI automatically. This is the primary use case for INotifyPropertyChanged.
CommunityToolkit.Mvvm (Source Generators)
The MVVM Toolkit's [ObservableProperty] attribute uses source generators to create the full property with change notification at compile time. This is the modern approach for .NET 6+ projects.
JavaScript/TypeScript Equivalent
Common Pitfalls
- Raising event before updating the backing field: If you fire
PropertyChangedbefore assigning the new value to the field, event handlers that read the property will get the old value. Always update the field first, then raise the event. - Forgetting the equality check: Without
if (_name != value), setting the same value triggers the event and causes unnecessary UI updates, which can lead to infinite loops in two-way data binding scenarios (setter fires event, binding sets value, setter fires event again). - Using string literals instead of
nameof:OnPropertyChanged("Name")works but breaks silently if you rename the property. Use[CallerMemberName]ornameof(Name)so the compiler catches renames. - Not raising events for dependent properties: If
FullNamedepends onFirstNameandLastName, changingFirstNamemust also raisePropertyChangedforFullName. Missing this causes the UI to show stale computed values. - Thread safety with event invocation:
PropertyChanged?.Invoke(...)is not thread-safe if subscribers are added/removed concurrently. In multi-threaded scenarios, capture the delegate in a local variable first:var handler = PropertyChanged; handler?.Invoke(...).
Summary
- Implement
INotifyPropertyChangedto raise events when properties change in C# - Use
[CallerMemberName]to automatically pass the property name without magic strings - Create a
SetProperty<T>helper method in a base class to reduce per-property boilerplate - Use
CommunityToolkit.Mvvmwith[ObservableProperty]for zero-boilerplate source-generated properties - Always check for value equality before raising the event to prevent infinite loops in data binding
- Update the backing field before invoking the event so handlers read the new value
Related reading
- Rancher with cattle vs Rancher with Kubernetes vs Standalone Kubernetes
- RDS with Cloud Formation and AZ issues
- Re-using environment variables in docker-compose.yml
- Re-using existing volume with docker compose
- Raising C events with an extension method - is it bad?
- Raising PropertyChanged in asynchronous Task and UI Thread
- react-router nginx ingress refresh causes white screen when path is not /
- Readiness probe for statefulset, not individual pod/container

System Design Fundamentals
Build a strong foundation in designing scalable, reliable distributed systems.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.