WPF
Asynchronous Workflows
Background Operations
C#
.NET

WPF background operations using Asynchronous Workflows

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

WPF applications feel slow when long-running work blocks the dispatcher thread. The fix is not “use threads everywhere”. The fix is to choose the right asynchronous pattern for the kind of work you have, keep UI updates on the dispatcher, and make cancellation and progress part of the design.

Distinguish I O-Bound Work from CPU-Bound Work

The first decision is whether the operation waits on an external resource or burns CPU locally. Network calls, database queries, and file reads are usually I/O-bound. Parsing a huge document, resizing an image, or computing a report is usually CPU-bound.

For I/O-bound work, prefer native async APIs and await them directly.

csharp
1using System.Net.Http;
2using System.Threading.Tasks;
3using System.Windows;
4
5public partial class MainWindow : Window
6{
7    private readonly HttpClient _http = new HttpClient();
8
9    public MainWindow()
10    {
11        InitializeComponent();
12    }
13
14    private async void LoadButton_Click(object sender, RoutedEventArgs e)
15    {
16        StatusText.Text = "Loading...";
17        string text = await _http.GetStringAsync("https://example.com");
18        StatusText.Text = text[..40];
19    }
20}

This keeps the window responsive because the request is not blocking the dispatcher thread while the process waits for the server.

For CPU-bound work, use Task.Run so the expensive loop executes on a worker thread.

csharp
1using System.Threading.Tasks;
2using System.Windows;
3
4private async void ComputeButton_Click(object sender, RoutedEventArgs e)
5{
6    StatusText.Text = "Computing...";
7
8    int result = await Task.Run(() =>
9    {
10        int sum = 0;
11        for (int i = 0; i < 10_000_000; i++)
12        {
13            sum += i % 7;
14        }
15        return sum;
16    });
17
18    StatusText.Text = result.ToString();
19}

If you swap those patterns, you usually create unnecessary complexity. Task.Run does not make an already-async web request more correct, and awaiting a CPU-heavy loop directly still freezes the window.

Return to the Dispatcher for UI Updates

WPF controls belong to the UI thread. In a normal event handler, code after await resumes on the dispatcher by default, so control updates are safe.

csharp
1private async void SaveButton_Click(object sender, RoutedEventArgs e)
2{
3    StatusText.Text = "Saving...";
4    await SaveDocumentAsync();
5    StatusText.Text = "Saved";
6}

The problem appears when background code tries to update UI elements directly. When you truly need to hop back to the UI thread manually, use the dispatcher.

csharp
1await Dispatcher.InvokeAsync(() =>
2{
3    StatusText.Text = "Done";
4    ProgressBar.Value = 100;
5});

Keep that boundary clean. Background methods should return data, status, or events. They should not secretly manipulate controls.

Add Cancellation and Progress Early

A responsive application is not just one that avoids freezing. It should also let the user cancel work that no longer matters and show that progress is happening.

csharp
1using System;
2using System.Threading;
3using System.Threading.Tasks;
4
5private CancellationTokenSource? _cts;
6
7private async void StartButton_Click(object sender, RoutedEventArgs e)
8{
9    _cts = new CancellationTokenSource();
10    ProgressBar.Value = 0;
11
12    var progress = new Progress<int>(value => ProgressBar.Value = value);
13
14    try
15    {
16        await Task.Run(() => ProcessItems(progress, _cts.Token));
17        StatusText.Text = "Finished";
18    }
19    catch (OperationCanceledException)
20    {
21        StatusText.Text = "Canceled";
22    }
23}
24
25private void CancelButton_Click(object sender, RoutedEventArgs e)
26{
27    _cts?.Cancel();
28}
29
30private void ProcessItems(IProgress<int> progress, CancellationToken token)
31{
32    for (int i = 0; i < 100; i++)
33    {
34        token.ThrowIfCancellationRequested();
35        Thread.Sleep(20);
36        progress.Report(i + 1);
37    }
38}

This pattern scales better than bolting cancellation onto the code later. It also forces you to define where a long-running operation may stop safely.

Avoid Legacy Threading Unless You Need It

Older WPF code often uses BackgroundWorker, explicit Thread creation, or callback-heavy patterns. They still exist, but async and await are usually clearer. The call flow reads top to bottom, exceptions propagate more naturally, and composition is much easier.

That does not mean every async method is good by default. It means the language now gives you a simpler model for the common case, so use that model unless you have a specific need for something lower level.

Common Pitfalls

  • Using Task.Run for naturally asynchronous I/O work that should simply be awaited.
  • Running CPU-heavy code directly on the dispatcher thread.
  • Updating WPF controls from a worker thread.
  • Exposing async void methods outside event handlers.
  • Ignoring cancellation until the operation is already large and hard to interrupt.
  • Assuming async automatically improves performance even when the real problem is inefficient work.

Summary

  • In WPF, background work exists to protect the dispatcher thread.
  • Await native async APIs for I/O-bound operations.
  • Use Task.Run for synchronous CPU-bound work.
  • Update controls only from the UI thread.
  • Design long-running workflows with progress and cancellation, not just offloading.

Related reading
Course
Intermediate
27 lessons
14 hours
OOD Fundamentals

Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.