diff --git a/Microsoft.Toolkit.Uwp.Connectivity/BluetoothLEHelper/BluetoothLEHelper.cs b/Microsoft.Toolkit.Uwp.Connectivity/BluetoothLEHelper/BluetoothLEHelper.cs
index c83718ec2ac..bafe8f6939e 100644
--- a/Microsoft.Toolkit.Uwp.Connectivity/BluetoothLEHelper/BluetoothLEHelper.cs
+++ b/Microsoft.Toolkit.Uwp.Connectivity/BluetoothLEHelper/BluetoothLEHelper.cs
@@ -8,7 +8,7 @@
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
-using Microsoft.Toolkit.Uwp.Helpers;
+using Microsoft.Toolkit.Uwp.Extensions;
using Windows.Devices.Bluetooth;
using Windows.Devices.Bluetooth.Advertisement;
using Windows.Devices.Enumeration;
@@ -197,7 +197,7 @@ private async Task Init()
/// The advertisement.
private async void AdvertisementWatcher_Received(BluetoothLEAdvertisementWatcher sender, BluetoothLEAdvertisementReceivedEventArgs args)
{
- await DispatcherQueue.ExecuteOnUIThreadAsync(
+ await DispatcherQueue.EnqueueAsync(
() =>
{
if (_readerWriterLockSlim.TryEnterReadLock(TimeSpan.FromSeconds(1)))
@@ -281,7 +281,7 @@ private async void DeviceWatcher_Removed(DeviceWatcher sender, DeviceInformation
// Protect against race condition if the task runs after the app stopped the deviceWatcher.
if (sender == _deviceWatcher)
{
- await DispatcherQueue.ExecuteOnUIThreadAsync(
+ await DispatcherQueue.EnqueueAsync(
() =>
{
if (_readerWriterLockSlim.TryEnterWriteLock(TimeSpan.FromSeconds(1)))
@@ -331,7 +331,7 @@ private async Task AddDeviceToList(DeviceInformation deviceInfo)
if (connectable)
{
- await DispatcherQueue.ExecuteOnUIThreadAsync(
+ await DispatcherQueue.EnqueueAsync(
() =>
{
if (_readerWriterLockSlim.TryEnterWriteLock(TimeSpan.FromSeconds(1)))
diff --git a/Microsoft.Toolkit.Uwp.Connectivity/BluetoothLEHelper/ObservableBluetoothLEDevice.cs b/Microsoft.Toolkit.Uwp.Connectivity/BluetoothLEHelper/ObservableBluetoothLEDevice.cs
index 2e72750c433..6aec998c966 100644
--- a/Microsoft.Toolkit.Uwp.Connectivity/BluetoothLEHelper/ObservableBluetoothLEDevice.cs
+++ b/Microsoft.Toolkit.Uwp.Connectivity/BluetoothLEHelper/ObservableBluetoothLEDevice.cs
@@ -11,12 +11,11 @@
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
-using Microsoft.Toolkit.Uwp.Helpers;
+using Microsoft.Toolkit.Uwp.Extensions;
using Windows.Devices.Bluetooth;
using Windows.Devices.Bluetooth.GenericAttributeProfile;
using Windows.Devices.Enumeration;
using Windows.System;
-using Windows.UI.Core;
using Windows.UI.Xaml.Media.Imaging;
namespace Microsoft.Toolkit.Uwp.Connectivity
@@ -404,7 +403,7 @@ private void ObservableBluetoothLEDevice_PropertyChanged(object sender, Property
/// Throws Exception when no permission to access device
public async Task ConnectAsync()
{
- await DispatcherQueue.ExecuteOnUIThreadAsync(
+ await DispatcherQueue.EnqueueAsync(
async () =>
{
if (BluetoothLEDevice == null)
@@ -478,7 +477,7 @@ public async Task DoInAppPairingAsync()
/// The task of the update.
public async Task UpdateAsync(DeviceInformationUpdate deviceUpdate)
{
- await DispatcherQueue.ExecuteOnUIThreadAsync(
+ await DispatcherQueue.EnqueueAsync(
() =>
{
DeviceInfo.Update(deviceUpdate);
@@ -521,7 +520,7 @@ protected virtual void OnPropertyChanged([CallerMemberName] string propertyName
/// The arguments.
private async void BluetoothLEDevice_NameChanged(BluetoothLEDevice sender, object args)
{
- await DispatcherQueue.ExecuteOnUIThreadAsync(() => { Name = BluetoothLEDevice.Name; }, DispatcherQueuePriority.Normal);
+ await DispatcherQueue.EnqueueAsync(() => { Name = BluetoothLEDevice.Name; }, DispatcherQueuePriority.Normal);
}
///
@@ -531,7 +530,7 @@ private async void BluetoothLEDevice_NameChanged(BluetoothLEDevice sender, objec
/// The arguments.
private async void BluetoothLEDevice_ConnectionStatusChanged(BluetoothLEDevice sender, object args)
{
- await DispatcherQueue.ExecuteOnUIThreadAsync(
+ await DispatcherQueue.EnqueueAsync(
() =>
{
IsPaired = DeviceInfo.Pairing.IsPaired;
@@ -544,7 +543,7 @@ await DispatcherQueue.ExecuteOnUIThreadAsync(
///
private async void LoadGlyph()
{
- await DispatcherQueue.ExecuteOnUIThreadAsync(
+ await DispatcherQueue.EnqueueAsync(
async () =>
{
var deviceThumbnail = await DeviceInfo.GetGlyphThumbnailAsync();
diff --git a/Microsoft.Toolkit.Uwp.Connectivity/BluetoothLEHelper/ObservableGattCharacteristics.cs b/Microsoft.Toolkit.Uwp.Connectivity/BluetoothLEHelper/ObservableGattCharacteristics.cs
index c1ab661c904..e00b722967b 100644
--- a/Microsoft.Toolkit.Uwp.Connectivity/BluetoothLEHelper/ObservableGattCharacteristics.cs
+++ b/Microsoft.Toolkit.Uwp.Connectivity/BluetoothLEHelper/ObservableGattCharacteristics.cs
@@ -7,7 +7,7 @@
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
-using Microsoft.Toolkit.Uwp.Helpers;
+using Microsoft.Toolkit.Uwp.Extensions;
using Windows.Devices.Bluetooth;
using Windows.Devices.Bluetooth.GenericAttributeProfile;
using Windows.Security.Cryptography;
@@ -469,7 +469,7 @@ protected virtual void OnPropertyChanged([CallerMemberName] string propertyName
/// The instance containing the event data.
private async void Characteristic_ValueChanged(GattCharacteristic sender, GattValueChangedEventArgs args)
{
- await DispatcherQueue.ExecuteOnUIThreadAsync(() => { SetValue(args.CharacteristicValue); }, DispatcherQueuePriority.Normal);
+ await DispatcherQueue.EnqueueAsync(() => { SetValue(args.CharacteristicValue); }, DispatcherQueuePriority.Normal);
}
///
diff --git a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/DispatcherQueueHelper/DispatcherQueueHelperPage.xaml.cs b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/DispatcherQueueHelper/DispatcherQueueHelperPage.xaml.cs
index 7b39cccf51a..fe61f6ea479 100644
--- a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/DispatcherQueueHelper/DispatcherQueueHelperPage.xaml.cs
+++ b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/DispatcherQueueHelper/DispatcherQueueHelperPage.xaml.cs
@@ -6,6 +6,7 @@
using Microsoft.Toolkit.Uwp.Helpers;
using Windows.System;
using Windows.UI.Xaml;
+using Microsoft.Toolkit.Uwp.Extensions;
namespace Microsoft.Toolkit.Uwp.SampleApp.SamplePages
{
@@ -21,7 +22,7 @@ private async void ExecuteFromDifferentThreadButton_Click(object sender, RoutedE
var dispatcherQueue = DispatcherQueue.GetForCurrentThread();
int crossThreadReturnedValue = await Task.Run(async () =>
{
- int returnedFromUIThread = await dispatcherQueue.ExecuteOnUIThreadAsync(() =>
+ int returnedFromUIThread = await dispatcherQueue.EnqueueAsync(() =>
{
NormalTextBlock.Text = "Updated from a random thread!";
return 1;
diff --git a/Microsoft.Toolkit.Uwp.UI/Cache/ImageCache.cs b/Microsoft.Toolkit.Uwp.UI/Cache/ImageCache.cs
index ece261b30b7..aef8f6f6a9a 100644
--- a/Microsoft.Toolkit.Uwp.UI/Cache/ImageCache.cs
+++ b/Microsoft.Toolkit.Uwp.UI/Cache/ImageCache.cs
@@ -7,9 +7,8 @@
using System.IO;
using System.Reflection;
using System.Threading.Tasks;
-using Microsoft.Toolkit.Uwp.Helpers;
+using Microsoft.Toolkit.Uwp.Extensions;
using Windows.Storage;
-using Windows.Storage.Streams;
using Windows.System;
using Windows.UI.Xaml.Media.Imaging;
@@ -63,7 +62,7 @@ protected override async Task InitializeTypeAsync(Stream stream, Li
throw new FileNotFoundException();
}
- return await DispatcherQueue.ExecuteOnUIThreadAsync(async () =>
+ return await DispatcherQueue.EnqueueAsync(async () =>
{
BitmapImage image = new BitmapImage();
diff --git a/Microsoft.Toolkit.Uwp.UI/Extensions/ScrollViewer/ScrollViewerExtensions.MiddleClickScrolling.cs b/Microsoft.Toolkit.Uwp.UI/Extensions/ScrollViewer/ScrollViewerExtensions.MiddleClickScrolling.cs
index 9b956d7510a..28bd87d9841 100644
--- a/Microsoft.Toolkit.Uwp.UI/Extensions/ScrollViewer/ScrollViewerExtensions.MiddleClickScrolling.cs
+++ b/Microsoft.Toolkit.Uwp.UI/Extensions/ScrollViewer/ScrollViewerExtensions.MiddleClickScrolling.cs
@@ -4,7 +4,7 @@
using System;
using System.Threading;
-using Microsoft.Toolkit.Uwp.Helpers;
+using Microsoft.Toolkit.Uwp.Extensions;
using Windows.Devices.Input;
using Windows.Foundation;
using Windows.System;
@@ -369,7 +369,7 @@ private static bool IsCursorResourceAvailable()
private static async void RunInUIThread(DispatcherQueue dispatcherQueue, Action action)
{
- await dispatcherQueue.ExecuteOnUIThreadAsync(action, DispatcherQueuePriority.Normal);
+ await dispatcherQueue.EnqueueAsync(action, DispatcherQueuePriority.Normal);
}
}
}
diff --git a/Microsoft.Toolkit.Uwp.UI/Helpers/ThemeListener.cs b/Microsoft.Toolkit.Uwp.UI/Helpers/ThemeListener.cs
index 9dc2559d506..ab727617720 100644
--- a/Microsoft.Toolkit.Uwp.UI/Helpers/ThemeListener.cs
+++ b/Microsoft.Toolkit.Uwp.UI/Helpers/ThemeListener.cs
@@ -3,10 +3,9 @@
// See the LICENSE file in the project root for more information.
using System;
-using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
-using Microsoft.Toolkit.Uwp.Helpers;
+using Microsoft.Toolkit.Uwp.Extensions;
using Windows.Foundation.Metadata;
using Windows.System;
using Windows.UI.ViewManagement;
@@ -84,7 +83,7 @@ public ThemeListener(DispatcherQueue dispatcherQueue = null)
private void Accessible_HighContrastChanged(AccessibilitySettings sender, object args)
{
#if DEBUG
- Debug.WriteLine("HighContrast Changed");
+ System.Diagnostics.Debug.WriteLine("HighContrast Changed");
#endif
UpdateProperties();
@@ -100,7 +99,7 @@ private async void Settings_ColorValuesChanged(UISettings sender, object args)
internal Task OnColorValuesChanged()
{
// Getting called off thread, so we need to dispatch to request value.
- return DispatcherQueue.ExecuteOnUIThreadAsync(
+ return DispatcherQueue.EnqueueAsync(
() =>
{
// TODO: This doesn't stop the multiple calls if we're in our faked 'White' HighContrast Mode below.
@@ -108,7 +107,7 @@ internal Task OnColorValuesChanged()
IsHighContrast != _accessible.HighContrast)
{
#if DEBUG
- Debug.WriteLine("Color Values Changed");
+ System.Diagnostics.Debug.WriteLine("Color Values Changed");
#endif
UpdateProperties();
@@ -122,7 +121,7 @@ private void CoreWindow_Activated(Windows.UI.Core.CoreWindow sender, Windows.UI.
IsHighContrast != _accessible.HighContrast)
{
#if DEBUG
- Debug.WriteLine("CoreWindow Activated Changed");
+ System.Diagnostics.Debug.WriteLine("CoreWindow Activated Changed");
#endif
UpdateProperties();
diff --git a/Microsoft.Toolkit.Uwp/Deferred/EventDeferral.cs b/Microsoft.Toolkit.Uwp/Deferred/EventDeferral.cs
index b481c2854a7..6c9cb076603 100644
--- a/Microsoft.Toolkit.Uwp/Deferred/EventDeferral.cs
+++ b/Microsoft.Toolkit.Uwp/Deferred/EventDeferral.cs
@@ -3,8 +3,6 @@
// See the LICENSE file in the project root for more information.
using System;
-using System.Collections.Generic;
-using System.Text;
using System.Threading;
using System.Threading.Tasks;
diff --git a/Microsoft.Toolkit.Uwp/Extensions/DispatcherQueueExtensions.cs b/Microsoft.Toolkit.Uwp/Extensions/DispatcherQueueExtensions.cs
new file mode 100644
index 00000000000..29bfbdad8ac
--- /dev/null
+++ b/Microsoft.Toolkit.Uwp/Extensions/DispatcherQueueExtensions.cs
@@ -0,0 +1,257 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Threading.Tasks;
+using Windows.Foundation.Metadata;
+using Windows.System;
+
+#nullable enable
+
+namespace Microsoft.Toolkit.Uwp.Extensions
+{
+ ///
+ /// Helpers for executing code in a .
+ ///
+ public static class DispatcherQueueExtensions
+ {
+ ///
+ /// Indicates whether or not is available.
+ ///
+ private static readonly bool IsHasThreadAccessPropertyAvailable = ApiInformation.IsMethodPresent("Windows.System.DispatcherQueue", "HasThreadAccess");
+
+ ///
+ /// Invokes a given function on the target and returns a
+ /// that completes when the invocation of the function is completed.
+ ///
+ /// The target to invoke the code on.
+ /// The to invoke.
+ /// The priority level for the function to invoke.
+ /// A that completes when the invocation of is over.
+ /// If the current thread has access to , will be invoked directly.
+ public static Task EnqueueAsync(this DispatcherQueue dispatcher, Action function, DispatcherQueuePriority priority = DispatcherQueuePriority.Normal)
+ {
+ // Run the function directly when we have thread access.
+ // Also reuse Task.CompletedTask in case of success,
+ // to skip an unnecessary heap allocation for every invocation.
+ if (IsHasThreadAccessPropertyAvailable && dispatcher.HasThreadAccess)
+ {
+ try
+ {
+ function();
+
+ return Task.CompletedTask;
+ }
+ catch (Exception e)
+ {
+ return Task.FromException(e);
+ }
+ }
+
+ static Task TryEnqueueAsync(DispatcherQueue dispatcher, Action function, DispatcherQueuePriority priority)
+ {
+ var taskCompletionSource = new TaskCompletionSource