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(); + + if (!dispatcher.TryEnqueue(priority, () => + { + try + { + function(); + + taskCompletionSource.SetResult(null); + } + catch (Exception e) + { + taskCompletionSource.SetException(e); + } + })) + { + taskCompletionSource.SetException(new InvalidOperationException("Failed to enqueue the operation")); + } + + return taskCompletionSource.Task; + } + + return TryEnqueueAsync(dispatcher, function, priority); + } + + /// + /// Invokes a given function on the target and returns a + /// that completes when the invocation of the function is completed. + /// + /// The return type of to relay through the returned . + /// 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, Func function, DispatcherQueuePriority priority = DispatcherQueuePriority.Normal) + { + if (IsHasThreadAccessPropertyAvailable && dispatcher.HasThreadAccess) + { + try + { + return Task.FromResult(function()); + } + catch (Exception e) + { + return Task.FromException(e); + } + } + + static Task TryEnqueueAsync(DispatcherQueue dispatcher, Func function, DispatcherQueuePriority priority) + { + var taskCompletionSource = new TaskCompletionSource(); + + if (!dispatcher.TryEnqueue(priority, () => + { + try + { + taskCompletionSource.SetResult(function()); + } + catch (Exception e) + { + taskCompletionSource.SetException(e); + } + })) + { + taskCompletionSource.SetException(new InvalidOperationException("Failed to enqueue the operation")); + } + + return taskCompletionSource.Task; + } + + return TryEnqueueAsync(dispatcher, function, priority); + } + + /// + /// Invokes a given function on the target and returns a + /// that acts as a proxy for the one returned by the given function. + /// + /// The target to invoke the code on. + /// The to invoke. + /// The priority level for the function to invoke. + /// A that acts as a proxy for the one returned by . + /// If the current thread has access to , will be invoked directly. + public static Task EnqueueAsync(this DispatcherQueue dispatcher, Func function, DispatcherQueuePriority priority = DispatcherQueuePriority.Normal) + { + // If we have thread access, we can retrieve the task directly. + // We don't use ConfigureAwait(false) in this case, in order + // to let the caller continue its execution on the same thread + // after awaiting the task returned by this function. + if (IsHasThreadAccessPropertyAvailable && dispatcher.HasThreadAccess) + { + try + { + if (function() is Task awaitableResult) + { + return awaitableResult; + } + + return Task.FromException(new InvalidOperationException("The Task returned by function cannot be null.")); + } + catch (Exception e) + { + return Task.FromException(e); + } + } + + static Task TryEnqueueAsync(DispatcherQueue dispatcher, Func function, DispatcherQueuePriority priority) + { + var taskCompletionSource = new TaskCompletionSource(); + + if (!dispatcher.TryEnqueue(priority, async () => + { + try + { + if (function() is Task awaitableResult) + { + await awaitableResult.ConfigureAwait(false); + + taskCompletionSource.SetResult(null); + } + else + { + taskCompletionSource.SetException(new InvalidOperationException("The Task returned by function cannot be null.")); + } + } + catch (Exception e) + { + taskCompletionSource.SetException(e); + } + })) + { + taskCompletionSource.SetException(new InvalidOperationException("Failed to enqueue the operation")); + } + + return taskCompletionSource.Task; + } + + return TryEnqueueAsync(dispatcher, function, priority); + } + + /// + /// Invokes a given function on the target and returns a + /// that acts as a proxy for the one returned by the given function. + /// + /// The return type of to relay through the returned . + /// The target to invoke the code on. + /// The to invoke. + /// The priority level for the function to invoke. + /// A that relays the one returned by . + /// If the current thread has access to , will be invoked directly. + public static Task EnqueueAsync(this DispatcherQueue dispatcher, Func> function, DispatcherQueuePriority priority = DispatcherQueuePriority.Normal) + { + if (IsHasThreadAccessPropertyAvailable && dispatcher.HasThreadAccess) + { + try + { + if (function() is Task awaitableResult) + { + return awaitableResult; + } + + return Task.FromException(new InvalidOperationException("The Task returned by function cannot be null.")); + } + catch (Exception e) + { + return Task.FromException(e); + } + } + + static Task TryEnqueueAsync(DispatcherQueue dispatcher, Func> function, DispatcherQueuePriority priority) + { + var taskCompletionSource = new TaskCompletionSource(); + + if (!dispatcher.TryEnqueue(priority, async () => + { + try + { + if (function() is Task awaitableResult) + { + var result = await awaitableResult.ConfigureAwait(false); + + taskCompletionSource.SetResult(result); + } + else + { + taskCompletionSource.SetException(new InvalidOperationException("The Task returned by function cannot be null.")); + } + } + catch (Exception e) + { + taskCompletionSource.SetException(e); + } + })) + { + taskCompletionSource.SetException(new InvalidOperationException("Failed to enqueue the operation")); + } + + return taskCompletionSource.Task; + } + + return TryEnqueueAsync(dispatcher, function, priority); + } + } +} diff --git a/Microsoft.Toolkit.Uwp/Extensions/StringExtensions.cs b/Microsoft.Toolkit.Uwp/Extensions/StringExtensions.cs index 8d97fe8b1fd..b19a592048c 100644 --- a/Microsoft.Toolkit.Uwp/Extensions/StringExtensions.cs +++ b/Microsoft.Toolkit.Uwp/Extensions/StringExtensions.cs @@ -4,7 +4,6 @@ using Windows.ApplicationModel.Resources; using Windows.UI; -using Windows.UI.WindowManagement; using Windows.UI.Xaml; namespace Microsoft.Toolkit.Uwp.Extensions diff --git a/Microsoft.Toolkit.Uwp/Helpers/DeepLinkParser/CollectionFormingDeepLinkParser.cs b/Microsoft.Toolkit.Uwp/Helpers/DeepLinkParser/CollectionFormingDeepLinkParser.cs index 8cf3acedd70..6e8426fed7e 100644 --- a/Microsoft.Toolkit.Uwp/Helpers/DeepLinkParser/CollectionFormingDeepLinkParser.cs +++ b/Microsoft.Toolkit.Uwp/Helpers/DeepLinkParser/CollectionFormingDeepLinkParser.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System; -using System.Collections.Generic; using System.Linq; using Windows.ApplicationModel.Activation; diff --git a/Microsoft.Toolkit.Uwp/Helpers/DispatcherHelper.cs b/Microsoft.Toolkit.Uwp/Helpers/DispatcherHelper.cs index c226d512edb..217b1edc836 100644 --- a/Microsoft.Toolkit.Uwp/Helpers/DispatcherHelper.cs +++ b/Microsoft.Toolkit.Uwp/Helpers/DispatcherHelper.cs @@ -12,7 +12,7 @@ namespace Microsoft.Toolkit.Uwp.Helpers /// /// This class provides static methods helper for executing code in UI thread of the main window. /// - [Obsolete] + [Obsolete("Replace calls to APIs in this class with extensions for the Windows.System.DispatcherQueue type (see https://docs.microsoft.com/uwp/api/windows.system.dispatcherqueue).")] public static class DispatcherHelper { /// @@ -22,6 +22,7 @@ public static class DispatcherHelper /// Dispatcher execution priority, default is normal. /// An awaitable for the operation. /// If the current thread has UI access, will be invoked directly. + [Obsolete("This method should be replaced with dispatcherQueue.EnqueueAsync(function, priority), where dispatcherQueue is a DispatcherQueue instance that was retrieved from the UI thread and stored for later use.")] public static Task ExecuteOnUIThreadAsync(Action function, CoreDispatcherPriority priority = CoreDispatcherPriority.Normal) { return ExecuteOnUIThreadAsync(CoreApplication.MainView, function, priority); @@ -35,6 +36,7 @@ public static Task ExecuteOnUIThreadAsync(Action function, CoreDispatcherPriorit /// Dispatcher execution priority, default is normal. /// An awaitable for the operation. /// If the current thread has UI access, will be invoked directly. + [Obsolete("This method should be replaced with dispatcherQueue.EnqueueAsync(function, priority), where dispatcherQueue is a DispatcherQueue instance that was retrieved from the UI thread and stored for later use.")] public static Task ExecuteOnUIThreadAsync(Func function, CoreDispatcherPriority priority = CoreDispatcherPriority.Normal) { return ExecuteOnUIThreadAsync(CoreApplication.MainView, function, priority); @@ -47,6 +49,7 @@ public static Task ExecuteOnUIThreadAsync(Func function, CoreDispatcher /// Asynchronous function to be executed asynchronously on UI thread. /// Dispatcher execution priority, default is normal. /// An awaitable for the operation. + [Obsolete("This method should be replaced with dispatcherQueue.EnqueueAsync(function, priority), where dispatcherQueue is a DispatcherQueue instance that was retrieved from the UI thread and stored for later use.")] public static Task ExecuteOnUIThreadAsync(Func function, CoreDispatcherPriority priority = CoreDispatcherPriority.Normal) { return ExecuteOnUIThreadAsync(CoreApplication.MainView, function, priority); @@ -60,6 +63,7 @@ public static Task ExecuteOnUIThreadAsync(Func function, CoreDispatcherPri /// Asynchronous function to be executed asynchronously on UI thread. /// Dispatcher execution priority, default is normal. /// An awaitable for the operation. + [Obsolete("This method should be replaced with dispatcherQueue.EnqueueAsync(function, priority), where dispatcherQueue is a DispatcherQueue instance that was retrieved from the UI thread and stored for later use.")] public static Task ExecuteOnUIThreadAsync(Func> function, CoreDispatcherPriority priority = CoreDispatcherPriority.Normal) { return ExecuteOnUIThreadAsync(CoreApplication.MainView, function, priority); @@ -73,6 +77,7 @@ public static Task ExecuteOnUIThreadAsync(Func> function, CoreDisp /// Dispatcher execution priority, default is normal /// An awaitable for the operation. /// If the current thread has UI access, will be invoked directly. + [Obsolete("This method should be replaced with viewToExecuteOn.DispatcherQueue.EnqueueAsync(function, priority).")] public static Task ExecuteOnUIThreadAsync(this CoreApplicationView viewToExecuteOn, Action function, CoreDispatcherPriority priority = CoreDispatcherPriority.Normal) { if (viewToExecuteOn is null) @@ -92,6 +97,7 @@ public static Task ExecuteOnUIThreadAsync(this CoreApplicationView viewToExecute /// Dispatcher execution priority, default is normal. /// An awaitable for the operation. /// If the current thread has UI access, will be invoked directly. + [Obsolete("This method should be replaced with viewToExecuteOn.DispatcherQueue.EnqueueAsync(function, priority).")] public static Task ExecuteOnUIThreadAsync(this CoreApplicationView viewToExecuteOn, Func function, CoreDispatcherPriority priority = CoreDispatcherPriority.Normal) { if (viewToExecuteOn is null) @@ -110,6 +116,7 @@ public static Task ExecuteOnUIThreadAsync(this CoreApplicationView viewToE /// Dispatcher execution priority, default is normal. /// An awaitable for the operation. /// If the current thread has UI access, will be invoked directly. + [Obsolete("This method should be replaced with viewToExecuteOn.DispatcherQueue.EnqueueAsync(function, priority).")] public static Task ExecuteOnUIThreadAsync(this CoreApplicationView viewToExecuteOn, Func function, CoreDispatcherPriority priority = CoreDispatcherPriority.Normal) { if (viewToExecuteOn is null) @@ -129,6 +136,7 @@ public static Task ExecuteOnUIThreadAsync(this CoreApplicationView viewToExecute /// Dispatcher execution priority, default is normal. /// An awaitable for the operation. /// If the current thread has UI access, will be invoked directly. + [Obsolete("This method should be replaced with viewToExecuteOn.DispatcherQueue.EnqueueAsync(function, priority).")] public static Task ExecuteOnUIThreadAsync(this CoreApplicationView viewToExecuteOn, Func> function, CoreDispatcherPriority priority = CoreDispatcherPriority.Normal) { if (viewToExecuteOn is null) @@ -147,6 +155,7 @@ public static Task ExecuteOnUIThreadAsync(this CoreApplicationView viewToE /// Dispatcher execution priority, default is normal. /// An awaitable for the operation. /// If the current thread has UI access, will be invoked directly. + [Obsolete("This method should be replaced with dispatcherQueue.EnqueueAsync(function, priority). A queue can be retrieved with DispatcherQueue.GetForCurrentThread().")] public static Task AwaitableRunAsync(this CoreDispatcher dispatcher, Action function, CoreDispatcherPriority priority = CoreDispatcherPriority.Normal) { if (function is null) @@ -199,6 +208,7 @@ public static Task AwaitableRunAsync(this CoreDispatcher dispatcher, Action func /// Dispatcher execution priority, default is normal. /// An awaitable for the operation. /// If the current thread has UI access, will be invoked directly. + [Obsolete("This method should be replaced with dispatcherQueue.EnqueueAsync(function, priority). A queue can be retrieved with DispatcherQueue.GetForCurrentThread().")] public static Task AwaitableRunAsync(this CoreDispatcher dispatcher, Func function, CoreDispatcherPriority priority = CoreDispatcherPriority.Normal) { if (function is null) @@ -244,6 +254,7 @@ public static Task AwaitableRunAsync(this CoreDispatcher dispatcher, Func< /// Dispatcher execution priority, default is normal. /// An awaitable for the operation. /// If the current thread has UI access, will be invoked directly. + [Obsolete("This method should be replaced with dispatcherQueue.EnqueueAsync(function, priority). A queue can be retrieved with DispatcherQueue.GetForCurrentThread().")] public static Task AwaitableRunAsync(this CoreDispatcher dispatcher, Func function, CoreDispatcherPriority priority = CoreDispatcherPriority.Normal) { if (function is null) @@ -307,6 +318,7 @@ public static Task AwaitableRunAsync(this CoreDispatcher dispatcher, Func /// Dispatcher execution priority, default is normal. /// An awaitable for the operation. /// If the current thread has UI access, will be invoked directly. + [Obsolete("This method should be replaced with dispatcherQueue.EnqueueAsync(function, priority). A queue can be retrieved with DispatcherQueue.GetForCurrentThread().")] public static Task AwaitableRunAsync(this CoreDispatcher dispatcher, Func> function, CoreDispatcherPriority priority = CoreDispatcherPriority.Normal) { if (function is null) diff --git a/Microsoft.Toolkit.Uwp/Helpers/DispatcherQueueHelper.cs b/Microsoft.Toolkit.Uwp/Helpers/DispatcherQueueHelper.cs deleted file mode 100644 index e752e17895a..00000000000 --- a/Microsoft.Toolkit.Uwp/Helpers/DispatcherQueueHelper.cs +++ /dev/null @@ -1,239 +0,0 @@ -// 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; - -namespace Microsoft.Toolkit.Uwp.Helpers -{ - /// - /// This class provides static methods helper for executing code in a DispatcherQueue. - /// - public static class DispatcherQueueHelper - { - /// - /// Extension method for . Offering an actual awaitable with optional result that will be executed on the given dispatcher. - /// - /// DispatcherQueue of a thread to run . - /// Function to be executed on the given dispatcher. - /// DispatcherQueue execution priority, default is normal. - /// An awaitable for the operation. - /// If the current thread has UI access, will be invoked directly. - public static Task ExecuteOnUIThreadAsync(this DispatcherQueue dispatcher, Action function, DispatcherQueuePriority priority = DispatcherQueuePriority.Normal) - { - if (function is null) - { - throw new ArgumentNullException(nameof(function)); - } - - /* 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 (HasThreadAccess(dispatcher)) - { - try - { - function(); - - return Task.CompletedTask; - } - catch (Exception e) - { - return Task.FromException(e); - } - } - - var taskCompletionSource = new TaskCompletionSource(); - - _ = dispatcher.TryEnqueue(priority, () => - { - try - { - function(); - - taskCompletionSource.SetResult(null); - } - catch (Exception e) - { - taskCompletionSource.SetException(e); - } - }); - - return taskCompletionSource.Task; - } - - /// - /// Extension method for . Offering an actual awaitable with optional result that will be executed on the given dispatcher. - /// - /// Returned data type of the function. - /// DispatcherQueue of a thread to run . - /// Function to be executed on the given dispatcher. - /// DispatcherQueue execution priority, default is normal. - /// An awaitable for the operation. - /// If the current thread has UI access, will be invoked directly. - public static Task ExecuteOnUIThreadAsync(this DispatcherQueue dispatcher, Func function, DispatcherQueuePriority priority = DispatcherQueuePriority.Normal) - { - if (function is null) - { - throw new ArgumentNullException(nameof(function)); - } - - if (HasThreadAccess(dispatcher)) - { - try - { - return Task.FromResult(function()); - } - catch (Exception e) - { - return Task.FromException(e); - } - } - - var taskCompletionSource = new TaskCompletionSource(); - - _ = dispatcher.TryEnqueue(priority, () => - { - try - { - taskCompletionSource.SetResult(function()); - } - catch (Exception e) - { - taskCompletionSource.SetException(e); - } - }); - - return taskCompletionSource.Task; - } - - /// - /// Extension method for . Offering an actual awaitable with optional result that will be executed on the given dispatcher. - /// - /// DispatcherQueue of a thread to run . - /// Asynchronous function to be executed on the given dispatcher. - /// DispatcherQueue execution priority, default is normal. - /// An awaitable for the operation. - /// If the current thread has UI access, will be invoked directly. - public static Task ExecuteOnUIThreadAsync(this DispatcherQueue dispatcher, Func function, DispatcherQueuePriority priority = DispatcherQueuePriority.Normal) - { - if (function is null) - { - throw new ArgumentNullException(nameof(function)); - } - - /* If we have thread access, we can retrieve the task directly. - * We don't use ConfigureAwait(false) in this case, in order - * to let the caller continue its execution on the same thread - * after awaiting the task returned by this function. */ - if (HasThreadAccess(dispatcher)) - { - try - { - if (function() is Task awaitableResult) - { - return awaitableResult; - } - - return Task.FromException(new InvalidOperationException("The Task returned by function cannot be null.")); - } - catch (Exception e) - { - return Task.FromException(e); - } - } - - var taskCompletionSource = new TaskCompletionSource(); - - _ = dispatcher.TryEnqueue(priority, async () => - { - try - { - if (function() is Task awaitableResult) - { - await awaitableResult.ConfigureAwait(false); - - taskCompletionSource.SetResult(null); - } - else - { - taskCompletionSource.SetException(new InvalidOperationException("The Task returned by function cannot be null.")); - } - } - catch (Exception e) - { - taskCompletionSource.SetException(e); - } - }); - - return taskCompletionSource.Task; - } - - /// - /// Extension method for . Offering an actual awaitable with optional result that will be executed on the given dispatcher. - /// - /// Returned data type of the function. - /// DispatcherQueue of a thread to run . - /// Asynchronous function to be executed Asynchronously on the given dispatcher. - /// DispatcherQueue execution priority, default is normal. - /// An awaitable for the operation. - /// If the current thread has UI access, will be invoked directly. - public static Task ExecuteOnUIThreadAsync(this DispatcherQueue dispatcher, Func> function, DispatcherQueuePriority priority = DispatcherQueuePriority.Normal) - { - if (function is null) - { - throw new ArgumentNullException(nameof(function)); - } - - if (HasThreadAccess(dispatcher)) - { - try - { - if (function() is Task awaitableResult) - { - return awaitableResult; - } - - return Task.FromException(new InvalidOperationException("The Task returned by function cannot be null.")); - } - catch (Exception e) - { - return Task.FromException(e); - } - } - - var taskCompletionSource = new TaskCompletionSource(); - - _ = dispatcher.TryEnqueue(priority, async () => - { - try - { - if (function() is Task awaitableResult) - { - var result = await awaitableResult.ConfigureAwait(false); - - taskCompletionSource.SetResult(result); - } - else - { - taskCompletionSource.SetException(new InvalidOperationException("The Task returned by function cannot be null.")); - } - } - catch (Exception e) - { - taskCompletionSource.SetException(e); - } - }); - - return taskCompletionSource.Task; - } - - private static bool HasThreadAccess(DispatcherQueue dispatcher) - { - return ApiInformation.IsMethodPresent("Windows.System.DispatcherQueue", "HasThreadAccess") && dispatcher.HasThreadAccess; - } - } -} diff --git a/Microsoft.Toolkit.Uwp/Helpers/PrintHelper/PrintHelper.cs b/Microsoft.Toolkit.Uwp/Helpers/PrintHelper/PrintHelper.cs index 3e489433331..89414f089f5 100644 --- a/Microsoft.Toolkit.Uwp/Helpers/PrintHelper/PrintHelper.cs +++ b/Microsoft.Toolkit.Uwp/Helpers/PrintHelper/PrintHelper.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using Microsoft.Toolkit.Uwp.Extensions; using Windows.Graphics.Printing; using Windows.System; using Windows.UI.Xaml; @@ -205,7 +206,7 @@ public void Dispose() } _printCanvas = null; - DispatcherQueue.ExecuteOnUIThreadAsync(() => + DispatcherQueue.EnqueueAsync(() => { _printDocument.Paginate -= CreatePrintPreviewPages; _printDocument.GetPreviewPage -= GetPrintPreviewPage; @@ -229,7 +230,7 @@ private async Task DetachCanvas() { if (!_directPrint) { - await DispatcherQueue.ExecuteOnUIThreadAsync(() => + await DispatcherQueue.EnqueueAsync(() => { _canvasContainer.Children.Remove(_printCanvas); _printCanvas.Children.Clear(); @@ -262,7 +263,7 @@ private void PrintTaskRequested(PrintManager sender, PrintTaskRequestedEventArgs printTask.Completed += async (s, args) => { // Notify the user when the print operation fails. - await DispatcherQueue.ExecuteOnUIThreadAsync( + await DispatcherQueue.EnqueueAsync( async () => { foreach (var element in _stateBags.Keys) @@ -515,7 +516,7 @@ private Task AddOnePrintPreviewPage(FrameworkElement element, PrintPageDescripti element.Margin = new Thickness(marginWidth / 2, marginHeight / 2, marginWidth / 2, marginHeight / 2); page.Content = element; - return DispatcherQueue.ExecuteOnUIThreadAsync( + return DispatcherQueue.EnqueueAsync( () => { // Add the (newly created) page to the print canvas which is part of the visual tree and force it to go @@ -531,7 +532,7 @@ private Task AddOnePrintPreviewPage(FrameworkElement element, PrintPageDescripti private Task ClearPageCache() { - return DispatcherQueue.ExecuteOnUIThreadAsync(() => + return DispatcherQueue.EnqueueAsync(() => { if (!_directPrint) { diff --git a/Microsoft.Toolkit.Uwp/Helpers/PrintHelper/PrintHelperStateBag.cs b/Microsoft.Toolkit.Uwp/Helpers/PrintHelper/PrintHelperStateBag.cs index 7be4a651451..9c9b96d83e4 100644 --- a/Microsoft.Toolkit.Uwp/Helpers/PrintHelper/PrintHelperStateBag.cs +++ b/Microsoft.Toolkit.Uwp/Helpers/PrintHelper/PrintHelperStateBag.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using Microsoft.Toolkit.Uwp.Extensions; using Windows.System; using Windows.UI.Xaml; @@ -63,7 +64,7 @@ public void Capture(FrameworkElement element) /// Element to restore state to public void Restore(FrameworkElement element) { - _dispatcherQueue.ExecuteOnUIThreadAsync(() => + _dispatcherQueue.EnqueueAsync(() => { element.HorizontalAlignment = HorizontalAlignment; element.VerticalAlignment = VerticalAlignment; diff --git a/Microsoft.Toolkit.Uwp/Helpers/RemoteDeviceHelper/RemoteDeviceHelper.cs b/Microsoft.Toolkit.Uwp/Helpers/RemoteDeviceHelper/RemoteDeviceHelper.cs index 842176428c4..65635422234 100644 --- a/Microsoft.Toolkit.Uwp/Helpers/RemoteDeviceHelper/RemoteDeviceHelper.cs +++ b/Microsoft.Toolkit.Uwp/Helpers/RemoteDeviceHelper/RemoteDeviceHelper.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; +using Microsoft.Toolkit.Uwp.Extensions; using Windows.System; using Windows.System.RemoteSystems; @@ -84,7 +85,7 @@ private void RemoteSystemWatcher_EnumerationCompleted(RemoteSystemWatcher sender private async void RemoteSystemWatcher_RemoteSystemUpdated(RemoteSystemWatcher sender, RemoteSystemUpdatedEventArgs args) { - await DispatcherQueue.ExecuteOnUIThreadAsync(() => + await DispatcherQueue.EnqueueAsync(() => { RemoteSystems.Remove(RemoteSystems.First(a => a.Id == args.RemoteSystem.Id)); RemoteSystems.Add(args.RemoteSystem); @@ -93,7 +94,7 @@ await DispatcherQueue.ExecuteOnUIThreadAsync(() => private async void RemoteSystemWatcher_RemoteSystemRemoved(RemoteSystemWatcher sender, RemoteSystemRemovedEventArgs args) { - await DispatcherQueue.ExecuteOnUIThreadAsync(() => + await DispatcherQueue.EnqueueAsync(() => { RemoteSystems.Remove(RemoteSystems.First(a => a.Id == args.RemoteSystemId)); }); @@ -101,7 +102,7 @@ await DispatcherQueue.ExecuteOnUIThreadAsync(() => private async void RemoteSystemWatcher_RemoteSystemAdded(RemoteSystemWatcher sender, RemoteSystemAddedEventArgs args) { - await DispatcherQueue.ExecuteOnUIThreadAsync(() => + await DispatcherQueue.EnqueueAsync(() => { RemoteSystems.Add(args.RemoteSystem); }); diff --git a/Microsoft.Toolkit.Uwp/Microsoft.Toolkit.Uwp.csproj b/Microsoft.Toolkit.Uwp/Microsoft.Toolkit.Uwp.csproj index 07ef6adb800..9ba9b97cd85 100644 --- a/Microsoft.Toolkit.Uwp/Microsoft.Toolkit.Uwp.csproj +++ b/Microsoft.Toolkit.Uwp/Microsoft.Toolkit.Uwp.csproj @@ -5,6 +5,7 @@ Windows Community Toolkit This package includes code only helpers such as Colors conversion tool, Storage file handling, a Stream helper class, etc. UWP Toolkit Windows + 8.0 diff --git a/Microsoft.Toolkit.Uwp/Structures/OSVersion.cs b/Microsoft.Toolkit.Uwp/Structures/OSVersion.cs index 9d3e0e8c628..5d00d94dca3 100644 --- a/Microsoft.Toolkit.Uwp/Structures/OSVersion.cs +++ b/Microsoft.Toolkit.Uwp/Structures/OSVersion.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Windows.System.Profile; - namespace Microsoft.Toolkit.Uwp.Helpers { /// diff --git a/UnitTests/UnitTests.UWP/Helpers/Test_DispatcherQueueHelper.cs b/UnitTests/UnitTests.UWP/Extensions/Test_DispatcherQueueExtensions.cs similarity index 75% rename from UnitTests/UnitTests.UWP/Helpers/Test_DispatcherQueueHelper.cs rename to UnitTests/UnitTests.UWP/Extensions/Test_DispatcherQueueExtensions.cs index ba81bb1afc6..a032b0b78bf 100644 --- a/UnitTests/UnitTests.UWP/Helpers/Test_DispatcherQueueHelper.cs +++ b/UnitTests/UnitTests.UWP/Extensions/Test_DispatcherQueueExtensions.cs @@ -3,38 +3,37 @@ // See the LICENSE file in the project root for more information. using System; -using System.Diagnostics.CodeAnalysis; using Microsoft.VisualStudio.TestTools.UnitTesting; using Microsoft.VisualStudio.TestTools.UnitTesting.AppContainer; using System.Linq; using System.Threading.Tasks; using Windows.UI.Xaml.Controls; -using Microsoft.Toolkit.Uwp.Helpers; using Windows.ApplicationModel.Core; using Windows.UI.Core; using Windows.System; +using Microsoft.Toolkit.Uwp.Extensions; -namespace UnitTests.Helpers +namespace UnitTests.Extensions { [TestClass] [Ignore("Ignored until issue on .Net Native is fixed. These are working.")] - public class Test_DispatcherQueueHelper + public class Test_DispatcherQueueExtensions { private const int TIME_OUT = 5000; - [TestCategory("Helpers")] + [TestCategory("DispatcherQueueExtensions")] [UITestMethod] - [ExpectedException(typeof(ArgumentNullException))] + [ExpectedException(typeof(NullReferenceException))] public void Test_DispatcherQueueHelper_Action_Null() { - DispatcherQueueHelper.ExecuteOnUIThreadAsync(DispatcherQueue.GetForCurrentThread(), default(Action)); + DispatcherQueue.GetForCurrentThread().EnqueueAsync(default(Action)!); } - [TestCategory("Helpers")] + [TestCategory("DispatcherQueueExtensions")] [UITestMethod] public void Test_DispatcherQueueHelper_Action_Ok_UIThread() { - DispatcherQueueHelper.ExecuteOnUIThreadAsync(DispatcherQueue.GetForCurrentThread(), () => + DispatcherQueue.GetForCurrentThread().EnqueueAsync(() => { var textBlock = new TextBlock { Text = nameof(Test_DispatcherQueueHelper_Action_Ok_UIThread) }; @@ -42,7 +41,7 @@ public void Test_DispatcherQueueHelper_Action_Ok_UIThread() }).Wait(); } - [TestCategory("Helpers")] + [TestCategory("DispatcherQueueExtensions")] [TestMethod] public async Task Test_DispatcherQueueHelper_Action_Ok_NonUIThread() { @@ -55,7 +54,7 @@ await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync( var dispatcherQueue = DispatcherQueue.GetForCurrentThread(); await Task.Run(async () => { - await DispatcherQueueHelper.ExecuteOnUIThreadAsync(dispatcherQueue, () => + await dispatcherQueue.EnqueueAsync(() => { var textBlock = new TextBlock { Text = nameof(Test_DispatcherQueueHelper_Action_Ok_NonUIThread) }; @@ -73,11 +72,11 @@ await DispatcherQueueHelper.ExecuteOnUIThreadAsync(dispatcherQueue, () => await taskSource.Task; } - [TestCategory("Helpers")] + [TestCategory("DispatcherQueueExtensions")] [UITestMethod] public void Test_DispatcherQueueHelper_Action_Exception() { - var task = DispatcherQueueHelper.ExecuteOnUIThreadAsync(DispatcherQueue.GetForCurrentThread(), () => + var task = DispatcherQueue.GetForCurrentThread().EnqueueAsync(() => { throw new ArgumentException(nameof(this.Test_DispatcherQueueHelper_Action_Exception)); }); @@ -88,19 +87,19 @@ public void Test_DispatcherQueueHelper_Action_Exception() Assert.IsInstanceOfType(task.Exception.InnerExceptions.FirstOrDefault(), typeof(ArgumentException)); } - [TestCategory("Helpers")] + [TestCategory("DispatcherQueueExtensions")] [UITestMethod] - [ExpectedException(typeof(ArgumentNullException))] + [ExpectedException(typeof(NullReferenceException))] public void Test_DispatcherQueueHelper_FuncOfT_Null() { - DispatcherQueueHelper.ExecuteOnUIThreadAsync(DispatcherQueue.GetForCurrentThread(), default(Func)); + DispatcherQueue.GetForCurrentThread().EnqueueAsync(default(Func)!); } - [TestCategory("Helpers")] + [TestCategory("DispatcherQueueExtensions")] [UITestMethod] public void Test_DispatcherQueueHelper_FuncOfT_Ok_UIThread() { - var textBlock = DispatcherQueueHelper.ExecuteOnUIThreadAsync(DispatcherQueue.GetForCurrentThread(), () => + var textBlock = DispatcherQueue.GetForCurrentThread().EnqueueAsync(() => { return new TextBlock { Text = nameof(Test_DispatcherQueueHelper_FuncOfT_Ok_UIThread) }; }).Result; @@ -108,7 +107,7 @@ public void Test_DispatcherQueueHelper_FuncOfT_Ok_UIThread() Assert.AreEqual(textBlock.Text, nameof(Test_DispatcherQueueHelper_FuncOfT_Ok_UIThread)); } - [TestCategory("Helpers")] + [TestCategory("DispatcherQueueExtensions")] [TestMethod] public async Task Test_DispatcherQueueHelper_FuncOfT_Ok_NonUIThread() { @@ -121,11 +120,11 @@ await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync( var dispatcherQueue = DispatcherQueue.GetForCurrentThread(); await Task.Run(async () => { - var textBlock = await DispatcherQueueHelper.ExecuteOnUIThreadAsync(dispatcherQueue, () => + var textBlock = await dispatcherQueue.EnqueueAsync(() => { return new TextBlock { Text = nameof(Test_DispatcherQueueHelper_FuncOfT_Ok_NonUIThread) }; }); - await DispatcherQueueHelper.ExecuteOnUIThreadAsync(dispatcherQueue, () => + await dispatcherQueue.EnqueueAsync(() => { Assert.AreEqual(textBlock.Text, nameof(Test_DispatcherQueueHelper_FuncOfT_Ok_NonUIThread)); taskSource.SetResult(null); @@ -140,11 +139,11 @@ await DispatcherQueueHelper.ExecuteOnUIThreadAsync(dispatcherQueue, () => await taskSource.Task; } - [TestCategory("Helpers")] + [TestCategory("DispatcherQueueExtensions")] [UITestMethod] public void Test_DispatcherQueueHelper_FuncOfT_Exception() { - var task = DispatcherQueueHelper.ExecuteOnUIThreadAsync(DispatcherQueue.GetForCurrentThread(), new Func(() => + var task = DispatcherQueue.GetForCurrentThread().EnqueueAsync(new Func(() => { throw new ArgumentException(nameof(this.Test_DispatcherQueueHelper_FuncOfT_Exception)); })); @@ -155,20 +154,19 @@ public void Test_DispatcherQueueHelper_FuncOfT_Exception() Assert.IsInstanceOfType(task.Exception.InnerExceptions.FirstOrDefault(), typeof(ArgumentException)); } - [TestCategory("Helpers")] + [TestCategory("DispatcherQueueExtensions")] [UITestMethod] - [ExpectedException(typeof(ArgumentNullException))] - [SuppressMessage("Style", "IDE0034", Justification = "Explicit overload for clarity")] + [ExpectedException(typeof(NullReferenceException))] public void Test_DispatcherQueueHelper_FuncOfTask_Null() { - DispatcherQueueHelper.ExecuteOnUIThreadAsync(DispatcherQueue.GetForCurrentThread(), default(Func)); + DispatcherQueue.GetForCurrentThread().EnqueueAsync(default(Func)!); } [TestCategory("Helpers")] [UITestMethod] public void Test_DispatcherQueueHelper_FuncOfTask_Ok_UIThread() { - DispatcherQueueHelper.ExecuteOnUIThreadAsync(DispatcherQueue.GetForCurrentThread(), () => + DispatcherQueue.GetForCurrentThread().EnqueueAsync(() => { var textBlock = new TextBlock { Text = nameof(Test_DispatcherQueueHelper_FuncOfTask_Ok_UIThread) }; @@ -178,7 +176,7 @@ public void Test_DispatcherQueueHelper_FuncOfTask_Ok_UIThread() }).Wait(); } - [TestCategory("Helpers")] + [TestCategory("DispatcherQueueExtensions")] [TestMethod] public async Task Test_DispatcherQueueHelper_FuncOfTask_Ok_NonUIThread() { @@ -188,7 +186,7 @@ await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync( { try { - await DispatcherQueueHelper.ExecuteOnUIThreadAsync(DispatcherQueue.GetForCurrentThread(), async () => + await DispatcherQueue.GetForCurrentThread().EnqueueAsync(async () => { await Task.Yield(); @@ -207,11 +205,11 @@ await DispatcherQueueHelper.ExecuteOnUIThreadAsync(DispatcherQueue.GetForCurrent await taskSource.Task; } - [TestCategory("Helpers")] + [TestCategory("DispatcherQueueExtensions")] [UITestMethod] public void Test_DispatcherQueueHelper_FuncOfTask_Exception() { - var task = DispatcherQueueHelper.ExecuteOnUIThreadAsync(DispatcherQueue.GetForCurrentThread(), new Func(() => + var task = DispatcherQueue.GetForCurrentThread().EnqueueAsync(new Func(() => { throw new ArgumentException(nameof(this.Test_DispatcherQueueHelper_FuncOfTask_Exception)); })); @@ -222,19 +220,19 @@ public void Test_DispatcherQueueHelper_FuncOfTask_Exception() Assert.IsInstanceOfType(task.Exception.InnerExceptions.FirstOrDefault(), typeof(ArgumentException)); } - [TestCategory("Helpers")] + [TestCategory("DispatcherQueueExtensions")] [UITestMethod] - [ExpectedException(typeof(ArgumentNullException))] + [ExpectedException(typeof(NullReferenceException))] public void Test_DispatcherQueueHelper_FuncOfTaskOfT_Null() { - DispatcherQueueHelper.ExecuteOnUIThreadAsync(DispatcherQueue.GetForCurrentThread(), default(Func>)); + DispatcherQueue.GetForCurrentThread().EnqueueAsync(default(Func>)!); } - [TestCategory("Helpers")] + [TestCategory("DispatcherQueueExtensions")] [UITestMethod] public void Test_DispatcherQueueHelper_FuncOfTaskOfT_Ok_UIThread() { - DispatcherQueueHelper.ExecuteOnUIThreadAsync(DispatcherQueue.GetForCurrentThread(), () => + DispatcherQueue.GetForCurrentThread().EnqueueAsync(() => { var textBlock = new TextBlock { Text = nameof(Test_DispatcherQueueHelper_FuncOfTaskOfT_Ok_UIThread) }; @@ -244,7 +242,7 @@ public void Test_DispatcherQueueHelper_FuncOfTaskOfT_Ok_UIThread() }).Wait(); } - [TestCategory("Helpers")] + [TestCategory("DispatcherQueueExtensions")] [TestMethod] public async Task Test_DispatcherQueueHelper_FuncOfTaskOfT_Ok_NonUIThread() { @@ -254,7 +252,7 @@ await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync( { try { - await DispatcherQueueHelper.ExecuteOnUIThreadAsync(DispatcherQueue.GetForCurrentThread(), async () => + await DispatcherQueue.GetForCurrentThread().EnqueueAsync(async () => { await Task.Yield(); @@ -275,11 +273,11 @@ await DispatcherQueueHelper.ExecuteOnUIThreadAsync(DispatcherQueue.GetForCurrent await taskSource.Task; } - [TestCategory("Helpers")] + [TestCategory("DispatcherQueueExtensions")] [UITestMethod] public void Test_DispatcherQueueHelper_FuncOfTaskOfT_Exception() { - var task = DispatcherQueueHelper.ExecuteOnUIThreadAsync(DispatcherQueue.GetForCurrentThread(), new Func>(() => + var task = DispatcherQueue.GetForCurrentThread().EnqueueAsync(new Func>(() => { throw new ArgumentException(nameof(this.Test_DispatcherQueueHelper_FuncOfTaskOfT_Exception)); })); diff --git a/UnitTests/UnitTests.UWP/Helpers/Test_DispatcherHelper.cs b/UnitTests/UnitTests.UWP/Helpers/Test_DispatcherHelper.cs index 94e37242419..5d0cb5e8a39 100644 --- a/UnitTests/UnitTests.UWP/Helpers/Test_DispatcherHelper.cs +++ b/UnitTests/UnitTests.UWP/Helpers/Test_DispatcherHelper.cs @@ -13,7 +13,7 @@ namespace UnitTests.Helpers { -#pragma warning disable CS0612 // Type or member is obsolete +#pragma warning disable CS0612, CS0618 // Type or member is obsolete [TestClass] public class Test_DispatcherHelper { diff --git a/UnitTests/UnitTests.UWP/UI/Controls/Test_TextToolbar_Localization.cs b/UnitTests/UnitTests.UWP/UI/Controls/Test_TextToolbar_Localization.cs index e4acdf40096..97de47cb3a9 100644 --- a/UnitTests/UnitTests.UWP/UI/Controls/Test_TextToolbar_Localization.cs +++ b/UnitTests/UnitTests.UWP/UI/Controls/Test_TextToolbar_Localization.cs @@ -16,6 +16,7 @@ using Windows.System; using Windows.UI.Xaml; using Windows.UI.Xaml.Markup; +using Microsoft.Toolkit.Uwp.Extensions; namespace UnitTests.UI.Controls { @@ -78,7 +79,7 @@ public void Test_TextToolbar_Localization_Override() [TestMethod] public async Task Test_TextToolbar_Localization_Override_Fr() { - await CoreApplication.MainView.DispatcherQueue.ExecuteOnUIThreadAsync(async () => + await CoreApplication.MainView.DispatcherQueue.EnqueueAsync(async () => { // Just double-check we've got the right environment setup in our tests. CollectionAssert.AreEquivalent(new string[] { "en-US", "fr" }, ApplicationLanguages.ManifestLanguages.ToArray(), "Missing locales for test"); diff --git a/UnitTests/UnitTests.UWP/UnitTests.UWP.csproj b/UnitTests/UnitTests.UWP/UnitTests.UWP.csproj index 2ca1eb49982..a05bbb4e8e3 100644 --- a/UnitTests/UnitTests.UWP/UnitTests.UWP.csproj +++ b/UnitTests/UnitTests.UWP/UnitTests.UWP.csproj @@ -145,7 +145,7 @@ - + diff --git a/UnitTests/UnitTests.XamlIslands.UWPApp/TestsPage.xaml.cs b/UnitTests/UnitTests.XamlIslands.UWPApp/TestsPage.xaml.cs index 34754312ce1..16f85e4a620 100644 --- a/UnitTests/UnitTests.XamlIslands.UWPApp/TestsPage.xaml.cs +++ b/UnitTests/UnitTests.XamlIslands.UWPApp/TestsPage.xaml.cs @@ -14,6 +14,7 @@ using Windows.UI.Xaml; using Windows.UI.Xaml.Documents; using Windows.UI.Xaml.Media; +using Microsoft.Toolkit.Uwp.Extensions; namespace UnitTests.XamlIslands.UWPApp { @@ -147,7 +148,7 @@ private async Task RunTestsAsync(Type type) } finally { - await App.Dispatcher.ExecuteOnUIThreadAsync(() => + await App.Dispatcher.EnqueueAsync(() => { SetMainTestContent(null); }); @@ -161,7 +162,7 @@ await App.Dispatcher.ExecuteOnUIThreadAsync(() => private Task WriteLineAsync(string message, Color? color = null, bool deleteLastLine = false) { Debug.WriteLine(message); - return App.Dispatcher.ExecuteOnUIThreadAsync(() => + return App.Dispatcher.EnqueueAsync(() => { if (deleteLastLine) { diff --git a/UnitTests/UnitTests.XamlIslands.UWPApp/XamlIslandsTest_DropShadowPanel.cs b/UnitTests/UnitTests.XamlIslands.UWPApp/XamlIslandsTest_DropShadowPanel.cs index be3a7438b71..c76796ae762 100644 --- a/UnitTests/UnitTests.XamlIslands.UWPApp/XamlIslandsTest_DropShadowPanel.cs +++ b/UnitTests/UnitTests.XamlIslands.UWPApp/XamlIslandsTest_DropShadowPanel.cs @@ -8,6 +8,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Windows.UI; using Windows.UI.Xaml.Controls; +using Microsoft.Toolkit.Uwp.Extensions; namespace UnitTests.XamlIslands.UWPApp { @@ -19,7 +20,7 @@ public partial class XamlIslandsTest_DropShadowPanel [TestInitialize] public async Task Init() { - await App.Dispatcher.ExecuteOnUIThreadAsync(() => + await App.Dispatcher.EnqueueAsync(() => { _dropShadowPanel = new DropShadowPanel { @@ -39,7 +40,7 @@ await App.Dispatcher.ExecuteOnUIThreadAsync(() => [TestMethod] public async Task DropShadowPanel_RendersFine() { - await App.Dispatcher.ExecuteOnUIThreadAsync(async () => + await App.Dispatcher.EnqueueAsync(async () => { var textBlock = new TextBlock { diff --git a/UnitTests/UnitTests.XamlIslands.UWPApp/XamlIslandsTest_Eyedropper.cs b/UnitTests/UnitTests.XamlIslands.UWPApp/XamlIslandsTest_Eyedropper.cs index aa18eaf7b3a..ef71c417ac4 100644 --- a/UnitTests/UnitTests.XamlIslands.UWPApp/XamlIslandsTest_Eyedropper.cs +++ b/UnitTests/UnitTests.XamlIslands.UWPApp/XamlIslandsTest_Eyedropper.cs @@ -9,6 +9,7 @@ using Windows.Devices.Input; using Windows.Foundation; using Windows.UI; +using Microsoft.Toolkit.Uwp.Extensions; namespace UnitTests.XamlIslands.UWPApp { @@ -20,7 +21,7 @@ public async Task Eyedropper_DoesntCrash() { Eyedropper eyedropper = null; Color? color = null; - _ = App.Dispatcher.ExecuteOnUIThreadAsync(async () => + _ = App.Dispatcher.EnqueueAsync(async () => { eyedropper = new Eyedropper { @@ -29,7 +30,7 @@ public async Task Eyedropper_DoesntCrash() color = await eyedropper.Open(); }); - await App.Dispatcher.ExecuteOnUIThreadAsync(async () => + await App.Dispatcher.EnqueueAsync(async () => { var xamlRoot = App.XamlRoot; diff --git a/UnitTests/UnitTests.XamlIslands.UWPApp/XamlIslandsTest_StringExtensions.cs b/UnitTests/UnitTests.XamlIslands.UWPApp/XamlIslandsTest_StringExtensions.cs index fd81c47a93b..d9393b8054c 100644 --- a/UnitTests/UnitTests.XamlIslands.UWPApp/XamlIslandsTest_StringExtensions.cs +++ b/UnitTests/UnitTests.XamlIslands.UWPApp/XamlIslandsTest_StringExtensions.cs @@ -22,7 +22,7 @@ public partial class XamlIslandsTest_StringExtensions [TestMethod] public async Task StringExtensions_GetViewLocalized() { - await App.Dispatcher.ExecuteOnUIThreadAsync(() => + await App.Dispatcher.EnqueueAsync(() => { var xamlRoot = App.XamlRoot; var str = StringExtensions.GetViewLocalized("abc", xamlRoot.UIContext); @@ -33,7 +33,7 @@ await App.Dispatcher.ExecuteOnUIThreadAsync(() => [TestMethod] public async Task StringExtensions_GetLocalized() { - await App.Dispatcher.ExecuteOnUIThreadAsync(() => + await App.Dispatcher.EnqueueAsync(() => { var xamlRoot = App.XamlRoot; var str = "abc".GetLocalized(xamlRoot.UIContext); @@ -55,7 +55,7 @@ public void StringExtensions_GetLocalizedWithResourcePath() [TestMethod] public async Task Test_TextToolbar_Localization_Retrieve() { - await App.Dispatcher.ExecuteOnUIThreadAsync(() => + await App.Dispatcher.EnqueueAsync(() => { var treeRoot = XamlReader.Load( @" [TestMethod] public async Task Test_TextToolbar_Localization_Override() { - await App.Dispatcher.ExecuteOnUIThreadAsync(() => + await App.Dispatcher.EnqueueAsync(() => { var commonButtons = new CommonButtons(new TextToolbar()); var italicsButton = commonButtons.Italics; @@ -109,7 +109,7 @@ await App.Dispatcher.ExecuteOnUIThreadAsync(() => [TestMethod] public async Task Test_TextToolbar_Localization_Override_Fr() { - await App.Dispatcher.ExecuteOnUIThreadAsync(async () => + await App.Dispatcher.EnqueueAsync(async () => { // Just double-check we've got the right environment setup in our tests. //// Note: This seems to fail on XAML Islands, but the rest of the test works fine...? diff --git a/UnitTests/UnitTests.XamlIslands.UWPApp/XamlIslandsTest_SystemInformation.cs b/UnitTests/UnitTests.XamlIslands.UWPApp/XamlIslandsTest_SystemInformation.cs index 668da199a41..fdab8ffafb0 100644 --- a/UnitTests/UnitTests.XamlIslands.UWPApp/XamlIslandsTest_SystemInformation.cs +++ b/UnitTests/UnitTests.XamlIslands.UWPApp/XamlIslandsTest_SystemInformation.cs @@ -6,6 +6,7 @@ using Microsoft.Toolkit.Uwp.Helpers; using Microsoft.VisualStudio.TestTools.UnitTesting; using Windows.ApplicationModel.Activation; +using Microsoft.Toolkit.Uwp.Extensions; namespace UnitTests.XamlIslands.UWPApp { @@ -15,7 +16,7 @@ public partial class XamlIslandsTest_SystemInformation [TestMethod] public async Task SystemInformationTrackAppUse() { - await App.Dispatcher.ExecuteOnUIThreadAsync(() => + await App.Dispatcher.EnqueueAsync(() => { var e = new FakeArgs { diff --git a/UnitTests/UnitTests.XamlIslands.UWPApp/XamlIslandsTest_TextToolbar.cs b/UnitTests/UnitTests.XamlIslands.UWPApp/XamlIslandsTest_TextToolbar.cs index e46d2546942..4ae1936d4d6 100644 --- a/UnitTests/UnitTests.XamlIslands.UWPApp/XamlIslandsTest_TextToolbar.cs +++ b/UnitTests/UnitTests.XamlIslands.UWPApp/XamlIslandsTest_TextToolbar.cs @@ -8,6 +8,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; +using Microsoft.Toolkit.Uwp.Extensions; namespace UnitTests.XamlIslands.UWPApp { @@ -19,7 +20,7 @@ public partial class XamlIslandsTest_TextToolbar [TestInitialize] public async Task Init() { - await App.Dispatcher.ExecuteOnUIThreadAsync(() => + await App.Dispatcher.EnqueueAsync(() => { var richEditBox = new RichEditBox { @@ -62,7 +63,7 @@ await App.Dispatcher.ExecuteOnUIThreadAsync(() => [TestMethod] public async Task TextToobar_PopupShowsInCorrectXamlRoot() { - await App.Dispatcher.ExecuteOnUIThreadAsync(async () => + await App.Dispatcher.EnqueueAsync(async () => { await Task.Delay(500); diff --git a/UnitTests/UnitTests.XamlIslands.UWPApp/XamlIslandsTest_ThemeListener_Threading.cs b/UnitTests/UnitTests.XamlIslands.UWPApp/XamlIslandsTest_ThemeListener_Threading.cs index aa3d98da9f5..766a5f95142 100644 --- a/UnitTests/UnitTests.XamlIslands.UWPApp/XamlIslandsTest_ThemeListener_Threading.cs +++ b/UnitTests/UnitTests.XamlIslands.UWPApp/XamlIslandsTest_ThemeListener_Threading.cs @@ -7,6 +7,7 @@ using Microsoft.Toolkit.Uwp.UI.Helpers; using Microsoft.VisualStudio.TestTools.UnitTesting; using Windows.UI.Xaml; +using Microsoft.Toolkit.Uwp.Extensions; namespace UnitTests.XamlIslands.UWPApp { @@ -19,7 +20,7 @@ public partial class XamlIslandsTest_ThemeListener_Threading [TestInitialize] public Task Init() { - return App.Dispatcher.ExecuteOnUIThreadAsync(() => + return App.Dispatcher.EnqueueAsync(() => { _taskCompletionSource = new TaskCompletionSource(); diff --git a/UnitTests/UnitTests.XamlIslands.UWPApp/XamlIslandsTest_TokenizingTextBox.cs b/UnitTests/UnitTests.XamlIslands.UWPApp/XamlIslandsTest_TokenizingTextBox.cs index dcb60f0f4bd..6b4b304f6f8 100644 --- a/UnitTests/UnitTests.XamlIslands.UWPApp/XamlIslandsTest_TokenizingTextBox.cs +++ b/UnitTests/UnitTests.XamlIslands.UWPApp/XamlIslandsTest_TokenizingTextBox.cs @@ -10,6 +10,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Markup; +using Microsoft.Toolkit.Uwp.Extensions; namespace UnitTests.XamlIslands.UWPApp { @@ -63,7 +64,7 @@ public override string ToString() [TestInitialize] public async Task Init() { - await App.Dispatcher.ExecuteOnUIThreadAsync(() => + await App.Dispatcher.EnqueueAsync(() => { _acv = new AdvancedCollectionView(_samples, false); @@ -110,7 +111,7 @@ await App.Dispatcher.ExecuteOnUIThreadAsync(() => [TestMethod] public async Task TokenizingTextBox_GetFocusedElement_RemoveAllSelectedTokens() { - await App.Dispatcher.ExecuteOnUIThreadAsync(async () => + await App.Dispatcher.EnqueueAsync(async () => { await Task.Delay(500); @@ -135,7 +136,7 @@ await App.Dispatcher.ExecuteOnUIThreadAsync(async () => [TestMethod] public async Task TokenizingTextBox_PopupShowsInCorrectXamlRoot() { - await App.Dispatcher.ExecuteOnUIThreadAsync(async () => + await App.Dispatcher.EnqueueAsync(async () => { await Task.Delay(500); diff --git a/UnitTests/UnitTests.XamlIslands.UWPApp/XamlIslandsTest_WrapPanel.cs b/UnitTests/UnitTests.XamlIslands.UWPApp/XamlIslandsTest_WrapPanel.cs index d6e071e69e0..fb54c623398 100644 --- a/UnitTests/UnitTests.XamlIslands.UWPApp/XamlIslandsTest_WrapPanel.cs +++ b/UnitTests/UnitTests.XamlIslands.UWPApp/XamlIslandsTest_WrapPanel.cs @@ -9,6 +9,7 @@ using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Markup; +using Microsoft.Toolkit.Uwp.Extensions; namespace UnitTests.XamlIslands.UWPApp { @@ -20,7 +21,7 @@ public partial class XamlIslandsTest_WrapPanel [TestInitialize] public async Task Init() { - await App.Dispatcher.ExecuteOnUIThreadAsync(() => + await App.Dispatcher.EnqueueAsync(() => { var xamlItemsPanelTemplate = @" [TestMethod] public async Task WrapPanel_RendersFine() { - await App.Dispatcher.ExecuteOnUIThreadAsync(async () => + await App.Dispatcher.EnqueueAsync(async () => { var item = new Uri("ms-appx:///Assets/StoreLogo.png"); for (int i = 0; i < 100; i++)