Periodic Updates for User Control Types (E.g. DataGrid/TextBoxes/etc) from DB in WPF with MVVM pattern?

# Postmort hospitaleem: Stale UI Data in WPF MVVM Due to Unhandled Database Changes

## Summary
A WPF MVVM application failed to reflect external database changes in UI controls (`DataGrid`, `TextBox`, etc.) because it lacked a mechanism to detect/apply live updates. This led users to act on **stale data**.

## Root Cause
The core failure was:
- **Single-fetch data loading** β€” Initial data bindings worked via `ObservableCollection`🧨 but only at startup
- **Zero external change detection** β€” No architecture to detect changes made outside the app (e.g., SSMS)
- **State unawareness** β€” Running data refreshes during user edits destroyed pending changes

## Why This Happens in Real Systems
Common architectural gaps:
- 🧾 **Assumption of data ownership**: Engineers assume no concurrent writes (false in multi-user systems)
- πŸ”„ **Polling complexity**: Implementing robust polling requires handling:
  - Thread safety
  - Update conflicts
  - Performance tuning
- βš–οΈ **State complexity**: Ignoring UI state (e.g., edit-in-progress) during refreshes

## Real-World Impact
- **Financial loss** β€” Trading apps showing outdated prices
- **Data corruption** β€” Forced refreshes overwriting user edits mid-transaction
- **Reputation damage** β€” Medical apps displaying incorrect patient vitals
- **UX failure** β€” Users losing trust in system accuracy

## Example or Code
```csharp
// RefreshService.cs (Polling Implementation)
public class RefreshService
{
    private readonly DispatcherTimer _refreshTimer;
    private readonly Action _refreshAction;
    private bool _isUserEditing;

    public RefreshService(Action refreshAction, TimeSpan interval)
    {
        _refreshAction = refreshAction;
        _refreshTimer = new DispatcherTimer { Interval = interval };
        _refreshTimer.Tick += (s, e) => CheckForUpdates();
    }

    public void Start() => _refreshTimer.Start();
    public void Pause() => _isUserEditing = true;
    public void Resume() => _isUserEditing = false;

    private void CheckForUpdates()
    {
        if (_isUserEditing) return;
        lock (_refreshAction)
        {
            _refreshAction.Invoke();
        }
    }
}
// ViewModel.cs (ateral Usage)
public class MainViewModel
{
    private RefreshService _refreshService;

    public MainViewModel()
    {
        _refreshService = new RefreshService(RefreshData, TimeSpan.FromSeconds(30));
        _refreshService.Start();
    }

    public void OnEditStarted() => _refreshService.Pause();
    public void OnEditCompleted() => _refreshService.Resume();

    private void RefreshData()
    {
        // Thread-safe DB fetch & ObservableCollection update
    }
}

How Senior Engineers Fix It

  1. Polling with locks:

    • Wrap refreshes in lock() blocks to prevent race conditions
    • Prioritize atomic operations for collection updates
  2. Edit-aware synchronization:

    • Freeze refreshes during edits using UI state flags
    • Implement dirty-checking to resume updates on save/cancel
  3. Optimized updates:

    • Use differential polling β€” Query DB for changes since last fetch
    • Apply INotifyPropertyChanged only to changed items
    • Partial refresh for complex screens:
      • Refresh only active controls
      • Scope updates to tab-specific data
  4. Advanced tooling:

    • πŸ’‘SQL Dependency for SQL Server immediate change alerts
    • Push notifications via SignalR for clustered systems

Why Juniors Miss It

  • πŸ” MVVM misconception: Belief that INotifyPropertyChanged auto-magically handles all updates
  • πŸ•ΈοΈ Thread negligence: Updating UI-bound objects without Dispatcher.Invoke
  • πŸ₯… Scope blindness: Attempting full-page refreshes instead of targeted updates
  • πŸ€” Over-engineering fear: Avoiding refreshes altogether due to conflict handling complexity