Skip to content

7. Threading extension 🧡

ScarletKuro edited this page Feb 15, 2026 · 1 revision

Threading Extension

Package: Extensions.Hosting.Wpf.Threading

This extension enables switching between the WPF Main UI Thread and background ThreadPool threads using Microsoft.VisualStudio.Threading. This is particularly useful when you need to perform UI operations from a background thread, such as showing a dialog during a network request.

Installation

Install-Package Extensions.Hosting.Wpf.Threading

Setup

Register the thread switching services in ConfigureServices:

private static void ConfigureServices(HostBuilderContext hostContext, IServiceCollection services)
{
    services.AddWpf<App>();
    services.AddThreadSwitching(); // <-- Add this line
}

This registers two services:

  • JoinableTaskContext β€” initialized with the WPF thread and its SynchronizationContext
  • JoinableTaskFactory β€” the factory used to switch threads

Generic Overload

If you need the generic version (e.g., for specific TApplication resolution):

services.AddThreadSwitching<App>();

Usage

Inject JoinableTaskFactory into any class that needs thread switching:

private readonly JoinableTaskFactory _joinableTaskFactory;

public MyService(JoinableTaskFactory joinableTaskFactory)
{
    _joinableTaskFactory = joinableTaskFactory;
}

Switch to the Main UI Thread

private async Task SomeOperationAsync()
{
    // Currently on a background thread...

    // Switch to the Main UI thread
    await _joinableTaskFactory.SwitchToMainThreadAsync();

    // Now on the UI thread β€” safe to manipulate UI elements
    myWindow.Show();
}

Switch to a Background Thread

private async Task SomeOperationAsync()
{
    // Currently on the UI thread...

    // Switch to a threadpool thread
    await TaskScheduler.Default;

    // Now on a background thread β€” do heavy computation
    var result = await DoExpensiveWorkAsync();

    // Switch back to UI thread to show results
    await _joinableTaskFactory.SwitchToMainThreadAsync();
    DisplayResult(result);
}

Full Example

private readonly JoinableTaskFactory _joinableTaskFactory;

public SomeViewModel(JoinableTaskFactory joinableTaskFactory)
{
    _joinableTaskFactory = joinableTaskFactory;
}

private async Task LoadDataAsync()
{
    // On the caller's thread
    await DoAsync();

    // Explicitly switch to a threadpool thread
    await TaskScheduler.Default;

    // Do background work
    var data = await FetchDataFromApiAsync();

    // Switch to the Main thread to update UI-bound properties
    await _joinableTaskFactory.SwitchToMainThreadAsync();
    Items = data;
}

How It Works

When you call AddThreadSwitching(), the library:

  1. Retrieves the IWpfThread service (which holds the WPF thread reference and its SynchronizationContext)
  2. Creates a JoinableTaskContext initialized with the WPF main thread and synchronization context
  3. Registers JoinableTaskFactory as a singleton

This ensures that SwitchToMainThreadAsync() correctly targets the WPF dispatcher thread.

More Information

For advanced use cases (deadlock avoidance, nested joins, etc.), see the Microsoft.VisualStudio.Threading repository.

Clone this wiki locally