<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/switching-back-to-the-ui-thread-in-wpf-uwp-in-modern-c--zltvjtle0" -->

---
title: Switching back to the UI thread in WPF/UWP, in modern C#
description: A deep dive into switching to the UI thread in WPF/UWP (and transferable to WinForms) using modern C# async machinery. Starts from the classic...
canonical: https://daily.dev/posts/switching-back-to-the-ui-thread-in-wpf-uwp-in-modern-c--zltvjtle0
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: Switching back to the UI thread in WPF/UWP, in modern C# | daily.dev
og:description: A deep dive into switching to the UI thread in WPF/UWP (and transferable to WinForms) using modern C# async machinery. Starts from the classic...
og:url: https://daily.dev/posts/switching-back-to-the-ui-thread-in-wpf-uwp-in-modern-c--zltvjtle0
og:image: https://api.daily.dev/og/posts/zLtVJtLE0.png
og:image:alt: Switching back to the UI thread in WPF/UWP, in modern C#
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Switching back to the UI thread in WPF/UWP, in modern C#

**[Kevin Gosse \(minidump.net\)](https://daily.dev/sources/minidump)** · 8 min read · 0 upvotes · 0 comments

## Summary

A deep dive into switching to the UI thread in WPF/UWP (and transferable to WinForms) using modern C# async machinery. Starts from the classic Dispatcher.BeginInvoke approach, moves to a custom awaiter (SwitchToUi) built on INotifyCompletion, then goes further by implementing a custom AsyncMethodBuilder and custom task type (UiTask/UiTaskMethodBuilder) so that an async method's return type alone signals that it should run on the UI thread. Includes full code for the awaiter, the custom task, and the method builder (Start, SetResult, SetException, AwaitOnCompleted, AwaitUnsafeOnCompleted), plus a note on the overhead trade-off and a link to a C# language proposal that could let this be expressed as a custom attribute instead.

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://minidump.net/switching-back-to-the-ui-thread-in-wpf-uwp-in-modern-c-5dc1cc8efa5e>

## Questions this post answers

### How can I make a C# async method automatically run on the WPF UI thread without manually checking Dispatcher.CheckAccess every time?

Define a custom task type (e.g. UiTask) annotated with the AsyncMethodBuilder attribute pointing to a custom method builder (UiTaskMethodBuilder). The builder's Start method checks Dispatcher.CheckAccess() and, if not on the UI thread, calls Dispatcher.BeginInvoke to run the state machine there; AwaitOnCompleted and AwaitUnsafeOnCompleted do the same after each await, so simply declaring the method's return type as UiTask forces it onto the UI thread.

_daily.dev surfaces deep dives like custom async method builders for developers wiring up WPF UI-thread patterns._

### What is the difference between implementing a custom awaiter and a custom AsyncMethodBuilder for switching to the UI thread in C#?

A custom awaiter (implementing INotifyCompletion with IsCompleted, OnCompleted, and GetResult) requires an explicit await call like 'await Dispatcher.SwitchToUi()' inside the method body, while a custom AsyncMethodBuilder paired with a custom task type lets the method's return type itself (e.g. UiTask) signal that the whole method, including its first line, runs on the UI thread, removing that boilerplate line entirely.

_Developers comparing async patterns for desktop UI threading can find implementation trade-offs like these on daily.dev._

## Similar posts on daily.dev

- [WinUI vs WPF vs UWP](https://daily.dev/posts/winui-vs-wpf-vs-uwp-gbasfyqfh) · Avalonia UI Blog · 0 upvotes · 0 comments
- [Demystifying async/await in C\#: The Hidden State Machine](https://daily.dev/posts/demystifying-async-await-in-c-the-hidden-state-machine-ej0npqym4) · C\# Corner · 0 upvotes · 0 comments
- [Async or Swim: The Complete Guide to Asynchronous .NET](https://daily.dev/posts/async-or-swim-the-complete-guide-to-asynchronous-net-n2fszfnf6) · ITNEXT · 9 upvotes · 1 comments

---

Tags: [#.net](https://daily.dev/tags/.net), [#c#](https://daily.dev/tags/c#), [#wpf](https://daily.dev/tags/wpf)

[View this post on daily.dev](https://daily.dev/posts/switching-back-to-the-ui-thread-in-wpf-uwp-in-modern-c--zltvjtle0)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"TechArticle","headline":"Switching back to the UI thread in WPF/UWP, in modern C#","url":"https://daily.dev/posts/switching-back-to-the-ui-thread-in-wpf-uwp-in-modern-c--zltvjtle0","mainEntityOfPage":{"@type":"WebPage","@id":"https://daily.dev/posts/switching-back-to-the-ui-thread-in-wpf-uwp-in-modern-c--zltvjtle0"},"datePublished":"2026-10-04T13:06:47.977Z","dateModified":"2026-10-04T13:15:05.004Z","description":"A deep dive into switching to the UI thread in WPF/UWP (and transferable to WinForms) using modern C# async machinery. Starts from the classic...","image":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/1056987b22c10d2dfbafaf2334787e56?_a=AQAEuop","thumbnailUrl":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/1056987b22c10d2dfbafaf2334787e56?_a=AQAEuop","isAccessibleForFree":true,"articleSection":"Kevin Gosse (minidump.net)","inLanguage":"en","publisher":{"@type":"Organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180}},"author":{"@type":"Organization","name":"Kevin Gosse (minidump.net)","logo":"https://media.daily.dev/image/upload/s--8KHn1aFB--/f_auto,q_auto/v1791119046/logos/minidump?_a=BAMAMicg0","url":"https://daily.dev/sources/minidump"},"commentCount":0,"discussionUrl":"https://daily.dev/posts/switching-back-to-the-ui-thread-in-wpf-uwp-in-modern-c--zltvjtle0","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":0},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":0}],"keywords":".net,c#,wpf","timeRequired":"PT8M"}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"Kevin Gosse (minidump.net)","item":"https://daily.dev/sources/minidump"},{"@type":"ListItem","position":3,"name":"Switching back to the UI thread in WPF/UWP, in modern C#"}]}
{"@context":"https://schema.org","@type":"FAQPage","@id":"https://daily.dev/posts/switching-back-to-the-ui-thread-in-wpf-uwp-in-modern-c--zltvjtle0#faq","mainEntity":[{"@type":"Question","name":"How can I make a C# async method automatically run on the WPF UI thread without manually checking Dispatcher.CheckAccess every time?","acceptedAnswer":{"@type":"Answer","text":"Define a custom task type (e.g. UiTask) annotated with the AsyncMethodBuilder attribute pointing to a custom method builder (UiTaskMethodBuilder). The builder's Start method checks Dispatcher.CheckAccess() and, if not on the UI thread, calls Dispatcher.BeginInvoke to run the state machine there; AwaitOnCompleted and AwaitUnsafeOnCompleted do the same after each await, so simply declaring the method's return type as UiTask forces it onto the UI thread. daily.dev surfaces deep dives like custom async method builders for developers wiring up WPF UI-thread patterns."}},{"@type":"Question","name":"What is the difference between implementing a custom awaiter and a custom AsyncMethodBuilder for switching to the UI thread in C#?","acceptedAnswer":{"@type":"Answer","text":"A custom awaiter (implementing INotifyCompletion with IsCompleted, OnCompleted, and GetResult) requires an explicit await call like 'await Dispatcher.SwitchToUi()' inside the method body, while a custom AsyncMethodBuilder paired with a custom task type lets the method's return type itself (e.g. UiTask) signal that the whole method, including its first line, runs on the UI thread, removing that boilerplate line entirely. Developers comparing async patterns for desktop UI threading can find implementation trade-offs like these on daily.dev."}}]}
```

