diff --git a/dotnet-desktop-guide/framework/wpf/advanced/media/threading-model/threading-message-loop.png b/dotnet-desktop-guide/framework/wpf/advanced/media/threading-model/threading-message-loop.png
index 39386c0239..d92c2287e4 100644
Binary files a/dotnet-desktop-guide/framework/wpf/advanced/media/threading-model/threading-message-loop.png and b/dotnet-desktop-guide/framework/wpf/advanced/media/threading-model/threading-message-loop.png differ
diff --git a/dotnet-desktop-guide/framework/wpf/advanced/media/threading-model/threading-multiwindow-ui.png b/dotnet-desktop-guide/framework/wpf/advanced/media/threading-model/threading-multiwindow-ui.png
new file mode 100644
index 0000000000..6b0a90da54
Binary files /dev/null and b/dotnet-desktop-guide/framework/wpf/advanced/media/threading-model/threading-multiwindow-ui.png differ
diff --git a/dotnet-desktop-guide/framework/wpf/advanced/media/threading-model/threading-prime-numbers.png b/dotnet-desktop-guide/framework/wpf/advanced/media/threading-model/threading-prime-numbers.png
index 3221910c4a..493b22af32 100644
Binary files a/dotnet-desktop-guide/framework/wpf/advanced/media/threading-model/threading-prime-numbers.png and b/dotnet-desktop-guide/framework/wpf/advanced/media/threading-model/threading-prime-numbers.png differ
diff --git a/dotnet-desktop-guide/framework/wpf/advanced/media/threading-model/threading-weather-ui.pdn b/dotnet-desktop-guide/framework/wpf/advanced/media/threading-model/threading-weather-ui.pdn
new file mode 100644
index 0000000000..d96830b3e8
Binary files /dev/null and b/dotnet-desktop-guide/framework/wpf/advanced/media/threading-model/threading-weather-ui.pdn differ
diff --git a/dotnet-desktop-guide/framework/wpf/advanced/media/threading-model/threading-weather-ui.png b/dotnet-desktop-guide/framework/wpf/advanced/media/threading-model/threading-weather-ui.png
index 0cf76b9afb..f980bfdb80 100644
Binary files a/dotnet-desktop-guide/framework/wpf/advanced/media/threading-model/threading-weather-ui.png and b/dotnet-desktop-guide/framework/wpf/advanced/media/threading-model/threading-weather-ui.png differ
diff --git a/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/csharp/App.xaml b/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/csharp/App.xaml
new file mode 100644
index 0000000000..b9a38c3fe2
--- /dev/null
+++ b/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/csharp/App.xaml
@@ -0,0 +1,182 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/csharp/App.xaml.cs b/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/csharp/App.xaml.cs
new file mode 100644
index 0000000000..94d1057d50
--- /dev/null
+++ b/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/csharp/App.xaml.cs
@@ -0,0 +1,14 @@
+using System.Configuration;
+using System.Data;
+using System.Windows;
+
+namespace SDKSamples
+{
+ ///
+ /// Interaction logic for App.xaml
+ ///
+ public partial class App : Application
+ {
+ }
+
+}
diff --git a/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/csharp/AssemblyInfo.cs b/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/csharp/AssemblyInfo.cs
new file mode 100644
index 0000000000..cc29e7f741
--- /dev/null
+++ b/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/csharp/AssemblyInfo.cs
@@ -0,0 +1,10 @@
+using System.Windows;
+
+[assembly:ThemeInfo(
+ ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
+ //(used if a resource is not found in the page,
+ // or application resource dictionaries)
+ ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
+ //(used if a resource is not found in the page,
+ // app, or any theme specific resource dictionaries)
+)]
diff --git a/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/csharp/MultiWindow.xaml b/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/csharp/MultiWindow.xaml
new file mode 100644
index 0000000000..884542b9cc
--- /dev/null
+++ b/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/csharp/MultiWindow.xaml
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/csharp/MultiWindow.xaml.cs b/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/csharp/MultiWindow.xaml.cs
new file mode 100644
index 0000000000..6cc1b19d4e
--- /dev/null
+++ b/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/csharp/MultiWindow.xaml.cs
@@ -0,0 +1,45 @@
+//
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Windows;
+
+namespace SDKSamples
+{
+ public partial class MultiWindow : Window
+ {
+ public MultiWindow() =>
+ InitializeComponent();
+
+ private void Window_Loaded(object sender, RoutedEventArgs e) =>
+ ThreadStatusItem.Content = $"Thread ID: {Thread.CurrentThread.ManagedThreadId}";
+
+ //
+ private void PauseButton_Click(object sender, RoutedEventArgs e) =>
+ Task.Delay(TimeSpan.FromSeconds(5)).Wait();
+ //
+
+ //
+ private void SameThreadWindow_Click(object sender, RoutedEventArgs e) =>
+ new MultiWindow().Show();
+
+ private void NewThreadWindow_Click(object sender, RoutedEventArgs e)
+ {
+ Thread newWindowThread = new Thread(ThreadStartingPoint);
+ newWindowThread.SetApartmentState(ApartmentState.STA);
+ newWindowThread.IsBackground = true;
+ newWindowThread.Start();
+ }
+ //
+
+ //
+ private void ThreadStartingPoint()
+ {
+ new MultiWindow().Show();
+
+ System.Windows.Threading.Dispatcher.Run();
+ }
+ //
+ }
+}
+//
diff --git a/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/csharp/NestedPumpScreenShot.xaml b/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/csharp/NestedPumpScreenShot.xaml
new file mode 100644
index 0000000000..ef49f80046
--- /dev/null
+++ b/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/csharp/NestedPumpScreenShot.xaml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/csharp/NestedPumpScreenShot.xaml.cs b/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/csharp/NestedPumpScreenShot.xaml.cs
new file mode 100644
index 0000000000..f5212fbb82
--- /dev/null
+++ b/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/csharp/NestedPumpScreenShot.xaml.cs
@@ -0,0 +1,32 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Shapes;
+
+namespace SDKSamples
+{
+ ///
+ /// Interaction logic for NestedPumpScreenShot.xaml
+ ///
+ public partial class NestedPumpScreenShot : Window
+ {
+ public NestedPumpScreenShot()
+ {
+ InitializeComponent();
+ }
+
+ private void Button_Click(object sender, RoutedEventArgs e)
+ {
+ MessageBox.Show("Click OK to close the window and stop blocking");
+ }
+ }
+}
diff --git a/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/csharp/PrimeNumber.xaml b/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/csharp/PrimeNumber.xaml
new file mode 100644
index 0000000000..1fdd290f34
--- /dev/null
+++ b/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/csharp/PrimeNumber.xaml
@@ -0,0 +1,14 @@
+
+
+
+
+ Biggest Prime Found:
+ 3
+
+
diff --git a/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/csharp/PrimeNumber.xaml.cs b/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/csharp/PrimeNumber.xaml.cs
new file mode 100644
index 0000000000..056216c7d6
--- /dev/null
+++ b/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/csharp/PrimeNumber.xaml.cs
@@ -0,0 +1,61 @@
+//
+using System;
+using System.Windows;
+using System.Windows.Threading;
+
+namespace SDKSamples
+{
+ public partial class PrimeNumber : Window
+ {
+ // Current number to check
+ private long _num = 3;
+ private bool _runCalculation = false;
+
+ public PrimeNumber() =>
+ InitializeComponent();
+
+ private void StartStopButton_Click(object sender, RoutedEventArgs e)
+ {
+ _runCalculation = !_runCalculation;
+
+ if (_runCalculation)
+ {
+ StartStopButton.Content = "Stop";
+ StartStopButton.Dispatcher.InvokeAsync(CheckNextNumber, DispatcherPriority.SystemIdle);
+ }
+ else
+ StartStopButton.Content = "Resume";
+ }
+
+ //
+ public void CheckNextNumber()
+ {
+ // Reset flag.
+ _isPrime = true;
+
+ for (long i = 3; i <= Math.Sqrt(_num); i++)
+ {
+ if (_num % i == 0)
+ {
+ // Set not a prime flag to true.
+ _isPrime = false;
+ break;
+ }
+ }
+
+ // If a prime number, update the UI text
+ if (_isPrime)
+ bigPrime.Text = _num.ToString();
+
+ _num += 2;
+
+ // Requeue this method on the dispatcher
+ if (_runCalculation)
+ StartStopButton.Dispatcher.InvokeAsync(CheckNextNumber, DispatcherPriority.SystemIdle);
+ }
+
+ private bool _isPrime = false;
+ //
+ }
+}
+//
diff --git a/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/csharp/ProjectCS.csproj b/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/csharp/ProjectCS.csproj
new file mode 100644
index 0000000000..0336b4ecc2
--- /dev/null
+++ b/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/csharp/ProjectCS.csproj
@@ -0,0 +1,11 @@
+
+
+
+ WinExe
+ net481
+ true
+ SDKSamples
+ app.manifest
+
+
+
diff --git a/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/csharp/Weather.xaml b/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/csharp/Weather.xaml
new file mode 100644
index 0000000000..86180539e4
--- /dev/null
+++ b/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/csharp/Weather.xaml
@@ -0,0 +1,60 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/csharp/Weather.xaml.cs b/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/csharp/Weather.xaml.cs
new file mode 100644
index 0000000000..14935c4ac1
--- /dev/null
+++ b/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/csharp/Weather.xaml.cs
@@ -0,0 +1,70 @@
+//
+using System;
+using System.Windows;
+using System.Windows.Media;
+using System.Windows.Media.Animation;
+using System.Threading.Tasks;
+
+namespace SDKSamples
+{
+ public partial class Weather : Window
+ {
+ public Weather() =>
+ InitializeComponent();
+
+ //
+
+ //
+ private async Task FetchWeatherFromServerAsync()
+ {
+ // Simulate the delay from network access
+ await Task.Delay(TimeSpan.FromSeconds(4));
+
+ // Tried and true method for weather forecasting - random numbers
+ Random rand = new Random();
+
+ if (rand.Next(2) == 0)
+ return "rainy";
+
+ else
+ return "sunny";
+ }
+ //
+
+ private void HideClockFaceStoryboard_Completed(object sender, EventArgs args) =>
+ ((Storyboard)Resources["ShowWeatherImageStoryboard"]).Begin(ClockImage);
+
+ private void HideWeatherImageStoryboard_Completed(object sender, EventArgs args) =>
+ ((Storyboard)Resources["ShowClockFaceStoryboard"]).Begin(ClockImage, true);
+ }
+}
+//
diff --git a/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/csharp/app.manifest b/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/csharp/app.manifest
new file mode 100644
index 0000000000..c522bb43f3
--- /dev/null
+++ b/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/csharp/app.manifest
@@ -0,0 +1,77 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/vb/App.config b/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/vb/App.config
new file mode 100644
index 0000000000..aee9adf485
--- /dev/null
+++ b/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/vb/App.config
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/vb/Application.xaml b/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/vb/Application.xaml
new file mode 100644
index 0000000000..1837eefd7c
--- /dev/null
+++ b/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/vb/Application.xaml
@@ -0,0 +1,182 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dotnet-desktop-guide/samples/snippets/visualbasic/VS_Snippets_Wpf/ThreadingPrimeNumbers/visualbasic/application.xaml.vb b/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/vb/Application.xaml.vb
similarity index 100%
rename from dotnet-desktop-guide/samples/snippets/visualbasic/VS_Snippets_Wpf/ThreadingPrimeNumbers/visualbasic/application.xaml.vb
rename to dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/vb/Application.xaml.vb
diff --git a/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/vb/AssemblyInfo.vb b/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/vb/AssemblyInfo.vb
new file mode 100644
index 0000000000..025ee7271e
--- /dev/null
+++ b/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/vb/AssemblyInfo.vb
@@ -0,0 +1,11 @@
+Imports System.Windows
+
+'The ThemeInfo attribute describes where any theme specific and generic resource dictionaries can be found.
+'1st parameter: where theme specific resource dictionaries are located
+'(used if a resource is not found in the page,
+' or application resource dictionaries)
+
+'2nd parameter: where the generic resource dictionary is located
+'(used if a resource is not found in the page,
+'app, and any theme specific resource dictionaries)
+
diff --git a/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/vb/MultiWindow.xaml b/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/vb/MultiWindow.xaml
new file mode 100644
index 0000000000..bddd24c56b
--- /dev/null
+++ b/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/vb/MultiWindow.xaml
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/vb/MultiWindow.xaml.vb b/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/vb/MultiWindow.xaml.vb
new file mode 100644
index 0000000000..bbccaa290f
--- /dev/null
+++ b/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/vb/MultiWindow.xaml.vb
@@ -0,0 +1,38 @@
+'
+Imports System.Threading
+
+Public Class MultiWindow
+ Private Sub Window_Loaded(sender As Object, e As RoutedEventArgs)
+ ThreadStatusItem.Content = $"Thread ID: {Thread.CurrentThread.ManagedThreadId}"
+ End Sub
+
+ '
+ Private Sub PauseButton_Click(sender As Object, e As RoutedEventArgs)
+ Task.Delay(TimeSpan.FromSeconds(5)).Wait()
+ End Sub
+ '
+
+ '
+ Private Sub SameThreadWindow_Click(sender As Object, e As RoutedEventArgs)
+ Dim window As New MultiWindow()
+ window.Show()
+ End Sub
+
+ Private Sub NewThreadWindow_Click(sender As Object, e As RoutedEventArgs)
+ Dim newWindowThread = New Thread(AddressOf ThreadStartingPoint)
+ newWindowThread.SetApartmentState(ApartmentState.STA)
+ newWindowThread.IsBackground = True
+ newWindowThread.Start()
+ End Sub
+ '
+
+ '
+ Private Sub ThreadStartingPoint()
+ Dim window As New MultiWindow()
+ window.Show()
+
+ System.Windows.Threading.Dispatcher.Run()
+ End Sub
+ '
+End Class
+'
diff --git a/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/vb/My Project/AssemblyInfo.vb b/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/vb/My Project/AssemblyInfo.vb
new file mode 100644
index 0000000000..0c518abf27
--- /dev/null
+++ b/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/vb/My Project/AssemblyInfo.vb
@@ -0,0 +1,59 @@
+Imports System
+Imports System.Globalization
+Imports System.Reflection
+Imports System.Resources
+Imports System.Runtime.InteropServices
+Imports System.Windows
+
+' General Information about an assembly is controlled through the following
+' set of attributes. Change these attribute values to modify the information
+' associated with an assembly.
+
+' Review the values of the assembly attributes
+
+
+
+
+
+
+
+
+
+'In order to begin building localizable applications, set
+'CultureYouAreCodingWith in your .vbproj file
+'inside a . For example, if you are using US english
+'in your source files, set the to "en-US". Then uncomment the
+'NeutralResourceLanguage attribute below. Update the "en-US" in the line
+'below to match the UICulture setting in the project file.
+
+'
+
+
+'The ThemeInfo attribute describes where any theme specific and generic resource dictionaries can be found.
+'1st parameter: where theme specific resource dictionaries are located
+'(used if a resource is not found in the page,
+' or application resource dictionaries)
+
+'2nd parameter: where the generic resource dictionary is located
+'(used if a resource is not found in the page,
+'app, and any theme specific resource dictionaries)
+
+
+
+
+'The following GUID is for the ID of the typelib if this project is exposed to COM
+
+
+' Version information for an assembly consists of the following four values:
+'
+' Major Version
+' Minor Version
+' Build Number
+' Revision
+'
+' You can specify all the values or you can default the Build and Revision Numbers
+' by using the '*' as shown below:
+'
+
+
+
diff --git a/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/vb/My Project/MyExtensions/MyWpfExtension.vb b/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/vb/My Project/MyExtensions/MyWpfExtension.vb
new file mode 100644
index 0000000000..22f84b7da5
--- /dev/null
+++ b/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/vb/My Project/MyExtensions/MyWpfExtension.vb
@@ -0,0 +1,121 @@
+#If _MyType <> "Empty" Then
+
+Namespace My
+ '''
+ ''' Module used to define the properties that are available in the My Namespace for WPF
+ '''
+ '''
+ _
+ Module MyWpfExtension
+ Private s_Computer As New ThreadSafeObjectProvider(Of Global.Microsoft.VisualBasic.Devices.Computer)
+ Private s_User As New ThreadSafeObjectProvider(Of Global.Microsoft.VisualBasic.ApplicationServices.User)
+ Private s_Windows As New ThreadSafeObjectProvider(Of MyWindows)
+ Private s_Log As New ThreadSafeObjectProvider(Of Global.Microsoft.VisualBasic.Logging.Log)
+ '''
+ ''' Returns the application object for the running application
+ '''
+ _
+ Friend ReadOnly Property Application() As Application
+ Get
+ Return CType(Global.System.Windows.Application.Current, Application)
+ End Get
+ End Property
+ '''
+ ''' Returns information about the host computer.
+ '''
+ _
+ Friend ReadOnly Property Computer() As Global.Microsoft.VisualBasic.Devices.Computer
+ Get
+ Return s_Computer.GetInstance()
+ End Get
+ End Property
+ '''
+ ''' Returns information for the current user. If you wish to run the application with the current
+ ''' Windows user credentials, call My.User.InitializeWithWindowsUser().
+ '''
+ _
+ Friend ReadOnly Property User() As Global.Microsoft.VisualBasic.ApplicationServices.User
+ Get
+ Return s_User.GetInstance()
+ End Get
+ End Property
+ '''
+ ''' Returns the application log. The listeners can be configured by the application's configuration file.
+ '''
+ _
+ Friend ReadOnly Property Log() As Global.Microsoft.VisualBasic.Logging.Log
+ Get
+ Return s_Log.GetInstance()
+ End Get
+ End Property
+
+ '''
+ ''' Returns the collection of Windows defined in the project.
+ '''
+ _
+ Friend ReadOnly Property Windows() As MyWindows
+ _
+ Get
+ Return s_Windows.GetInstance()
+ End Get
+ End Property
+ _
+ _
+ Friend NotInheritable Class MyWindows
+ _
+ Private Shared Function Create__Instance__(Of T As {New, Global.System.Windows.Window})(ByVal Instance As T) As T
+ If Instance Is Nothing Then
+ If s_WindowBeingCreated IsNot Nothing Then
+ If s_WindowBeingCreated.ContainsKey(GetType(T)) = True Then
+ Throw New Global.System.InvalidOperationException("The window cannot be accessed via My.Windows from the Window constructor.")
+ End If
+ Else
+ s_WindowBeingCreated = New Global.System.Collections.Hashtable()
+ End If
+ s_WindowBeingCreated.Add(GetType(T), Nothing)
+ Return New T()
+ s_WindowBeingCreated.Remove(GetType(T))
+ Else
+ Return Instance
+ End If
+ End Function
+ _
+ _
+ Private Sub Dispose__Instance__(Of T As Global.System.Windows.Window)(ByRef instance As T)
+ instance = Nothing
+ End Sub
+ _
+ _
+ Public Sub New()
+ MyBase.New()
+ End Sub
+ Private Shared s_WindowBeingCreated As Global.System.Collections.Hashtable
+ Public Overrides Function Equals(ByVal o As Object) As Boolean
+ Return MyBase.Equals(o)
+ End Function
+ Public Overrides Function GetHashCode() As Integer
+ Return MyBase.GetHashCode
+ End Function
+ _
+ _
+ Friend Overloads Function [GetType]() As Global.System.Type
+ Return GetType(MyWindows)
+ End Function
+ Public Overrides Function ToString() As String
+ Return MyBase.ToString
+ End Function
+ End Class
+ End Module
+End Namespace
+Partial Class Application
+ Inherits Global.System.Windows.Application
+ _
+ _
+ Friend ReadOnly Property Info() As Global.Microsoft.VisualBasic.ApplicationServices.AssemblyInfo
+ _
+ Get
+ Return New Global.Microsoft.VisualBasic.ApplicationServices.AssemblyInfo(Global.System.Reflection.Assembly.GetExecutingAssembly())
+ End Get
+ End Property
+End Class
+#End If
\ No newline at end of file
diff --git a/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/vb/My Project/Resources.Designer.vb b/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/vb/My Project/Resources.Designer.vb
new file mode 100644
index 0000000000..e7ecddcab6
--- /dev/null
+++ b/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/vb/My Project/Resources.Designer.vb
@@ -0,0 +1,62 @@
+'------------------------------------------------------------------------------
+'
+' This code was generated by a tool.
+' Runtime Version:$clrversion$
+'
+' Changes to this file may cause incorrect behavior and will be lost if
+' the code is regenerated.
+'
+'------------------------------------------------------------------------------
+
+Option Strict On
+Option Explicit On
+
+
+Namespace My.Resources
+
+ 'This class was auto-generated by the StronglyTypedResourceBuilder
+ 'class via a tool like ResGen or Visual Studio.
+ 'To add or remove a member, edit your .ResX file then rerun ResGen
+ 'with the /str option, or rebuild your VS project.
+ '''
+ ''' A strongly-typed resource class, for looking up localized strings, etc.
+ '''
+ _
+ Friend Module Resources
+
+ Private resourceMan As Global.System.Resources.ResourceManager
+
+ Private resourceCulture As Global.System.Globalization.CultureInfo
+
+ '''
+ ''' Returns the cached ResourceManager instance used by this class.
+ '''
+ _
+ Friend ReadOnly Property ResourceManager() As Global.System.Resources.ResourceManager
+ Get
+ If Object.ReferenceEquals(resourceMan, Nothing) Then
+ Dim temp As Global.System.Resources.ResourceManager = New Global.System.Resources.ResourceManager("$safeprojectname$.Resources", GetType(Resources).Assembly)
+ resourceMan = temp
+ End If
+ Return resourceMan
+ End Get
+ End Property
+
+ '''
+ ''' Overrides the current thread's CurrentUICulture property for all
+ ''' resource lookups using this strongly typed resource class.
+ '''
+ _
+ Friend Property Culture() As Global.System.Globalization.CultureInfo
+ Get
+ Return resourceCulture
+ End Get
+ Set(ByVal value As Global.System.Globalization.CultureInfo)
+ resourceCulture = value
+ End Set
+ End Property
+ End Module
+End Namespace
diff --git a/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/vb/My Project/Resources.resx b/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/vb/My Project/Resources.resx
new file mode 100644
index 0000000000..af7dbebbac
--- /dev/null
+++ b/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/vb/My Project/Resources.resx
@@ -0,0 +1,117 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/vb/My Project/Settings.Designer.vb b/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/vb/My Project/Settings.Designer.vb
new file mode 100644
index 0000000000..51901f82e0
--- /dev/null
+++ b/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/vb/My Project/Settings.Designer.vb
@@ -0,0 +1,73 @@
+'------------------------------------------------------------------------------
+'
+' This code was generated by a tool.
+' Runtime Version:4.0.30319.42000
+'
+' Changes to this file may cause incorrect behavior and will be lost if
+' the code is regenerated.
+'
+'------------------------------------------------------------------------------
+
+Option Strict On
+Option Explicit On
+
+
+Namespace My
+
+ _
+ Partial Friend NotInheritable Class MySettings
+ Inherits Global.System.Configuration.ApplicationSettingsBase
+
+ Private Shared defaultInstance As MySettings = CType(Global.System.Configuration.ApplicationSettingsBase.Synchronized(New MySettings), MySettings)
+
+#Region "My.Settings Auto-Save Functionality"
+#If _MyType = "WindowsForms" Then
+ Private Shared addedHandler As Boolean
+
+ Private Shared addedHandlerLockObject As New Object
+
+ _
+ Private Shared Sub AutoSaveSettings(ByVal sender As Global.System.Object, ByVal e As Global.System.EventArgs)
+ If My.Application.SaveMySettingsOnExit Then
+ My.Settings.Save()
+ End If
+ End Sub
+#End If
+#End Region
+
+ Public Shared ReadOnly Property [Default]() As MySettings
+ Get
+
+#If _MyType = "WindowsForms" Then
+ If Not addedHandler Then
+ SyncLock addedHandlerLockObject
+ If Not addedHandler Then
+ AddHandler My.Application.Shutdown, AddressOf AutoSaveSettings
+ addedHandler = True
+ End If
+ End SyncLock
+ End If
+#End If
+ Return defaultInstance
+ End Get
+ End Property
+ End Class
+End Namespace
+
+Namespace My
+
+ _
+ Friend Module MySettingsProperty
+
+
+ Friend ReadOnly Property Settings() As Global.SDKSamples.My.MySettings
+ Get
+ Return Global.SDKSamples.My.MySettings.Default
+ End Get
+ End Property
+ End Module
+End Namespace
diff --git a/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/vb/My Project/Settings.settings b/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/vb/My Project/Settings.settings
new file mode 100644
index 0000000000..40ed9fdbad
--- /dev/null
+++ b/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/vb/My Project/Settings.settings
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/vb/PrimeNumber.xaml b/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/vb/PrimeNumber.xaml
new file mode 100644
index 0000000000..7a3be68746
--- /dev/null
+++ b/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/vb/PrimeNumber.xaml
@@ -0,0 +1,14 @@
+
+
+
+
+ Biggest Prime Found:
+ 3
+
+
diff --git a/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/vb/PrimeNumber.xaml.vb b/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/vb/PrimeNumber.xaml.vb
new file mode 100644
index 0000000000..1657fceb1c
--- /dev/null
+++ b/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/vb/PrimeNumber.xaml.vb
@@ -0,0 +1,51 @@
+'
+Imports System.Windows.Threading
+
+Public Class PrimeNumber
+ ' Current number to check
+ Private _num As Long = 3
+ Private _runCalculation As Boolean = False
+
+ Private Sub StartStopButton_Click(sender As Object, e As RoutedEventArgs)
+ _runCalculation = Not _runCalculation
+
+ If _runCalculation Then
+ StartStopButton.Content = "Stop"
+ StartStopButton.Dispatcher.InvokeAsync(AddressOf CheckNextNumber, DispatcherPriority.SystemIdle)
+ Else
+ StartStopButton.Content = "Resume"
+ End If
+
+ End Sub
+
+ '
+ Public Sub CheckNextNumber()
+ ' Reset flag.
+ _isPrime = True
+
+ For i As Long = 3 To Math.Sqrt(_num)
+ If (_num Mod i = 0) Then
+
+ ' Set Not a prime flag to true.
+ _isPrime = False
+ Exit For
+ End If
+ Next
+
+ ' If a prime number, update the UI text
+ If _isPrime Then
+ bigPrime.Text = _num.ToString()
+ End If
+
+ _num += 2
+
+ ' Requeue this method on the dispatcher
+ If (_runCalculation) Then
+ StartStopButton.Dispatcher.InvokeAsync(AddressOf CheckNextNumber, DispatcherPriority.SystemIdle)
+ End If
+ End Sub
+
+ Private _isPrime As Boolean
+ '
+End Class
+'
diff --git a/dotnet-desktop-guide/samples/snippets/visualbasic/VS_Snippets_Wpf/ThreadingPrimeNumbers/visualbasic/threadingprimenumbersample.vbproj b/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/vb/ProjectVB.vbproj
similarity index 53%
rename from dotnet-desktop-guide/samples/snippets/visualbasic/VS_Snippets_Wpf/ThreadingPrimeNumbers/visualbasic/threadingprimenumbersample.vbproj
rename to dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/vb/ProjectVB.vbproj
index 3100cfdf7a..b32454bd63 100644
--- a/dotnet-desktop-guide/samples/snippets/visualbasic/VS_Snippets_Wpf/ThreadingPrimeNumbers/visualbasic/threadingprimenumbersample.vbproj
+++ b/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/vb/ProjectVB.vbproj
@@ -1,30 +1,31 @@
-
-
+
+ Debug
- x86
- {C00AEFF0-66F0-4EEB-A2E8-1E9746CC9834}
+ AnyCPU
+ {7D142ED4-D5D6-4680-BD9E-290CA944A377}{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{F184B08F-C81C-45F6-A57F-5ABD9991F28F}WinExe
- ThreadingPrimeNumberSample
- ThreadingPrimeNumberSample
- v4.0
- Client
+ SDKSamples
+ ThreadExample
+ v4.8.1Custom
+ true
+ true
-
- x86
+
+ AnyCPUtruefulltruetruetruebin\Debug\
- ThreadingPrimeNumberSample.xml
+ ThreadExample.xml41999,42016,42017,42018,42019,42020,42021,42022,42032,42036,42314
-
- x86
+
+ AnyCPUpdbonlyfalsefalse
@@ -32,7 +33,7 @@
falsetruebin\Release\
- ThreadingPrimeNumberSample.xml
+ ThreadExample.xml41999,42016,42017,42018,42019,42020,42021,42022,42032,42036,42314
@@ -60,13 +61,24 @@
+ MSBuild:CompileDesigner
-
+
+ MultiWindow.xaml
+
+
+ Weather.xaml
+
+
+ Designer
+ MSBuild:Compile
+
+ MSBuild:CompileDesigner
@@ -74,12 +86,17 @@
Application.xamlCode
-
- MainWindow.xaml
+
+ PrimeNumber.xamlCode
+
+ Designer
+ MSBuild:Compile
+
+
@@ -98,10 +115,35 @@
-
+
+ Code
+
+
+ Microsoft.VisualBasic.WPF.MyExtension
+ 1.0.0.0
+
+
+ True
+ True
+ Resources.resx
+
+
+ True
+ Settings.settings
+ True
+
+
+ VbMyResourcesResXFileCodeGenerator
+ Resources.Designer.vb
+ My.Resources
+
+
+ SettingsSingleFileGenerator
+ Settings.Designer.vb
+
-
+
\ No newline at end of file
diff --git a/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/vb/Weather.xaml b/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/vb/Weather.xaml
new file mode 100644
index 0000000000..e5b0913173
--- /dev/null
+++ b/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/vb/Weather.xaml
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/vb/Weather.xaml.vb b/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/vb/Weather.xaml.vb
new file mode 100644
index 0000000000..023ff2191b
--- /dev/null
+++ b/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/vb/Weather.xaml.vb
@@ -0,0 +1,65 @@
+'
+Imports System.Windows.Media.Animation
+
+Public Class Weather
+
+ '
+
+ '
+ Private Async Function FetchWeatherFromServerAsync() As Task(Of String)
+
+ ' Simulate the delay from network access
+ Await Task.Delay(TimeSpan.FromSeconds(4))
+
+ ' Tried and true method for weather forecasting - random numbers
+ Dim rand As New Random()
+
+ If rand.Next(2) = 0 Then
+ Return "rainy"
+ Else
+ Return "sunny"
+ End If
+
+ End Function
+ '
+
+ Private Sub HideClockFaceStoryboard_Completed(sender As Object, e As EventArgs)
+ DirectCast(Resources("ShowWeatherImageStoryboard"), Storyboard).Begin(ClockImage)
+ End Sub
+
+ Private Sub HideWeatherImageStoryboard_Completed(sender As Object, e As EventArgs)
+ DirectCast(Resources("ShowClockFaceStoryboard"), Storyboard).Begin(ClockImage, True)
+ End Sub
+End Class
+'
diff --git a/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/vb/snippets.5000.json b/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/vb/snippets.5000.json
new file mode 100644
index 0000000000..da9ebf8da2
--- /dev/null
+++ b/dotnet-desktop-guide/framework/wpf/advanced/snippets/threading-model/vb/snippets.5000.json
@@ -0,0 +1,3 @@
+{
+ "host": "visualstudio"
+}
diff --git a/dotnet-desktop-guide/framework/wpf/advanced/threading-model.md b/dotnet-desktop-guide/framework/wpf/advanced/threading-model.md
index d48138b2c0..416d0a35e0 100644
--- a/dotnet-desktop-guide/framework/wpf/advanced/threading-model.md
+++ b/dotnet-desktop-guide/framework/wpf/advanced/threading-model.md
@@ -21,20 +21,22 @@ helpviewer_keywords:
- "reentrancy [WPF]"
ms.assetid: 02d8fd00-8d7c-4604-874c-58e40786770b
---
-# Threading Model
+# Threading model
-Windows Presentation Foundation (WPF) is designed to save developers from the difficulties of threading. As a result, the majority of WPF developers won't have to write an interface that uses more than one thread. Because multithreaded programs are complex and difficult to debug, they should be avoided when single-threaded solutions exist.
+Windows Presentation Foundation (WPF) is designed to save developers from the difficulties of threading. As a result, most WPF developers don't write an interface that uses more than one thread. Because multithreaded programs are complex and difficult to debug, they should be avoided when single-threaded solutions exist.
- No matter how well architected, however, no UI framework will ever be able to provide a single-threaded solution for every sort of problem. WPF comes close, but there are still situations where multiple threads improve user interface (UI) responsiveness or application performance. After discussing some background material, this paper explores some of these situations and then concludes with a discussion of some lower-level details.
+ No matter how well architected, however, no UI framework is able to provide a single-threaded solution for every sort of problem. WPF comes close, but there are still situations where multiple threads improve user interface (UI) responsiveness or application performance. After discussing some background material, this article explores some of these situations and then concludes with a discussion of some lower-level details.
> [!NOTE]
-> This topic discusses threading by using the method for asynchronous calls. You can also make asynchronous calls by calling the method, which take an or as a parameter. The method returns a or , which has a property. You can use the `await` keyword with either the or the associated . If you need to wait synchronously for the that is returned by a or , call the extension method. Calling will result in a deadlock. For more information about using a to perform asynchronous operations, see [Task-based asynchronous programming](/dotnet/standard/parallel-programming/task-based-asynchronous-programming). The method also has overloads that take an or as a parameter. You can use the method to make synchronous calls by passing in a delegate, or .
+> This topic discusses threading by using the method for asynchronous calls. The `InvokeAsync` method takes an or as a parameter, and returns a or , which has a property. You can use the `await` keyword with either the or the associated . If you need to wait synchronously for the that is returned by a or , call the extension method. Calling will result in a **deadlock**. For more information about using a to perform asynchronous operations, see [Task-based asynchronous programming](/dotnet/standard/parallel-programming/task-based-asynchronous-programming).
+>
+> To make a synchronous call, use the method, which also has overloads that takes a delegate, , or parameter.
-## Overview and the Dispatcher
+## Overview and the dispatcher
- Typically, WPF applications start with two threads: one for handling rendering and another for managing the UI. The rendering thread effectively runs hidden in the background while the UI thread receives input, handles events, paints the screen, and runs application code. Most applications use a single UI thread, although in some situations it is best to use several. We’ll discuss this with an example later.
+ Typically, WPF applications start with two threads: one for handling rendering and another for managing the UI. The rendering thread effectively runs hidden in the background while the UI thread receives input, handles events, paints the screen, and runs application code. Most applications use a single UI thread, although in some situations it is best to use several. We'll discuss this with an example later.
The UI thread queues work items inside an object called a . The selects work items on a priority basis and runs each one to completion. Every UI thread must have at least one , and each can execute work items in exactly one thread.
@@ -44,25 +46,25 @@ Windows Presentation Foundation (WPF) is designed to save developers from the di
Historically, Windows allows UI elements to be accessed only by the thread that created them. This means that a background thread in charge of some long-running task cannot update a text box when it is finished. Windows does this to ensure the integrity of UI components. A list box could look strange if its contents were updated by a background thread during painting.
- WPF has a built-in mutual exclusion mechanism that enforces this coordination. Most classes in WPF derive from . At construction, a stores a reference to the linked to the currently running thread. In effect, the associates with the thread that creates it. During program execution, a can call its public method. examines the associated with the current thread and compares it to the reference stored during construction. If they don’t match, throws an exception. is intended to be called at the beginning of every method belonging to a .
+ WPF has a built-in mutual exclusion mechanism that enforces this coordination. Most classes in WPF derive from . At construction, a stores a reference to the linked to the currently running thread. In effect, the associates with the thread that creates it. During program execution, a can call its public method. examines the associated with the current thread and compares it to the reference stored during construction. If they don't match, throws an exception. is intended to be called at the beginning of every method belonging to a .
- If only one thread can modify the UI, how do background threads interact with the user? A background thread can ask the UI thread to perform an operation on its behalf. It does this by registering a work item with the of the UI thread. The class provides two methods for registering work items: and . Both methods schedule a delegate for execution. is a synchronous call – that is, it doesn’t return until the UI thread actually finishes executing the delegate. is asynchronous and returns immediately.
+ If only one thread can modify the UI, how do background threads interact with the user? A background thread can ask the UI thread to perform an operation on its behalf. It does this by registering a work item with the of the UI thread. The class provides the methods for registering work items: , , and . These methods schedule a delegate for execution. is a synchronous call – that is, it doesn't return until the UI thread actually finishes executing the delegate. and are asynchronous and return immediately.
- The orders the elements in its queue by priority. There are ten levels that may be specified when adding an element to the queue. These priorities are maintained in the enumeration. Detailed information about levels can be found in the Windows SDK documentation.
+ The orders the elements in its queue by priority. There are ten levels that may be specified when adding an element to the queue. These priorities are maintained in the enumeration.
-## Threads in Action: The Samples
-
-### A Single-Threaded Application with a Long-Running Calculation
+## Single-threaded app with a long-running calculation
+
+ Most graphical user interfaces (GUIs) spend a large portion of their time idle while waiting for events that are generated in response to user interactions. With careful programming this idle time can be used constructively, without affecting the responsiveness of the UI. The WPF threading model doesn't allow input to interrupt an operation happening in the UI thread. This means you must be sure to return to the periodically to process pending input events before they get stale.
- Most graphical user interfaces (GUIs) spend a large portion of their time idle while waiting for events that are generated in response to user interactions. With careful programming this idle time can be used constructively, without affecting the responsiveness of the UI. The WPF threading model doesn’t allow input to interrupt an operation happening in the UI thread. This means you must be sure to return to the periodically to process pending input events before they get stale.
+ A sample app demonstrating the concepts of this section can be downloaded from GitHub for either [C#](https://github.com/dotnet/samples/tree/main/wpf/Threading/PrimeNumber/net48/csharp) or [Visual Basic](https://github.com/dotnet/samples/tree/main/wpf/Threading/PrimeNumber/net48/vb).
Consider the following example:
- ![Screenshot that shows threading of prime numbers.](./media/threading-model/threading-prime-numbers.png)
+ :::image type="content" source="./media/threading-model/threading-prime-numbers.png" alt-text="Screenshot that shows threading of prime numbers.":::
This simple application counts upwards from three, searching for prime numbers. When the user clicks the **Start** button, the search begins. When the program finds a prime, it updates the user interface with its discovery. At any point, the user can stop the search.
@@ -72,159 +74,183 @@ Windows Presentation Foundation (WPF) is designed to save developers from the di
If we break up the task of calculation into manageable chunks, we can periodically return to the and process events. We can give WPF an opportunity to repaint and process input.
- The best way to split processing time between calculation and event handling is to manage calculation from the . By using the method, we can schedule prime number checks in the same queue that UI events are drawn from. In our example, we schedule only a single prime number check at a time. After the prime number check is complete, we schedule the next check immediately. This check proceeds only after pending UI events have been handled.
+ The best way to split processing time between calculation and event handling is to manage calculation from the . By using the method, we can schedule prime number checks in the same queue that UI events are drawn from. In our example, we schedule only a single prime number check at a time. After the prime number check is complete, we schedule the next check immediately. This check proceeds only after pending UI events have been handled.
- ![Screenshot that shows the dispatcher queue.](./media/threading-model/threading-dispatcher-queue.png)
+ :::image type="content" source="./media/threading-model/threading-dispatcher-queue.png" alt-text="Screenshot that shows the dispatcher queue.":::
Microsoft Word accomplishes spell checking using this mechanism. Spell checking is done in the background using the idle time of the UI thread. Let's take a look at the code.
The following example shows the XAML that creates the user interface.
- [!code-xaml[ThreadingPrimeNumbers#ThreadingPrimeNumberXAML](~/samples/snippets/csharp/VS_Snippets_Wpf/ThreadingPrimeNumbers/CSharp/Window1.xaml#threadingprimenumberxaml)]
+> [!IMPORTANT]
+> The XAML shown in this article is from a C# project. Visual Basic XAML is slightly different when declaring the backing class for the XAML.
+
+ :::code language="xaml" source="./snippets/threading-model/csharp/PrimeNumber.xaml":::
The following example shows the code-behind.
- [!code-csharp[ThreadingPrimeNumbers#ThreadingPrimeNumberCodeBehind](~/samples/snippets/csharp/VS_Snippets_Wpf/ThreadingPrimeNumbers/CSharp/Window1.xaml.cs#threadingprimenumbercodebehind)]
- [!code-vb[ThreadingPrimeNumbers#ThreadingPrimeNumberCodeBehind](~/samples/snippets/visualbasic/VS_Snippets_Wpf/ThreadingPrimeNumbers/visualbasic/mainwindow.xaml.vb#threadingprimenumbercodebehind)]
+ :::code language="csharp" source="./snippets/threading-model/csharp/PrimeNumber.xaml.cs" id="full":::
+ :::code language="vb" source="./snippets/threading-model/vb/PrimeNumber.xaml.vb" id="full":::
- The following example shows the event handler for the .
+ Besides updating the text on the , the `StartStopButton_Click` handler is responsible for scheduling the first prime number check by adding a delegate to the queue. Sometime after this event handler has completed its work, the will select the delegate for execution.
- [!code-csharp[ThreadingPrimeNumbers#ThreadingPrimeNumberStartOrStop](~/samples/snippets/csharp/VS_Snippets_Wpf/ThreadingPrimeNumbers/CSharp/Window1.xaml.cs#threadingprimenumberstartorstop)]
- [!code-vb[ThreadingPrimeNumbers#ThreadingPrimeNumberStartOrStop](~/samples/snippets/visualbasic/VS_Snippets_Wpf/ThreadingPrimeNumbers/visualbasic/mainwindow.xaml.vb#threadingprimenumberstartorstop)]
+ As we mentioned earlier, is the member used to schedule a delegate for execution. In this case, we choose the priority. The will execute this delegate only when there are no important events to process. UI responsiveness is more important than number checking. We also pass a new delegate representing the number-checking routine.
- Besides updating the text on the , this handler is responsible for scheduling the first prime number check by adding a delegate to the queue. Sometime after this event handler has completed its work, the will select this delegate for execution.
+ :::code language="csharp" source="./snippets/threading-model/csharp/PrimeNumber.xaml.cs" id="check_number":::
+ :::code language="vb" source="./snippets/threading-model/vb/PrimeNumber.xaml.vb" id="check_number":::
- As we mentioned earlier, is the member used to schedule a delegate for execution. In this case, we choose the priority. The will execute this delegate only when there are no important events to process. UI responsiveness is more important than number checking. We also pass a new delegate representing the number-checking routine.
+ This method checks if the next odd number is prime. If it is prime, the method directly updates the `bigPrime` to reflect its discovery. We can do this because the calculation is occurring in the same thread that was used to create the control. Had we chosen to use a separate thread for the calculation, we would have to use a more complicated synchronization mechanism and execute the update in the UI thread. We'll demonstrate this situation next.
- [!code-csharp[ThreadingPrimeNumbers#ThreadingPrimeNumberCheckNextNumber](~/samples/snippets/csharp/VS_Snippets_Wpf/ThreadingPrimeNumbers/CSharp/Window1.xaml.cs#threadingprimenumberchecknextnumber)]
- [!code-vb[ThreadingPrimeNumbers#ThreadingPrimeNumberCheckNextNumber](~/samples/snippets/visualbasic/VS_Snippets_Wpf/ThreadingPrimeNumbers/visualbasic/mainwindow.xaml.vb#threadingprimenumberchecknextnumber)]
+
- This method checks if the next odd number is prime. If it is prime, the method directly updates the `bigPrime` to reflect its discovery. We can do this because the calculation is occurring in the same thread that was used to create the component. Had we chosen to use a separate thread for the calculation, we would have to use a more complicated synchronization mechanism and execute the update in the UI thread. We’ll demonstrate this situation next.
+## Handle a blocking operation with a background thread
- For the complete source code for this sample, see the [Single-Threaded Application with Long-Running Calculation Sample](https://github.com/Microsoft/WPF-Samples/tree/master/Threading/SingleThreadedApplication)
+ Handling blocking operations in a graphical application can be difficult. We don't want to call blocking methods from event handlers because the application will appear to freeze up. We can use a separate thread to handle these operations, but when we're done, we have to synchronize with the UI thread because we can't directly modify the GUI from our worker thread. We can use , , or , to insert delegates into the of the UI thread. Eventually, these delegates will be executed with permission to modify UI elements.
-
+In this example, we mimic a remote procedure call that retrieves a weather forecast. When the button is clicked, the UI is updated normally to indicate that the data fetch is in progress. A separate worker thread is used to mimic fetching the weather forecast. When the "data" is returned, the is used to schedule an update to the UI with the weather information.
+
+:::image type="complex" source="./media/threading-model/threading-weather-ui.png" alt-text="A diagram that demonstrates the workflow of the example app.":::
-### Handling a Blocking Operation with a Background Thread
+A diagram demonstrating the example app's workflow. The app has a single button with the text "Fetch Forecast." There's an arrow pointing to the next phase of the app after the button is pressed, which is a clock image placed in the center of the app indicating that the app is busy fetching data. After some time, the app returns with either an image of the sun or of rain clouds, depending on the result of the data.
- Handling blocking operations in a graphical application can be difficult. We don’t want to call blocking methods from event handlers because the application will appear to freeze up. We can use a separate thread to handle these operations, but when we’re done, we have to synchronize with the UI thread because we can’t directly modify the GUI from our worker thread. We can use or to insert delegates into the of the UI thread. Eventually, these delegates will be executed with permission to modify UI elements.
+:::image-end:::
- In this example, we mimic a remote procedure call that retrieves a weather forecast. We use a separate worker thread to execute this call, and we schedule an update method in the of the UI thread when we’re finished.
+A sample app demonstrating the concepts of this section can be downloaded from GitHub for either [C#](https://github.com/dotnet/samples/tree/main/wpf/Threading/WeatherForecast/net48/csharp) or [Visual Basic](https://github.com/dotnet/samples/tree/main/wpf/Threading/WeatherForecast/net48/vb). The XAML for this example is quite large and not provided in this article. Use the previous GitHub links to browse the XAML.
- ![Screenshot that shows the weather UI.](./media/threading-model/threading-weather-ui.png)
+Consider the code-behind to the XAML:
- [!code-csharp[ThreadingWeatherForecast#ThreadingWeatherCodeBehind](~/samples/snippets/csharp/VS_Snippets_Wpf/ThreadingWeatherForecast/CSharp/Window1.xaml.cs#threadingweathercodebehind)]
- [!code-vb[ThreadingWeatherForecast#ThreadingWeatherCodeBehind](~/samples/snippets/visualbasic/VS_Snippets_Wpf/ThreadingWeatherForecast/visualbasic/window1.xaml.vb#threadingweathercodebehind)]
+:::code language="csharp" source="./snippets/threading-model/csharp/Weather.xaml.cs" id="full":::
+:::code language="vb" source="./snippets/threading-model/vb/Weather.xaml.vb" id="full":::
The following are some of the details to be noted.
- Creating the Button Handler
- [!code-csharp[ThreadingWeatherForecast#ThreadingWeatherButtonHandler](~/samples/snippets/csharp/VS_Snippets_Wpf/ThreadingWeatherForecast/CSharp/Window1.xaml.cs#threadingweatherbuttonhandler)]
- [!code-vb[ThreadingWeatherForecast#ThreadingWeatherButtonHandler](~/samples/snippets/visualbasic/VS_Snippets_Wpf/ThreadingWeatherForecast/visualbasic/window1.xaml.vb#threadingweatherbuttonhandler)]
+ :::code language="csharp" source="./snippets/threading-model/csharp/Weather.xaml.cs" id="button" highlight="1,10":::
+ :::code language="vb" source="./snippets/threading-model/vb/Weather.xaml.vb" id="button" highlight="1,10":::
- When the button is clicked, we display the clock drawing and start animating it. We disable the button. We invoke the `FetchWeatherFromServer` method in a new thread, and then we return, allowing the to process events while we wait to collect the weather forecast.
+ Notice that the event handler was declared as `async` (or `Async` with Visual Basic). An async method suspends the code when the awaited method, `FetchWeatherFromServer` is called, designated by the `await` (or `Await` with Visual Basic) keyword. Until the `FetchWeatherFromServer` finishes, the button's handler code returns control to the caller of the async method. This is similar to a synchronous method except that a synchronous method waits for every operation in the method to finish after which control is returned to the caller.
+
+ Awaited methods utilize the threading context of the current method, which in the case of the button handler, is the UI thread. This means that calling `await FetchWeatherFromServer();` (Or `Await FetchWeatherFromServer()` with Visual Basic) causes the code in `FetchWeatherFromServer` to run on the UI thread. However, notice that `await Task.Run` is used. This creates a new thread on the thread pool for the designated task, `FetchWeatherFromServer`, so it's not running in the UI thread but on its own thread.
- Fetching the Weather
- [!code-csharp[ThreadingWeatherForecast#ThreadingWeatherFetchWeather](~/samples/snippets/csharp/VS_Snippets_Wpf/ThreadingWeatherForecast/CSharp/Window1.xaml.cs#threadingweatherfetchweather)]
- [!code-vb[ThreadingWeatherForecast#ThreadingWeatherFetchWeather](~/samples/snippets/visualbasic/VS_Snippets_Wpf/ThreadingWeatherForecast/visualbasic/window1.xaml.vb#threadingweatherfetchweather)]
+ :::code language="csharp" source="./snippets/threading-model/csharp/Weather.xaml.cs" id="fetch_weather":::
+ :::code language="vb" source="./snippets/threading-model/vb/Weather.xaml.vb" id="fetch_weather":::
- To keep things simple, we don’t actually have any networking code in this example. Instead, we simulate the delay of network access by putting our new thread to sleep for four seconds. In this time, the original UI thread is still running and responding to events. To show this, we’ve left an animation running, and the minimize and maximize buttons also continue to work.
+ To keep things simple, we don't actually have any networking code in this example. Instead, we simulate the delay of network access by putting our new thread to sleep for four seconds. In this time, the original UI thread is still running and responding to events, all the while the button's event handler is paused until this thread completes. To show this, we've left an animation running, and the minimize and maximize buttons also continue to work.
- When the delay is finished, and we’ve randomly selected our weather forecast, it’s time to report back to the UI thread. We do this by scheduling a call to `UpdateUserInterface` in the UI thread using that thread’s . We pass a string describing the weather to this scheduled method call.
+ When the delay is finished, and we've randomly selected our weather forecast, and the weather status is returned to the caller, which is running on the UI thread.
- Updating the UI
- [!code-csharp[ThreadingWeatherForecast#ThreadingWeatherUpdateUI](~/samples/snippets/csharp/VS_Snippets_Wpf/ThreadingWeatherForecast/CSharp/Window1.xaml.cs#threadingweatherupdateui)]
- [!code-vb[ThreadingWeatherForecast#ThreadingWeatherUpdateUI](~/samples/snippets/visualbasic/VS_Snippets_Wpf/ThreadingWeatherForecast/visualbasic/window1.xaml.vb#threadingweatherupdateui)]
+ :::code language="csharp" source="./snippets/threading-model/csharp/Weather.xaml.cs" id="button" highlight="14-27":::
+ :::code language="vb" source="./snippets/threading-model/vb/Weather.xaml.vb" id="button" highlight="14-30":::
+
+ When the task finishes and the UI thread has time, the button's event handler is resumed. The rest of the method stops the clock animation and chooses an image to describe the weather. It displays this image and enables the "fetch forecast" button.
- When the in the UI thread has time, it executes the scheduled call to `UpdateUserInterface`. This method stops the clock animation and chooses an image to describe the weather. It displays this image and restores the "fetch forecast" button.
+A sample app demonstrating the concepts of this section can be downloaded from GitHub for either [C#](https://github.com/dotnet/samples/tree/main/wpf/Threading/Weather/net48/csharp) or [Visual Basic](https://github.com/dotnet/samples/tree/main/wpf/Threading/Weather/net48/vb).
-### Multiple Windows, Multiple Threads
+## Multiple windows, multiple threads
- Some WPF applications require multiple top-level windows. It is perfectly acceptable for one Thread/ combination to manage multiple windows, but sometimes several threads do a better job. This is especially true if there is any chance that one of the windows will monopolize the thread.
+Some WPF applications require multiple top-level windows. It's perfectly acceptable for one Thread/Dispatcher combination to manage multiple windows, but sometimes several threads do a better job. This is especially true if there's any chance that one of the windows will monopolize the thread.
- Windows Explorer works in this fashion. Each new Explorer window belongs to the original process, but it is created under the control of an independent thread.
+Windows Explorer works in this fashion. Each new Explorer window belongs to the original process, but it's created under the control of an independent thread. When Explorer becomes nonresponsive, such as when looking for network resources, other Explorer windows continue to be responsive and usable.
- By using a WPF control, we can display Web pages. We can easily create a simple Internet Explorer substitute. We start with an important feature: the ability to open a new explorer window. When the user clicks the "new window" button, we launch a copy of our window in a separate thread. This way, long-running or blocking operations in one of the windows won’t lock all the other windows.
+We can demonstrate this concept with the following example.
- In reality, the Web browser model has its own complicated threading model. We’ve chosen it because it should be familiar to most readers.
+:::image type="complex" source="./media/threading-model/threading-multiwindow-ui.png" alt-text="A screenshot of a WPF window that's duplicated four times. Three of the windows indicate that they're using the same thread, while the other two are on different threads.":::
- The following example shows the code.
+The top three windows of this image share the same thread identifier: 1. The two other windows have different thread identifiers: Nine and 4. There's a magenta colored rotating ‼️ glyph in the top right of each window.
- [!code-xaml[ThreadingMultipleBrowsers#ThreadingMultiBrowserXAML](~/samples/snippets/csharp/VS_Snippets_Wpf/ThreadingMultipleBrowsers/CSharp/Window1.xaml#threadingmultibrowserxaml)]
+:::image-end:::
- [!code-csharp[ThreadingMultipleBrowsers#ThreadingMultiBrowserCodeBehind](~/samples/snippets/csharp/VS_Snippets_Wpf/ThreadingMultipleBrowsers/CSharp/Window1.xaml.cs#threadingmultibrowsercodebehind)]
- [!code-vb[ThreadingMultipleBrowsers#ThreadingMultiBrowserCodeBehind](~/samples/snippets/visualbasic/VS_Snippets_Wpf/ThreadingMultipleBrowsers/VisualBasic/Window1.xaml.vb#threadingmultibrowsercodebehind)]
+This example contains a window with a rotating `‼️` glyph, a **Pause** button, and two other buttons that create a new window under the current thread or in a new thread. The `‼️` glyph is constantly rotating until the **Pause** button is pressed, which pauses the thread for five seconds. At the bottom of the window, the thread identifier is displayed.
- The following threading segments of this code are the most interesting to us in this context:
+When the **Pause** button is pressed, all windows under the same thread become nonresponsive. Any window under a different thread continues to work normally.
- [!code-csharp[ThreadingMultipleBrowsers#ThreadingMultiBrowserNewWindow](~/samples/snippets/csharp/VS_Snippets_Wpf/ThreadingMultipleBrowsers/CSharp/Window1.xaml.cs#threadingmultibrowsernewwindow)]
- [!code-vb[ThreadingMultipleBrowsers#ThreadingMultiBrowserNewWindow](~/samples/snippets/visualbasic/VS_Snippets_Wpf/ThreadingMultipleBrowsers/VisualBasic/Window1.xaml.vb#threadingmultibrowsernewwindow)]
+The following example is the XAML to the window:
- This method is called when the "new window" button is clicked. It creates a new thread and starts it asynchronously.
+:::code language="xaml" source="./snippets/threading-model/csharp/MultiWindow.xaml":::
- [!code-csharp[ThreadingMultipleBrowsers#ThreadingMultiBrowserThreadStart](~/samples/snippets/csharp/VS_Snippets_Wpf/ThreadingMultipleBrowsers/CSharp/Window1.xaml.cs#threadingmultibrowserthreadstart)]
- [!code-vb[ThreadingMultipleBrowsers#ThreadingMultiBrowserThreadStart](~/samples/snippets/visualbasic/VS_Snippets_Wpf/ThreadingMultipleBrowsers/VisualBasic/Window1.xaml.vb#threadingmultibrowserthreadstart)]
+The following example shows the code-behind.
- This method is the starting point for the new thread. We create a new window under the control of this thread. WPF automatically creates a new to manage the new thread. All we have to do to make the window functional is to start the .
+:::code language="csharp" source="./snippets/threading-model/csharp/MultiWindow.xaml.cs" id="full":::
+:::code language="vb" source="./snippets/threading-model/vb/MultiWindow.xaml.vb" id="full":::
-
+The following are some of the details to be noted:
-## Technical Details and Stumbling Points
+- The task is used to cause the current thread to pause for five seconds when the **Pause** button is pressed.
-### Writing Components Using Threading
+ :::code language="csharp" source="./snippets/threading-model/csharp/MultiWindow.xaml.cs" id="delay":::
+ :::code language="vb" source="./snippets/threading-model/vb/MultiWindow.xaml.vb" id="delay":::
- The Microsoft .NET Framework Developer's Guide describes a pattern for how a component can expose asynchronous behavior to its clients (see [Event-based Asynchronous Pattern Overview](/dotnet/standard/asynchronous-programming-patterns/event-based-asynchronous-pattern-overview)). For instance, suppose we wanted to package the `FetchWeatherFromServer` method into a reusable, nongraphical component. Following the standard Microsoft .NET Framework pattern, this would look something like the following.
+- The `SameThreadWindow_Click` event handler immediently shows a new window under the current thread. The `NewThreadWindow_Click` event handler creates a new thread that starts executing the `ThreadStartingPoint` method, which in turn shows a new window, as described in the next bullet point.
- [!code-csharp[CommandingOverviewSnippets#ThreadingArticleWeatherComponent1](~/samples/snippets/csharp/VS_Snippets_Wpf/CommandingOverviewSnippets/CSharp/Window1.xaml.cs#threadingarticleweathercomponent1)]
- [!code-vb[CommandingOverviewSnippets#ThreadingArticleWeatherComponent1](~/samples/snippets/visualbasic/VS_Snippets_Wpf/CommandingOverviewSnippets/visualbasic/window1.xaml.vb#threadingarticleweathercomponent1)]
+ :::code language="csharp" source="./snippets/threading-model/csharp/MultiWindow.xaml.cs" id="buttons" highlight="2,6":::
+ :::code language="vb" source="./snippets/threading-model/vb/MultiWindow.xaml.vb" id="buttons" highlight="2,6":::
- `GetWeatherAsync` would use one of the techniques described earlier, such as creating a background thread, to do the work asynchronously, not blocking the calling thread.
+- The `ThreadStartingPoint` method is the starting point for the new thread. The new window is created under the control of this thread. WPF automatically creates a new to manage the new thread. All we have to do to make the window functional is to start the .
- One of the most important parts of this pattern is calling the *MethodName*`Completed` method on the same thread that called the *MethodName*`Async` method to begin with. You could do this using WPF fairly easily, by storing —but then the nongraphical component could only be used in WPF applications, not in Windows Forms or ASP.NET programs.
+ :::code language="csharp" source="./snippets/threading-model/csharp/MultiWindow.xaml.cs" id="thread":::
+ :::code language="vb" source="./snippets/threading-model/vb/MultiWindow.xaml.vb" id="thread":::
+
+A sample app demonstrating the concepts of this section can be downloaded from GitHub for either [C#](https://github.com/dotnet/samples/tree/main/wpf/Threading/MultithreadedWindow/net48/csharp) or [Visual Basic](https://github.com/dotnet/samples/tree/main/wpf/Threading/MultithreadedWindow/net48/vb).
+
+
- The class addresses this need—think of it as a simplified version of that works with other UI frameworks as well.
+## Technical details and stumbling points
- [!code-csharp[CommandingOverviewSnippets#ThreadingArticleWeatherComponent2](~/samples/snippets/csharp/VS_Snippets_Wpf/CommandingOverviewSnippets/CSharp/Window1.xaml.cs#threadingarticleweathercomponent2)]
- [!code-vb[CommandingOverviewSnippets#ThreadingArticleWeatherComponent2](~/samples/snippets/visualbasic/VS_Snippets_Wpf/CommandingOverviewSnippets/visualbasic/window1.xaml.vb#threadingarticleweathercomponent2)]
+The following sections describe some of the details and stumbling points you may come across with multithreading.
-### Nested Pumping
+### Nested pumping
- Sometimes it is not feasible to completely lock up the UI thread. Let’s consider the method of the class. doesn’t return until the user clicks the OK button. It does, however, create a window that must have a message loop in order to be interactive. While we are waiting for the user to click OK, the original application window does not respond to user input. It does, however, continue to process paint messages. The original window redraws itself when covered and revealed.
+ Sometimes it is not feasible to completely lock up the UI thread. Let's consider the method of the class. doesn't return until the user clicks the OK button. It does, however, create a window that must have a message loop in order to be interactive. While we are waiting for the user to click OK, the original application window does not respond to user input. It does, however, continue to process paint messages. The original window redraws itself when covered and revealed.
- ![Screenshot that shows a MessageBox with an OK button](./media/threading-model/threading-message-loop.png)
+ :::image type="content" source="./media/threading-model/threading-message-loop.png" alt-text="Screenshot that shows a MessageBox with an OK button":::
- Some thread must be in charge of the message box window. WPF could create a new thread just for the message box window, but this thread would be unable to paint the disabled elements in the original window (remember the earlier discussion of mutual exclusion). Instead, WPF uses a nested message processing system. The class includes a special method called , which stores an application’s current execution point then begins a new message loop. When the nested message loop finishes, execution resumes after the original call.
+ Some thread must be in charge of the message box window. WPF could create a new thread just for the message box window, but this thread would be unable to paint the disabled elements in the original window (remember the earlier discussion of mutual exclusion). Instead, WPF uses a nested message processing system. The class includes a special method called , which stores an application's current execution point then begins a new message loop. When the nested message loop finishes, execution resumes after the original call.
In this case, maintains the program context at the call to , and it starts a new message loop to repaint the background window and handle input to the message box window. When the user clicks OK and clears the pop-up window, the nested loop exits and control resumes after the call to .
-### Stale Routed Events
+### Stale routed events
The routed event system in WPF notifies entire trees when events are raised.
- [!code-xaml[InputOvw#ThreadingArticleStaticRoutedEvent](~/samples/snippets/csharp/VS_Snippets_Wpf/InputOvw/CSharp/Page1.xaml#threadingarticlestaticroutedevent)]
+```xaml
+
+```
When the left mouse button is pressed over the ellipse, `handler2` is executed. After `handler2` finishes, the event is passed along to the object, which uses `handler1` to process it. This happens only if `handler2` does not explicitly mark the event object as handled.
- It’s possible that `handler2` will take a great deal of time processing this event. `handler2` might use to begin a nested message loop that doesn’t return for hours. If `handler2` does not mark the event as handled when this message loop is complete, the event is passed up the tree even though it is very old.
+ It's possible that `handler2` will take a great deal of time processing this event. `handler2` might use to begin a nested message loop that doesn't return for hours. If `handler2` does not mark the event as handled when this message loop is complete, the event is passed up the tree even though it is very old.
-### Reentrancy and Locking
+### Reentrancy and locking
- The locking mechanism of the common language runtime (CLR) doesn’t behave exactly as one might imagine; one might expect a thread to cease operation completely when requesting a lock. In actuality, the thread continues to receive and process high-priority messages. This helps prevent deadlocks and make interfaces minimally responsive, but it introduces the possibility for subtle bugs. The vast majority of the time you don’t need to know anything about this, but under rare circumstances (usually involving Win32 window messages or COM STA components) this can be worth knowing.
+ The locking mechanism of the common language runtime (CLR) doesn't behave exactly as one might imagine; one might expect a thread to cease operation completely when requesting a lock. In actuality, the thread continues to receive and process high-priority messages. This helps prevent deadlocks and make interfaces minimally responsive, but it introduces the possibility for subtle bugs. The vast majority of the time you don't need to know anything about this, but under rare circumstances (usually involving Win32 window messages or COM STA components) this can be worth knowing.
Most interfaces are not built with thread safety in mind because developers work under the assumption that a UI is never accessed by more than one thread. In this case, that single thread may make environmental changes at unexpected times, causing those ill effects that the mutual exclusion mechanism is supposed to solve. Consider the following pseudocode:
- ![Diagram that shows threading reentrancy.](./media/threading-model/threading-reentrancy.png "ThreadingReentrancy")
+ :::image type="content" source="./media/threading-model/threading-reentrancy.png" alt-text="Diagram that shows threading reentrancy.":::
- Most of the time that’s the right thing, but there are times in WPF where such unexpected reentrancy can really cause problems. So, at certain key times, WPF calls , which changes the lock instruction for that thread to use the WPF reentrancy-free lock, instead of the usual CLR lock.
+ Most of the time that's the right thing, but there are times in WPF where such unexpected reentrancy can really cause problems. So, at certain key times, WPF calls , which changes the lock instruction for that thread to use the WPF reentrancy-free lock, instead of the usual CLR lock.
- So why did the CLR team choose this behavior? It had to do with COM STA objects and the finalization thread. When an object is garbage collected, its `Finalize` method is run on the dedicated finalizer thread, not the UI thread. And therein lies the problem, because a COM STA object that was created on the UI thread can only be disposed on the UI thread. The CLR does the equivalent of a (in this case using Win32’s `SendMessage`). But if the UI thread is busy, the finalizer thread is stalled and the COM STA object can’t be disposed, which creates a serious memory leak. So the CLR team made the tough call to make locks work the way they do.
+ So why did the CLR team choose this behavior? It had to do with COM STA objects and the finalization thread. When an object is garbage collected, its `Finalize` method is run on the dedicated finalizer thread, not the UI thread. And therein lies the problem, because a COM STA object that was created on the UI thread can only be disposed on the UI thread. The CLR does the equivalent of a (in this case using Win32's `SendMessage`). But if the UI thread is busy, the finalizer thread is stalled and the COM STA object can't be disposed, which creates a serious memory leak. So the CLR team made the tough call to make locks work the way they do.
- The task for WPF is to avoid unexpected reentrancy without reintroducing the memory leak, which is why we don’t block reentrancy everywhere.
+ The task for WPF is to avoid unexpected reentrancy without reintroducing the memory leak, which is why we don't block reentrancy everywhere.
## See also
diff --git a/dotnet-desktop-guide/samples/snippets/csharp/VS_Snippets_Wpf/ThreadingMultipleBrowsers/CSharp/ThreadingMultipleBrowserSample.csproj b/dotnet-desktop-guide/samples/snippets/csharp/VS_Snippets_Wpf/ThreadingMultipleBrowsers/CSharp/ThreadingMultipleBrowserSample.csproj
deleted file mode 100644
index e929c3f4ff..0000000000
--- a/dotnet-desktop-guide/samples/snippets/csharp/VS_Snippets_Wpf/ThreadingMultipleBrowsers/CSharp/ThreadingMultipleBrowserSample.csproj
+++ /dev/null
@@ -1,64 +0,0 @@
-
-
- Debug
- AnyCPU
- {7EF15B0A-9DD3-4D9D-8711-0F288E68224B}
- SDKSamples
- ThreadingMultipleBrowserSample
- 4
- winexe
- 1.0.0.*
-
- false
- v4.0
- {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
- Client
- 10.0.20821
-
-
- true
- full
- false
- .\bin\Debug\
- DEBUG;TRACE
-
-
- false
- true
- .\bin\Release\
- TRACE
-
-
-
-
-
-
-
-
-
- 4.0
-
-
-
-
-
-
-
- Designer
- MSBuild:Compile
-
-
- Designer
- MSBuild:Compile
-
-
- app.xaml
- Code
-
-
- Window1.xaml
- Code
-
-
-
-
\ No newline at end of file
diff --git a/dotnet-desktop-guide/samples/snippets/csharp/VS_Snippets_Wpf/ThreadingMultipleBrowsers/CSharp/Window1.xaml b/dotnet-desktop-guide/samples/snippets/csharp/VS_Snippets_Wpf/ThreadingMultipleBrowsers/CSharp/Window1.xaml
deleted file mode 100644
index cd5a8cc06e..0000000000
--- a/dotnet-desktop-guide/samples/snippets/csharp/VS_Snippets_Wpf/ThreadingMultipleBrowsers/CSharp/Window1.xaml
+++ /dev/null
@@ -1,25 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dotnet-desktop-guide/samples/snippets/csharp/VS_Snippets_Wpf/ThreadingMultipleBrowsers/CSharp/Window1.xaml.cs b/dotnet-desktop-guide/samples/snippets/csharp/VS_Snippets_Wpf/ThreadingMultipleBrowsers/CSharp/Window1.xaml.cs
deleted file mode 100644
index e359f5f640..0000000000
--- a/dotnet-desktop-guide/samples/snippets/csharp/VS_Snippets_Wpf/ThreadingMultipleBrowsers/CSharp/Window1.xaml.cs
+++ /dev/null
@@ -1,49 +0,0 @@
-//
-using System;
-using System.Windows;
-using System.Windows.Controls;
-using System.Windows.Data;
-using System.Windows.Threading;
-using System.Threading;
-
-namespace SDKSamples
-{
- public partial class Window1 : Window
- {
-
- public Window1() : base()
- {
- InitializeComponent();
- }
-
- private void OnLoaded(object sender, RoutedEventArgs e)
- {
- placeHolder.Source = new Uri("http://www.msn.com");
- }
-
- private void Browse(object sender, RoutedEventArgs e)
- {
- placeHolder.Source = new Uri(newLocation.Text);
- }
-
- //
- private void NewWindowHandler(object sender, RoutedEventArgs e)
- {
- Thread newWindowThread = new Thread(new ThreadStart(ThreadStartingPoint));
- newWindowThread.SetApartmentState(ApartmentState.STA);
- newWindowThread.IsBackground = true;
- newWindowThread.Start();
- }
- //
-
- //
- private void ThreadStartingPoint()
- {
- Window1 tempWindow = new Window1();
- tempWindow.Show();
- System.Windows.Threading.Dispatcher.Run();
- }
- //
- }
-}
-//
\ No newline at end of file
diff --git a/dotnet-desktop-guide/samples/snippets/csharp/VS_Snippets_Wpf/ThreadingMultipleBrowsers/CSharp/app.xaml b/dotnet-desktop-guide/samples/snippets/csharp/VS_Snippets_Wpf/ThreadingMultipleBrowsers/CSharp/app.xaml
deleted file mode 100644
index c205680b08..0000000000
--- a/dotnet-desktop-guide/samples/snippets/csharp/VS_Snippets_Wpf/ThreadingMultipleBrowsers/CSharp/app.xaml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
diff --git a/dotnet-desktop-guide/samples/snippets/csharp/VS_Snippets_Wpf/ThreadingMultipleBrowsers/CSharp/app.xaml.cs b/dotnet-desktop-guide/samples/snippets/csharp/VS_Snippets_Wpf/ThreadingMultipleBrowsers/CSharp/app.xaml.cs
deleted file mode 100644
index d23c731dfc..0000000000
--- a/dotnet-desktop-guide/samples/snippets/csharp/VS_Snippets_Wpf/ThreadingMultipleBrowsers/CSharp/app.xaml.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-using System;
-using System.Windows;
-using System.Data;
-using System.Xml;
-using System.Configuration;
-
-namespace SDKSamples
-{
- ///
- /// Interaction logic for app.xaml
- ///
-
- public partial class app : Application
- {
- }
-}
\ No newline at end of file
diff --git a/dotnet-desktop-guide/samples/snippets/csharp/VS_Snippets_Wpf/ThreadingPrimeNumbers/CSharp/ThreadingPrimeNumberSample.csproj b/dotnet-desktop-guide/samples/snippets/csharp/VS_Snippets_Wpf/ThreadingPrimeNumbers/CSharp/ThreadingPrimeNumberSample.csproj
deleted file mode 100644
index 5efe4a9b95..0000000000
--- a/dotnet-desktop-guide/samples/snippets/csharp/VS_Snippets_Wpf/ThreadingPrimeNumbers/CSharp/ThreadingPrimeNumberSample.csproj
+++ /dev/null
@@ -1,61 +0,0 @@
-
-
- Debug
- AnyCPU
- SDKSamples
- ThreadingPrimeNumberSample
- 4
- winexe
- 1.0.0.*
-
- {53F8DDD9-7DC8-4DBC-BF48-D19E85FDB3EC}
- v4.0
- {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
- Client
- 10.0.20821
-
-
- true
- full
- false
- .\bin\Debug\
- DEBUG;TRACE
-
-
- false
- true
- .\bin\Release\
- TRACE
-
-
-
-
-
-
-
-
- 4.0
-
-
-
-
-
-
- Designer
- MSBuild:Compile
-
-
- Designer
- MSBuild:Compile
-
-
- app.xaml
- Code
-
-
- Window1.xaml
- Code
-
-
-
-
\ No newline at end of file
diff --git a/dotnet-desktop-guide/samples/snippets/csharp/VS_Snippets_Wpf/ThreadingPrimeNumbers/CSharp/Window1.xaml b/dotnet-desktop-guide/samples/snippets/csharp/VS_Snippets_Wpf/ThreadingPrimeNumbers/CSharp/Window1.xaml
deleted file mode 100644
index 3e7351d1c3..0000000000
--- a/dotnet-desktop-guide/samples/snippets/csharp/VS_Snippets_Wpf/ThreadingPrimeNumbers/CSharp/Window1.xaml
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-
-
- Biggest Prime Found:
- 3
-
-
-
diff --git a/dotnet-desktop-guide/samples/snippets/csharp/VS_Snippets_Wpf/ThreadingPrimeNumbers/CSharp/Window1.xaml.cs b/dotnet-desktop-guide/samples/snippets/csharp/VS_Snippets_Wpf/ThreadingPrimeNumbers/CSharp/Window1.xaml.cs
deleted file mode 100644
index 9f58c9e0c4..0000000000
--- a/dotnet-desktop-guide/samples/snippets/csharp/VS_Snippets_Wpf/ThreadingPrimeNumbers/CSharp/Window1.xaml.cs
+++ /dev/null
@@ -1,82 +0,0 @@
-//
-using System;
-using System.Windows;
-using System.Windows.Controls;
-using System.Windows.Threading;
-using System.Threading;
-
-namespace SDKSamples
-{
- public partial class Window1 : Window
- {
- //
- public delegate void NextPrimeDelegate();
- //
-
- //Current number to check
- private long num = 3;
-
- private bool continueCalculating = false;
-
- public Window1() : base()
- {
- InitializeComponent();
- }
-
- //
- private void StartOrStop(object sender, EventArgs e)
- {
- if (continueCalculating)
- {
- continueCalculating = false;
- startStopButton.Content = "Resume";
- }
- else
- {
- continueCalculating = true;
- startStopButton.Content = "Stop";
- //
- startStopButton.Dispatcher.BeginInvoke(
- DispatcherPriority.Normal,
- new NextPrimeDelegate(CheckNextNumber));
- //
- }
- }
- //
-
- //
- public void CheckNextNumber()
- {
- // Reset flag.
- NotAPrime = false;
-
- for (long i = 3; i <= Math.Sqrt(num); i++)
- {
- if (num % i == 0)
- {
- // Set not a prime flag to true.
- NotAPrime = true;
- break;
- }
- }
-
- // If a prime number.
- if (!NotAPrime)
- {
- bigPrime.Text = num.ToString();
- }
-
- num += 2;
- if (continueCalculating)
- {
- startStopButton.Dispatcher.BeginInvoke(
- System.Windows.Threading.DispatcherPriority.SystemIdle,
- new NextPrimeDelegate(this.CheckNextNumber));
- }
- }
-
- private bool NotAPrime = false;
- //
- }
-}
-//
\ No newline at end of file
diff --git a/dotnet-desktop-guide/samples/snippets/csharp/VS_Snippets_Wpf/ThreadingPrimeNumbers/CSharp/app.xaml b/dotnet-desktop-guide/samples/snippets/csharp/VS_Snippets_Wpf/ThreadingPrimeNumbers/CSharp/app.xaml
deleted file mode 100644
index c205680b08..0000000000
--- a/dotnet-desktop-guide/samples/snippets/csharp/VS_Snippets_Wpf/ThreadingPrimeNumbers/CSharp/app.xaml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
diff --git a/dotnet-desktop-guide/samples/snippets/csharp/VS_Snippets_Wpf/ThreadingPrimeNumbers/CSharp/app.xaml.cs b/dotnet-desktop-guide/samples/snippets/csharp/VS_Snippets_Wpf/ThreadingPrimeNumbers/CSharp/app.xaml.cs
deleted file mode 100644
index d23c731dfc..0000000000
--- a/dotnet-desktop-guide/samples/snippets/csharp/VS_Snippets_Wpf/ThreadingPrimeNumbers/CSharp/app.xaml.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-using System;
-using System.Windows;
-using System.Data;
-using System.Xml;
-using System.Configuration;
-
-namespace SDKSamples
-{
- ///
- /// Interaction logic for app.xaml
- ///
-
- public partial class app : Application
- {
- }
-}
\ No newline at end of file
diff --git a/dotnet-desktop-guide/samples/snippets/csharp/VS_Snippets_Wpf/ThreadingWeatherForecast/CSharp/ThreadingWeatherForecastSample.csproj b/dotnet-desktop-guide/samples/snippets/csharp/VS_Snippets_Wpf/ThreadingWeatherForecast/CSharp/ThreadingWeatherForecastSample.csproj
deleted file mode 100644
index 22b084d226..0000000000
--- a/dotnet-desktop-guide/samples/snippets/csharp/VS_Snippets_Wpf/ThreadingWeatherForecast/CSharp/ThreadingWeatherForecastSample.csproj
+++ /dev/null
@@ -1,61 +0,0 @@
-
-
- Debug
- AnyCPU
- SDKSamples
- ThreadingWeatherForecastSample
- 4
- winexe
- 1.0.0.*
-
- {884214C5-0C31-4CC6-ACF0-6096E0993FFE}
- v4.0
- {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
- Client
- 10.0.20821
-
-
- true
- full
- false
- .\bin\Debug\
- DEBUG;TRACE
-
-
- false
- true
- .\bin\Release\
- TRACE
-
-
-
-
-
-
-
-
- 4.0
-
-
-
-
-
-
- Designer
- MSBuild:Compile
-
-
- Designer
- MSBuild:Compile
-
-
- app.xaml
- Code
-
-
- Window1.xaml
- Code
-
-
-
-
\ No newline at end of file
diff --git a/dotnet-desktop-guide/samples/snippets/csharp/VS_Snippets_Wpf/ThreadingWeatherForecast/CSharp/Window1.xaml b/dotnet-desktop-guide/samples/snippets/csharp/VS_Snippets_Wpf/ThreadingWeatherForecast/CSharp/Window1.xaml
deleted file mode 100644
index 46f46edd47..0000000000
--- a/dotnet-desktop-guide/samples/snippets/csharp/VS_Snippets_Wpf/ThreadingWeatherForecast/CSharp/Window1.xaml
+++ /dev/null
@@ -1,190 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dotnet-desktop-guide/samples/snippets/csharp/VS_Snippets_Wpf/ThreadingWeatherForecast/CSharp/Window1.xaml.cs b/dotnet-desktop-guide/samples/snippets/csharp/VS_Snippets_Wpf/ThreadingWeatherForecast/CSharp/Window1.xaml.cs
deleted file mode 100644
index 7d4d5a092a..0000000000
--- a/dotnet-desktop-guide/samples/snippets/csharp/VS_Snippets_Wpf/ThreadingWeatherForecast/CSharp/Window1.xaml.cs
+++ /dev/null
@@ -1,131 +0,0 @@
-//
-using System;
-using System.Windows;
-using System.Windows.Controls;
-using System.Windows.Media;
-using System.Windows.Media.Animation;
-using System.Windows.Media.Imaging;
-using System.Windows.Shapes;
-using System.Windows.Threading;
-using System.Threading;
-
-namespace SDKSamples
-{
- public partial class Window1 : Window
- {
- // Delegates to be used in placking jobs onto the Dispatcher.
- private delegate void NoArgDelegate();
- //
- private delegate void OneArgDelegate(String arg);
- //
-
- // Storyboards for the animations.
- private Storyboard showClockFaceStoryboard;
- private Storyboard hideClockFaceStoryboard;
- private Storyboard showWeatherImageStoryboard;
- private Storyboard hideWeatherImageStoryboard;
-
- public Window1(): base()
- {
- InitializeComponent();
- }
-
- private void Window_Loaded(object sender, RoutedEventArgs e)
- {
- // Load the storyboard resources.
- showClockFaceStoryboard =
- (Storyboard)this.Resources["ShowClockFaceStoryboard"];
- hideClockFaceStoryboard =
- (Storyboard)this.Resources["HideClockFaceStoryboard"];
- showWeatherImageStoryboard =
- (Storyboard)this.Resources["ShowWeatherImageStoryboard"];
- hideWeatherImageStoryboard =
- (Storyboard)this.Resources["HideWeatherImageStoryboard"];
- }
-
- //
- private void ForecastButtonHandler(object sender, RoutedEventArgs e)
- {
- // Change the status image and start the rotation animation.
- fetchButton.IsEnabled = false;
- fetchButton.Content = "Contacting Server";
- weatherText.Text = "";
- hideWeatherImageStoryboard.Begin(this);
-
- // Start fetching the weather forecast asynchronously.
- NoArgDelegate fetcher = new NoArgDelegate(
- this.FetchWeatherFromServer);
-
- fetcher.BeginInvoke(null, null);
- }
- //
-
- //
- private void FetchWeatherFromServer()
- {
- // Simulate the delay from network access.
- Thread.Sleep(4000);
-
- // Tried and true method for weather forecasting - random numbers.
- Random rand = new Random();
- String weather;
-
- if (rand.Next(2) == 0)
- {
- weather = "rainy";
- }
- else
- {
- weather = "sunny";
- }
-
- //
- // Schedule the update function in the UI thread.
- tomorrowsWeather.Dispatcher.BeginInvoke(
- System.Windows.Threading.DispatcherPriority.Normal,
- new OneArgDelegate(UpdateUserInterface),
- weather);
- //
- }
- //
-
- //
- private void UpdateUserInterface(String weather)
- {
- //Set the weather image
- if (weather == "sunny")
- {
- weatherIndicatorImage.Source = (ImageSource)this.Resources[
- "SunnyImageSource"];
- }
- else if (weather == "rainy")
- {
- weatherIndicatorImage.Source = (ImageSource)this.Resources[
- "RainingImageSource"];
- }
-
- //Stop clock animation
- showClockFaceStoryboard.Stop(this);
- hideClockFaceStoryboard.Begin(this);
-
- //Update UI text
- fetchButton.IsEnabled = true;
- fetchButton.Content = "Fetch Forecast";
- weatherText.Text = weather;
- }
- //
-
- private void HideClockFaceStoryboard_Completed(object sender,
- EventArgs args)
- {
- showWeatherImageStoryboard.Begin(this);
- }
-
- private void HideWeatherImageStoryboard_Completed(object sender,
- EventArgs args)
- {
- showClockFaceStoryboard.Begin(this, true);
- }
- }
-}
-//
diff --git a/dotnet-desktop-guide/samples/snippets/csharp/VS_Snippets_Wpf/ThreadingWeatherForecast/CSharp/app.xaml b/dotnet-desktop-guide/samples/snippets/csharp/VS_Snippets_Wpf/ThreadingWeatherForecast/CSharp/app.xaml
deleted file mode 100644
index 355e971088..0000000000
--- a/dotnet-desktop-guide/samples/snippets/csharp/VS_Snippets_Wpf/ThreadingWeatherForecast/CSharp/app.xaml
+++ /dev/null
@@ -1,123 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dotnet-desktop-guide/samples/snippets/csharp/VS_Snippets_Wpf/ThreadingWeatherForecast/CSharp/app.xaml.cs b/dotnet-desktop-guide/samples/snippets/csharp/VS_Snippets_Wpf/ThreadingWeatherForecast/CSharp/app.xaml.cs
deleted file mode 100644
index d23c731dfc..0000000000
--- a/dotnet-desktop-guide/samples/snippets/csharp/VS_Snippets_Wpf/ThreadingWeatherForecast/CSharp/app.xaml.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-using System;
-using System.Windows;
-using System.Data;
-using System.Xml;
-using System.Configuration;
-
-namespace SDKSamples
-{
- ///
- /// Interaction logic for app.xaml
- ///
-
- public partial class app : Application
- {
- }
-}
\ No newline at end of file
diff --git a/dotnet-desktop-guide/samples/snippets/visualbasic/VS_Snippets_Wpf/ThreadingMultipleBrowsers/VisualBasic/ThreadingMultipleBrowserSample.vbproj b/dotnet-desktop-guide/samples/snippets/visualbasic/VS_Snippets_Wpf/ThreadingMultipleBrowsers/VisualBasic/ThreadingMultipleBrowserSample.vbproj
deleted file mode 100644
index 6594ab4cd5..0000000000
--- a/dotnet-desktop-guide/samples/snippets/visualbasic/VS_Snippets_Wpf/ThreadingMultipleBrowsers/VisualBasic/ThreadingMultipleBrowserSample.vbproj
+++ /dev/null
@@ -1,69 +0,0 @@
-
-
- Debug
- AnyCPU
- {7EF15B0A-9DD3-4D9D-8711-0F288E68224B}
-
- ThreadingMultipleBrowserSample
- winexe
- 1.0.0.*
-
- false
- v4.0
- On
- Binary
- Off
- On
- {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{F184B08F-C81C-45F6-A57F-5ABD9991F28F}
- Client
- 10.0.20821
-
-
- true
- full
- false
- .\bin\Debug\
- true
- true
-
-
- false
- true
- .\bin\Release\
- false
- true
-
-
-
-
-
-
-
-
-
- 4.0
-
-
-
-
-
-
-
- Designer
- MSBuild:Compile
-
-
- Designer
- MSBuild:Compile
-
-
- app.xaml
- Code
-
-
- Window1.xaml
- Code
-
-
-
-
\ No newline at end of file
diff --git a/dotnet-desktop-guide/samples/snippets/visualbasic/VS_Snippets_Wpf/ThreadingMultipleBrowsers/VisualBasic/Window1.xaml b/dotnet-desktop-guide/samples/snippets/visualbasic/VS_Snippets_Wpf/ThreadingMultipleBrowsers/VisualBasic/Window1.xaml
deleted file mode 100644
index d1f60c017f..0000000000
--- a/dotnet-desktop-guide/samples/snippets/visualbasic/VS_Snippets_Wpf/ThreadingMultipleBrowsers/VisualBasic/Window1.xaml
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dotnet-desktop-guide/samples/snippets/visualbasic/VS_Snippets_Wpf/ThreadingMultipleBrowsers/VisualBasic/Window1.xaml.vb b/dotnet-desktop-guide/samples/snippets/visualbasic/VS_Snippets_Wpf/ThreadingMultipleBrowsers/VisualBasic/Window1.xaml.vb
deleted file mode 100644
index b19c04996f..0000000000
--- a/dotnet-desktop-guide/samples/snippets/visualbasic/VS_Snippets_Wpf/ThreadingMultipleBrowsers/VisualBasic/Window1.xaml.vb
+++ /dev/null
@@ -1,45 +0,0 @@
-'
-
-Imports System.Windows
-Imports System.Windows.Controls
-Imports System.Windows.Data
-Imports System.Windows.Threading
-Imports System.Threading
-
-
-Namespace SDKSamples
- Partial Public Class Window1
- Inherits Window
-
- Public Sub New()
- MyBase.New()
- InitializeComponent()
- End Sub
-
- Private Sub OnLoaded(ByVal sender As Object, ByVal e As RoutedEventArgs)
- placeHolder.Source = New Uri("http://www.msn.com")
- End Sub
-
- Private Sub Browse(ByVal sender As Object, ByVal e As RoutedEventArgs)
- placeHolder.Source = New Uri(newLocation.Text)
- End Sub
-
- '
- Private Sub NewWindowHandler(ByVal sender As Object, ByVal e As RoutedEventArgs)
- Dim newWindowThread As New Thread(New ThreadStart(AddressOf ThreadStartingPoint))
- newWindowThread.SetApartmentState(ApartmentState.STA)
- newWindowThread.IsBackground = True
- newWindowThread.Start()
- End Sub
- '
-
- '
- Private Sub ThreadStartingPoint()
- Dim tempWindow As New Window1()
- tempWindow.Show()
- System.Windows.Threading.Dispatcher.Run()
- End Sub
- '
- End Class
-End Namespace
-'
\ No newline at end of file
diff --git a/dotnet-desktop-guide/samples/snippets/visualbasic/VS_Snippets_Wpf/ThreadingMultipleBrowsers/VisualBasic/app.xaml b/dotnet-desktop-guide/samples/snippets/visualbasic/VS_Snippets_Wpf/ThreadingMultipleBrowsers/VisualBasic/app.xaml
deleted file mode 100644
index 4afe9002f6..0000000000
--- a/dotnet-desktop-guide/samples/snippets/visualbasic/VS_Snippets_Wpf/ThreadingMultipleBrowsers/VisualBasic/app.xaml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
diff --git a/dotnet-desktop-guide/samples/snippets/visualbasic/VS_Snippets_Wpf/ThreadingMultipleBrowsers/VisualBasic/app.xaml.vb b/dotnet-desktop-guide/samples/snippets/visualbasic/VS_Snippets_Wpf/ThreadingMultipleBrowsers/VisualBasic/app.xaml.vb
deleted file mode 100644
index 067b6f355a..0000000000
--- a/dotnet-desktop-guide/samples/snippets/visualbasic/VS_Snippets_Wpf/ThreadingMultipleBrowsers/VisualBasic/app.xaml.vb
+++ /dev/null
@@ -1,15 +0,0 @@
-Imports System.Windows
-Imports System.Data
-Imports System.Xml
-Imports System.Configuration
-
-Namespace SDKSamples
- '''
- ''' Interaction logic for app.xaml
- '''
-
- Partial Public Class app
- Inherits Application
-
- End Class
-End Namespace
\ No newline at end of file
diff --git a/dotnet-desktop-guide/samples/snippets/visualbasic/VS_Snippets_Wpf/ThreadingPrimeNumbers/visualbasic/application.xaml b/dotnet-desktop-guide/samples/snippets/visualbasic/VS_Snippets_Wpf/ThreadingPrimeNumbers/visualbasic/application.xaml
deleted file mode 100644
index ff7991a65c..0000000000
--- a/dotnet-desktop-guide/samples/snippets/visualbasic/VS_Snippets_Wpf/ThreadingPrimeNumbers/visualbasic/application.xaml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
diff --git a/dotnet-desktop-guide/samples/snippets/visualbasic/VS_Snippets_Wpf/ThreadingPrimeNumbers/visualbasic/mainwindow.xaml b/dotnet-desktop-guide/samples/snippets/visualbasic/VS_Snippets_Wpf/ThreadingPrimeNumbers/visualbasic/mainwindow.xaml
deleted file mode 100644
index e116a11a15..0000000000
--- a/dotnet-desktop-guide/samples/snippets/visualbasic/VS_Snippets_Wpf/ThreadingPrimeNumbers/visualbasic/mainwindow.xaml
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
- Biggest Prime Found:
- 3
-
-
\ No newline at end of file
diff --git a/dotnet-desktop-guide/samples/snippets/visualbasic/VS_Snippets_Wpf/ThreadingPrimeNumbers/visualbasic/mainwindow.xaml.vb b/dotnet-desktop-guide/samples/snippets/visualbasic/VS_Snippets_Wpf/ThreadingPrimeNumbers/visualbasic/mainwindow.xaml.vb
deleted file mode 100644
index 639598c386..0000000000
--- a/dotnet-desktop-guide/samples/snippets/visualbasic/VS_Snippets_Wpf/ThreadingPrimeNumbers/visualbasic/mainwindow.xaml.vb
+++ /dev/null
@@ -1,67 +0,0 @@
-'
-Imports System.Windows
-Imports System.Windows.Controls
-Imports System.Windows.Threading
-Imports System.Threading
-
-Namespace SDKSamples
- Partial Public Class MainWindow
- Inherits Window
- '
- Public Delegate Sub NextPrimeDelegate()
- '
-
- 'Current number to check
- Private num As Long = 3
-
- Private continueCalculating As Boolean = False
-
- Public Sub New()
- MyBase.New()
- InitializeComponent()
- End Sub
-
- '
- Private Sub StartOrStop(ByVal sender As Object, ByVal e As EventArgs)
- If continueCalculating Then
- continueCalculating = False
- startStopButton.Content = "Resume"
- Else
- continueCalculating = True
- startStopButton.Content = "Stop"
- '
- startStopButton.Dispatcher.BeginInvoke(DispatcherPriority.Normal, New NextPrimeDelegate(AddressOf CheckNextNumber))
- '
- End If
- End Sub
- '
-
- '
- Public Sub CheckNextNumber()
- ' Reset flag.
- NotAPrime = False
-
- For i As Long = 3 To Math.Sqrt(num)
- If num Mod i = 0 Then
- ' Set not a prime flag to true.
- NotAPrime = True
- Exit For
- End If
- Next
-
- ' If a prime number.
- If Not NotAPrime Then
- bigPrime.Text = num.ToString()
- End If
-
- num += 2
- If continueCalculating Then
- startStopButton.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.SystemIdle, New NextPrimeDelegate(AddressOf Me.CheckNextNumber))
- End If
- End Sub
-
- Private NotAPrime As Boolean = False
- '
- End Class
-End Namespace
-'
diff --git a/dotnet-desktop-guide/samples/snippets/visualbasic/VS_Snippets_Wpf/ThreadingWeatherForecast/visualbasic/app.xaml b/dotnet-desktop-guide/samples/snippets/visualbasic/VS_Snippets_Wpf/ThreadingWeatherForecast/visualbasic/app.xaml
deleted file mode 100644
index 355e971088..0000000000
--- a/dotnet-desktop-guide/samples/snippets/visualbasic/VS_Snippets_Wpf/ThreadingWeatherForecast/visualbasic/app.xaml
+++ /dev/null
@@ -1,123 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dotnet-desktop-guide/samples/snippets/visualbasic/VS_Snippets_Wpf/ThreadingWeatherForecast/visualbasic/app.xaml.vb b/dotnet-desktop-guide/samples/snippets/visualbasic/VS_Snippets_Wpf/ThreadingWeatherForecast/visualbasic/app.xaml.vb
deleted file mode 100644
index 067b6f355a..0000000000
--- a/dotnet-desktop-guide/samples/snippets/visualbasic/VS_Snippets_Wpf/ThreadingWeatherForecast/visualbasic/app.xaml.vb
+++ /dev/null
@@ -1,15 +0,0 @@
-Imports System.Windows
-Imports System.Data
-Imports System.Xml
-Imports System.Configuration
-
-Namespace SDKSamples
- '''
- ''' Interaction logic for app.xaml
- '''
-
- Partial Public Class app
- Inherits Application
-
- End Class
-End Namespace
\ No newline at end of file
diff --git a/dotnet-desktop-guide/samples/snippets/visualbasic/VS_Snippets_Wpf/ThreadingWeatherForecast/visualbasic/threadingweatherforecastsample.vbproj b/dotnet-desktop-guide/samples/snippets/visualbasic/VS_Snippets_Wpf/ThreadingWeatherForecast/visualbasic/threadingweatherforecastsample.vbproj
deleted file mode 100644
index 4568f7da8d..0000000000
--- a/dotnet-desktop-guide/samples/snippets/visualbasic/VS_Snippets_Wpf/ThreadingWeatherForecast/visualbasic/threadingweatherforecastsample.vbproj
+++ /dev/null
@@ -1,66 +0,0 @@
-
-
- Debug
- AnyCPU
-
- ThreadingWeatherForecastSample
- winexe
- 1.0.0.*
-
- {884214C5-0C31-4CC6-ACF0-6096E0993FFE}
- v4.0
- On
- Binary
- Off
- On
- {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{F184B08F-C81C-45F6-A57F-5ABD9991F28F}
- Client
- 10.0.20821
-
-
- true
- full
- false
- .\bin\Debug\
- true
- true
-
-
- false
- true
- .\bin\Release\
- false
- true
-
-
-
-
-
-
-
-
- 4.0
-
-
-
-
-
-
- Designer
- MSBuild:Compile
-
-
- Designer
- MSBuild:Compile
-
-
- app.xaml
- Code
-
-
- Window1.xaml
- Code
-
-
-
-
\ No newline at end of file
diff --git a/dotnet-desktop-guide/samples/snippets/visualbasic/VS_Snippets_Wpf/ThreadingWeatherForecast/visualbasic/window1.xaml b/dotnet-desktop-guide/samples/snippets/visualbasic/VS_Snippets_Wpf/ThreadingWeatherForecast/visualbasic/window1.xaml
deleted file mode 100644
index 46f46edd47..0000000000
--- a/dotnet-desktop-guide/samples/snippets/visualbasic/VS_Snippets_Wpf/ThreadingWeatherForecast/visualbasic/window1.xaml
+++ /dev/null
@@ -1,190 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dotnet-desktop-guide/samples/snippets/visualbasic/VS_Snippets_Wpf/ThreadingWeatherForecast/visualbasic/window1.xaml.vb b/dotnet-desktop-guide/samples/snippets/visualbasic/VS_Snippets_Wpf/ThreadingWeatherForecast/visualbasic/window1.xaml.vb
deleted file mode 100644
index a2443dbe59..0000000000
--- a/dotnet-desktop-guide/samples/snippets/visualbasic/VS_Snippets_Wpf/ThreadingWeatherForecast/visualbasic/window1.xaml.vb
+++ /dev/null
@@ -1,106 +0,0 @@
-'
-
-Imports System.Windows
-Imports System.Windows.Controls
-Imports System.Windows.Media
-Imports System.Windows.Media.Animation
-Imports System.Windows.Media.Imaging
-Imports System.Windows.Shapes
-Imports System.Windows.Threading
-Imports System.Threading
-
-Namespace SDKSamples
- Partial Public Class Window1
- Inherits Window
- ' Delegates to be used in placking jobs onto the Dispatcher.
- Private Delegate Sub NoArgDelegate()
- '
- Private Delegate Sub OneArgDelegate(ByVal arg As String)
- '
-
- ' Storyboards for the animations.
- Private showClockFaceStoryboard As Storyboard
- Private hideClockFaceStoryboard As Storyboard
- Private showWeatherImageStoryboard As Storyboard
- Private hideWeatherImageStoryboard As Storyboard
-
- Public Sub New()
- MyBase.New()
- InitializeComponent()
- End Sub
-
- Private Sub Window_Loaded(ByVal sender As Object, ByVal e As RoutedEventArgs)
- ' Load the storyboard resources.
- showClockFaceStoryboard = CType(Me.Resources("ShowClockFaceStoryboard"), Storyboard)
- hideClockFaceStoryboard = CType(Me.Resources("HideClockFaceStoryboard"), Storyboard)
- showWeatherImageStoryboard = CType(Me.Resources("ShowWeatherImageStoryboard"), Storyboard)
- hideWeatherImageStoryboard = CType(Me.Resources("HideWeatherImageStoryboard"), Storyboard)
- End Sub
-
- '
- Private Sub ForecastButtonHandler(ByVal sender As Object, ByVal e As RoutedEventArgs)
- ' Change the status image and start the rotation animation.
- fetchButton.IsEnabled = False
- fetchButton.Content = "Contacting Server"
- weatherText.Text = ""
- hideWeatherImageStoryboard.Begin(Me)
-
- ' Start fetching the weather forecast asynchronously.
- Dim fetcher As New NoArgDelegate(AddressOf Me.FetchWeatherFromServer)
-
- fetcher.BeginInvoke(Nothing, Nothing)
- End Sub
- '
-
- '
- Private Sub FetchWeatherFromServer()
- ' Simulate the delay from network access.
- Thread.Sleep(4000)
-
- ' Tried and true method for weather forecasting - random numbers.
- Dim rand As New Random()
- Dim weather As String
-
- If rand.Next(2) = 0 Then
- weather = "rainy"
- Else
- weather = "sunny"
- End If
-
- '
- ' Schedule the update function in the UI thread.
- tomorrowsWeather.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Normal, New OneArgDelegate(AddressOf UpdateUserInterface), weather)
- '
- End Sub
- '
-
- '
- Private Sub UpdateUserInterface(ByVal weather As String)
- 'Set the weather image
- If weather = "sunny" Then
- weatherIndicatorImage.Source = CType(Me.Resources("SunnyImageSource"), ImageSource)
- ElseIf weather = "rainy" Then
- weatherIndicatorImage.Source = CType(Me.Resources("RainingImageSource"), ImageSource)
- End If
-
- 'Stop clock animation
- showClockFaceStoryboard.Stop(Me)
- hideClockFaceStoryboard.Begin(Me)
-
- 'Update UI text
- fetchButton.IsEnabled = True
- fetchButton.Content = "Fetch Forecast"
- weatherText.Text = weather
- End Sub
- '
-
- Private Sub HideClockFaceStoryboard_Completed(ByVal sender As Object, ByVal args As EventArgs)
- showWeatherImageStoryboard.Begin(Me)
- End Sub
-
- Private Sub HideWeatherImageStoryboard_Completed(ByVal sender As Object, ByVal args As EventArgs)
- showClockFaceStoryboard.Begin(Me, True)
- End Sub
- End Class
-End Namespace
-'