Skip to content

1. Big Picture

WPF is a reactive UI framework. It does not “pull” data from your objects — it waits for signals.

If your data changes but you don’t send a signal, the UI simply does not know anything happened.

That’s why change tracking exists:

  • Without it → UI becomes stale, incorrect
  • With it → UI stays in sync automatically

2. Beginner Mental Model

Key idea:

WPF does NOT poll your data. It listens for notifications.

Think of it like this:

  • ❌ Normal C# object → “silent”
  • ✅ ViewModel with notifications → “talkative”

The UI subscribes to your object:

“Hey, tell me when something changes.”

If your object never speaks → UI never updates.


3. Basic Example

❌ Broken: No notification

csharp
public class MachineViewModel
{
    public int Temperature { get; set; }
}
xml
<TextBlock Text="{Binding Temperature}" />
csharp
viewModel.Temperature = 100;

👉 UI does NOT update Because nothing told WPF that the value changed.


✅ Working: With INotifyPropertyChanged

csharp
using System.ComponentModel;

public class MachineViewModel : INotifyPropertyChanged
{
    private int _temperature;

    public int Temperature
    {
        get => _temperature;
        set
        {
            if (_temperature != value)
            {
                _temperature = value;
                OnPropertyChanged(nameof(Temperature));
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

Now:

csharp
viewModel.Temperature = 100;

👉 UI updates immediately


4. Implementation Pattern

Standard pattern (you’ll write this a lot)

csharp
public class BaseViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    protected bool SetProperty<T>(ref T field, T value, string propertyName)
    {
        if (EqualityComparer<T>.Default.Equals(field, value))
            return false;

        field = value;
        OnPropertyChanged(propertyName);
        return true;
    }
}

Usage:

csharp
public class MachineViewModel : BaseViewModel
{
    private int _temperature;

    public int Temperature
    {
        get => _temperature;
        set => SetProperty(ref _temperature, value, nameof(Temperature));
    }
}

Why nameof matters

  • Safe refactoring
  • No magic strings
  • Avoid silent bugs

5. How It Really Works in WPF

What happens when binding is created?

xml
<TextBlock Text="{Binding Temperature}" />

WPF does roughly:

  1. Resolve DataContext
  2. Find property Temperature
  3. Check:
    • Does object implement INotifyPropertyChanged?

👉 If YES:

  • Subscribe to PropertyChanged event

What happens when value changes?

csharp
OnPropertyChanged("Temperature");

WPF:

  1. Receives event
  2. Checks property name
  3. Re-reads property value
  4. Pushes new value into UI element (DependencyProperty)

Important relationship

  • Your ViewModel → uses INotifyPropertyChanged
  • UI elements → use Dependency Properties

Flow:

ViewModel.Property → Binding → UI.DependencyProperty

   PropertyChanged event triggers update

6. Real-World Example

Scenario 1: Live Dashboard (machine monitoring)

csharp
public class MachineViewModel : BaseViewModel
{
    private double _pressure;
    public double Pressure
    {
        get => _pressure;
        set => SetProperty(ref _pressure, value, nameof(Pressure));
    }
}

Background thread:

csharp
while (true)
{
    viewModel.Pressure = ReadSensor();
    await Task.Delay(100);
}

👉 Every update triggers UI refresh 👉 This is how real-time dashboards work


Scenario 2: Form Editing

csharp
<TextBox Text="{Binding UserName, UpdateSourceTrigger=PropertyChanged}" />

User types:

  • Each keystroke updates ViewModel
  • ViewModel raises PropertyChanged
  • UI stays in sync (validation, computed fields, etc.)

Change flow in real app:

User input / device data

ViewModel property set

PropertyChanged raised

Binding engine notified

UI updated

7. Common Mistakes

❌ Forgetting to raise PropertyChanged

csharp
_temperature = value; // UI will NOT update

❌ Wrong property name

csharp
OnPropertyChanged("Temp"); // typo → silent failure

❌ Updating field instead of property

csharp
viewModel._temperature = 100; // bypass notification

❌ Replacing object without notifying

csharp
public Machine Machine { get; set; }
csharp
Machine = new Machine(); // UI won’t update unless you notify

Fix:

csharp
private Machine _machine;
public Machine Machine
{
    get => _machine;
    set => SetProperty(ref _machine, value, nameof(Machine));
}

❌ Nested property changes

csharp
Machine.Temperature = 100;

If Machine does NOT implement INotifyPropertyChanged → UI won’t update


8. Performance Considerations

Problem: Too many updates

Example:

  • Sensor updates every 10ms
  • UI redraws every 10ms

👉 UI thread gets overloaded → lag / freeze


Strategies

1. Throttling

Update UI less frequently

csharp
// update every 200ms instead of 10ms

2. Change filtering

csharp
if (Math.Abs(_temperature - value) < 0.1)
    return;

3. Batch updates

Instead of:

csharp
Prop1 changed
Prop2 changed
Prop3 changed

→ Consider raising a single refresh signal (carefully)


Key insight:

PropertyChanged is cheap… until it isn’t (in high-frequency systems)


9. Practical Guidance

Structure your ViewModels like this:

  • One ViewModel per screen/component
  • Always inherit from a base class
  • Always use SetProperty

Reduce boilerplate

Options:

  • Base class (as shown)
  • MVVM libraries:
    • CommunityToolkit.Mvvm ([ObservableProperty])
    • Prism
    • ReactiveUI

Be intentional about updates

Ask:

  • Does UI need this update?
  • How often?
  • What is the cost?

For collections

Use:

csharp
ObservableCollection<T>

Why:

  • It raises change notifications for:
    • Add
    • Remove
    • Reset

Normal List<T> → UI will NOT update


10. Summary

Core ideas to remember

  • WPF does not poll data
  • UI updates only when notified

INotifyPropertyChanged

  • Provides change notification mechanism
  • Binding engine subscribes to it
  • UI updates when event is raised

Critical rules

  • Always raise PropertyChanged
  • Use nameof
  • Never update fields directly
  • Be careful when replacing objects

Real-world mindset

  • Change tracking = correctness
  • Over-notifying = performance issues
  • Under-notifying = broken UI

Final mental model

Your ViewModel is a signal emitter. If it doesn’t emit signals → the UI is blind.

Docs-first project memory for AI-assisted implementation.