In this lesson, you will learn how to trigger efficient UI updates by implementing property change notifications that react precisely when data values are modified.
In high-performance UMG development, having your UI constantly "tick" to check if a value has changed is a waste of CPU cycles. Instead, we use the Observer pattern, where the UI "subscribes" to a property and only executes a refresh function when that specific property broadcasts a change.
The Mechanism
In C++, this is typically achieved using FSimpleMulticastDelegate or FDelegateHandle. When your ViewModel data changes, you trigger the delegate, and your View (the Widget) catches that signal to update its text or visuals.
Consider a simple health bar scenario. Rather than polling GetHealth() every frame, you attach a listener:
// In your ViewModel
DECLARE_MULTICAST_DELEGATE_OneParam(FOnHealthChanged, float);
FOnHealthChanged OnHealthChanged;
void UPlayerViewModel::SetHealth(float NewHealth) {
if (Health != NewHealth) {
Health = NewHealth;
// Notify subscribers only when the value actually changes
OnHealthChanged.Broadcast(Health);
}
}
Connecting to the Widget
In your Widget’s NativeConstruct, you bind a local function to that delegate:
void UMyPlayerWidget::NativeConstruct() {
Super::NativeConstruct();
// Subscribe to the delegate
if (ViewModel) {
ViewModel->OnHealthChanged.AddUObject(this, &UMyPlayerWidget::UpdateHealthBar);
}
}
void UMyPlayerWidget::UpdateHealthBar(float NewHealth) {
// This code ONLY runs when Health changes
HealthProgressBar->SetPercent(NewHealth / MaxHealth);
}
By shifting from "polling" to "pushing," you ensure that the UI remains performant regardless of how complex your data model becomes. The widget becomes a passive observer that sits idle until the ViewModel explicitly tells it that an update is required. This drastically reduces unnecessary layout invalidations and keeps your frame budget healthy.
Key Takeaway: Implement property change notifications to move from expensive per-frame polling to an event-driven system that updates your UI only when meaningful data changes occur.