WPF Dispatcher Threading
Priority Levels (High to Low)
Priority Value Use Case
Send 10 Synchronous (avoid - deadlock risk)
Normal 9 Standard operations
DataBind 8 Binding updates
Render 7 Rendering operations
Loaded 6 Loaded event handlers
Input 5 User input processing
Background 4 Background tasks (UI stays responsive)
ContextIdle 3 After context operations
ApplicationIdle 2 App idle (cache cleanup)
SystemIdle 1 System idle
Inactive 0 Disabled
Common Patterns
Background Work (UI Responsive)
await Dispatcher.InvokeAsync(() => { // This runs between input processing ProcessNextChunk(); }, DispatcherPriority.Background);
After Render Complete
await Dispatcher.InvokeAsync(() => { // Runs after layout/render ScrollIntoView(lastItem); }, DispatcherPriority.Loaded);
Idle Cleanup
Dispatcher.InvokeAsync(() => { // Low priority cleanup ClearUnusedCache(); }, DispatcherPriority.ApplicationIdle);
Yielding Pattern
Keep UI responsive during long operations:
public async Task ProcessLargeDataAsync(IList<Item> items) { for (int i = 0; i < items.Count; i++) { Process(items[i]);
// Yield every 100 items to process pending input
if (i % 100 == 0)
{
await Dispatcher.Yield(DispatcherPriority.Background);
UpdateProgress(i, items.Count);
}
}
}
Threading Rules
// Check if on UI thread if (!Dispatcher.CheckAccess()) { Dispatcher.Invoke(() => UpdateUI()); return; }
// From background thread await Task.Run(() => { var result = HeavyComputation();
// Marshal back to UI
Dispatcher.Invoke(() => DisplayResult(result));
});
Avoid
// ❌ Send priority - can cause deadlock Dispatcher.Invoke(() => {}, DispatcherPriority.Send);
// ❌ Blocking UI thread Thread.Sleep(1000);
// ✅ Use async/await instead await Task.Delay(1000);