WPF's multi-threaded UI is not thread safe
- 2020 年 2 月 10 日
- 筆記
WPF supports multiple UI threads in its framework. You can create multiple UI thread windows or create multiple UI threads in a single window. But unfortunately, this is not really thread-safe.
There is a very low probability that WPF application will crash when you creating a multi-thread UI. In this post, I’ll tell how this happens.
The Issue
Necessary conditions:
- Create multiple WPF UI threads
- In fact, two are enough, one is the main UI thread with the App class we usually write; a background UI thread, for example, to display the UI thread that starts the splash screen.
- If you use two threads, you need a lot of repetitive trials to reproduce; and by creating more threads you can greatly improve the probability of a single recurrence
- These UI threads all display WPF windows
- This issue will occur in both WPF on .NET Core 3 and WPF on .NET Framework 4.7.2.
phenomenon:
– An exception is thrown and the application crashes
For example, the following is one of the exceptions:
Exception thrown: 'System.NullReferenceException' in WindowsBase.dll Object reference not set to an instance of an object. System.NullReferenceException: Object reference not set to an instance of an object. at System.IO.Packaging.PackagePart.CleanUpRequestedStreamsList() at System.IO.Packaging.PackagePart.GetStream(FileMode mode, FileAccess access) at System.Windows.Application.LoadComponent(Object component, Uri resourceLocator) at Walterlv.Bugs.MultiThreadedUI.SplashWindow.InitializeComponent() in C:UserslvyiDesktopWalterlv.Bugs.MultiThreadedUIWalterlv.Bugs.MultiThreadedUISplashWindow.xaml:line 1 at Walterlv.Bugs.MultiThreadedUI.SplashWindow..ctor() in C:UserslvyiDesktopWalterlv.Bugs.MultiThreadedUIWalterlv.Bugs.MultiThreadedUISplashWindow.xaml.cs:line 24 at Walterlv.Bugs.MultiThreadedUI.Program.<>c__DisplayClass1_0.<RunSplashWindow>b__0() in C:UserslvyiDesktopWalterlv.Bugs.MultiThreadedUIWalterlv.Bugs.MultiThreadedUIProgram.cs:line 33
The following image is an exception caught in WPF on .NET Core 3 that is shown in visual studio 2019:

How to Reproduce
- Create a new WPF project (either .NET Core 3 or .NET Framework 4.7.2)
- Keep the automatically generated
App
andMainWindow
unchanged, we create a new windowSplashWindow
. - Create a new
Program
class containing the Main function and setProgram
as the startup object (instead ofApp
) in the project properties.

All other files remain the same as the default code generated by Visual Studio, and the code of Program.cs is as follows:
using System; using System.Threading; using System.Windows.Threading; namespace Walterlv.Bugs.MultiThreadedUI { public class Program { [STAThread] private static void Main(string[] args) { for (var i = 0; i < 50; i++) { RunSplashWindow(i); } var app = new App(); app.InitializeComponent(); app.Run(); } private static void RunSplashWindow(int index) { var thread = new Thread(() => { var window = new SplashWindow { Title = $"SplashWindow {index.ToString().PadLeft(2, ' ')}", }; window.Show(); Dispatcher.Run(); }) { IsBackground = true, }; thread.SetApartmentState(ApartmentState.STA); thread.Start(); } } }
Remarks: Even if you add this code just before the Splash Window creating, this exception still occurs.
SynchronizationContext.SetSynchronizationContext( new DispatcherSynchronizationContext( Dispatcher.CurrentDispatcher));
本文会经常更新,请阅读原文: https://blog.walterlv.com/post/wpf-multi-thread-ui-is-not-thread-safe-en.html ,以避免陈旧错误知识的误导,同时有更好的阅读体验。
本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名 吕毅 (包含链接: https://blog.walterlv.com ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请 与我联系 ([email protected]) 。