Skip to content

Commit 9d90b62

Browse files
author
msftbot[bot]
authored
Optimizations/refactoring/tweaks to DispatcherQueueHelper (#3498)
## Follow up for #3206 <!-- Add the relevant issue number after the "#" mentioned above (for ex: Fixes #1234) which will automatically close the issue once the PR is merged. --> <!-- Add a brief overview here of the feature/bug & fix. --> ## PR Type What kind of change does this PR introduce? <!-- Please uncomment one or more that apply to this PR. --> - Bugfix - Code style update (formatting) - Refactoring (no functional changes, ~~no api changes~~) - Optimization ## What is the new behavior? <!-- Describe how was this issue resolved or changed? --> This PR includes a number of optimizations, tweaks and refactorings to `DispatcherQueueHelper`: - Removed unnecessary `null` checks for `function`, and enabled nullability annotations. Those `null` checks were unnecessary since there were also other parameters that could also be `null` (ie. the actual `DispatcherQueue`) anyway, plus we'd still get an exception anyway when those instances are accessed. Instead, we now have nullability annotations to make the intent clearer. - Avoided the slowdown and memory allocations in case the thread already had access to the dispatcher queue, which was caused by the C# compiler (sadly) always preemptively instantiating the display class for the closure of the lambda expression used in the other branch (I made a sharplab repro [here](https://sharplab.io/#v2:EYLgxg9gTgpgtADwGwBYA+ABATARgLABQGADAAQY4CsA3IYRgMzlakDChA3oaT+UxUnKCAogDsAjgFcY0gIIBnAJ6iwACgAiAS3kAHAIYAXMAAsYUAIrTppKTJgAacjhZ6wBzRFEBKbry4FeQNJNADNSVVtpADoACT15ABVjWD0AE1kwMBh5eR8AoJ5/AoKDKEVfYr8KyqDXd09VL1p8mqDq1p4MAHYhKNYIAFsdABsYAxhUjCRmjtIAX3bisEMTcOEELJ160VIYPNmi2d5u3oAxKEH1ze3VPZmOhZagx8rFngA3PShSI3lSAF5SKIYAB3IT9IajbYAZQgkigWQAPBBgAArGBuAB8jXuBTeNisMCiCTKYkiMFUjQBmPxh1apXKT0qdKOdQ8ohx+NeTI6vyi0LGACVspJhgZVKJRcMmlzeC8OssjMY1hsYFt2bt9h0WbM+QKDFc1Tc7rKePKCnMZTyePiTnyprj5oRHvR+CwtLoVqYLITONVGKRgBAIMNSHFEskYGkMlkcqQOKQAOZjahOp7+/goUgkxRkwmqCgsYx6USpUZQLWFbmBR5zIA=) that illustrates the issue). Instead now the fallback path is moved to a separate method, so that the IL has the correct codegen. - Renamed the class to `DispatcherQueueExtensions`, since these are all extensions and not a helper class - Similarly, moved the class to the `.Extensions` namespace - Renamed the APIs to `EnqueueAsync` to mirror the `TryEnqueue` name of the actual API in the `DispatcherQueue` class. This better follows the naming convention of the class, and it's also clearer as in case users have multiple windows and different dispatching queues, there isn't really a single "UI thread" - the API is literally just enqueueing an operation on a given dispatcher queue. - Added a check in case `TryEnqueue` fails, so if that happens we now return a wrapped `InvalidOperationException` in the `Task`, whereas the previous behavior would've just caused that task to never be completed, leaving the caller just waiting forever. ## PR Checklist Please check if your PR fulfills the following requirements: - [X] Tested code with current [supported SDKs](../readme.md#supported) - [ ] ~~Pull Request has been submitted to the documentation repository [instructions](..\contributing.md#docs). Link: <!-- docs PR link -->~~ - [ ] ~~Sample in sample app has been added / updated (for bug fixes / features)~~ - [ ] ~~Icon has been created (if new sample) following the [Thumbnail Style Guide and templates](https://github.com/windows-toolkit/WindowsCommunityToolkit-design-assets)~~ - [ ] ~~Tests for the changes have been added (for bug fixes / features) (if applicable)~~ - [X] Header has been added to all new source files (run *build/UpdateHeaders.bat*) - [ ] Contains **NO** breaking changes
2 parents 1ef0ab2 + eca3eb6 commit 9d90b62

31 files changed

+377
-344
lines changed

Microsoft.Toolkit.Uwp.Connectivity/BluetoothLEHelper/BluetoothLEHelper.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
using System.Linq;
99
using System.Threading;
1010
using System.Threading.Tasks;
11-
using Microsoft.Toolkit.Uwp.Helpers;
11+
using Microsoft.Toolkit.Uwp.Extensions;
1212
using Windows.Devices.Bluetooth;
1313
using Windows.Devices.Bluetooth.Advertisement;
1414
using Windows.Devices.Enumeration;
@@ -197,7 +197,7 @@ private async Task Init()
197197
/// <param name="args">The advertisement.</param>
198198
private async void AdvertisementWatcher_Received(BluetoothLEAdvertisementWatcher sender, BluetoothLEAdvertisementReceivedEventArgs args)
199199
{
200-
await DispatcherQueue.ExecuteOnUIThreadAsync(
200+
await DispatcherQueue.EnqueueAsync(
201201
() =>
202202
{
203203
if (_readerWriterLockSlim.TryEnterReadLock(TimeSpan.FromSeconds(1)))
@@ -281,7 +281,7 @@ private async void DeviceWatcher_Removed(DeviceWatcher sender, DeviceInformation
281281
// Protect against race condition if the task runs after the app stopped the deviceWatcher.
282282
if (sender == _deviceWatcher)
283283
{
284-
await DispatcherQueue.ExecuteOnUIThreadAsync(
284+
await DispatcherQueue.EnqueueAsync(
285285
() =>
286286
{
287287
if (_readerWriterLockSlim.TryEnterWriteLock(TimeSpan.FromSeconds(1)))
@@ -331,7 +331,7 @@ private async Task AddDeviceToList(DeviceInformation deviceInfo)
331331

332332
if (connectable)
333333
{
334-
await DispatcherQueue.ExecuteOnUIThreadAsync(
334+
await DispatcherQueue.EnqueueAsync(
335335
() =>
336336
{
337337
if (_readerWriterLockSlim.TryEnterWriteLock(TimeSpan.FromSeconds(1)))

Microsoft.Toolkit.Uwp.Connectivity/BluetoothLEHelper/ObservableBluetoothLEDevice.cs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,11 @@
1111
using System.Runtime.CompilerServices;
1212
using System.Threading;
1313
using System.Threading.Tasks;
14-
using Microsoft.Toolkit.Uwp.Helpers;
14+
using Microsoft.Toolkit.Uwp.Extensions;
1515
using Windows.Devices.Bluetooth;
1616
using Windows.Devices.Bluetooth.GenericAttributeProfile;
1717
using Windows.Devices.Enumeration;
1818
using Windows.System;
19-
using Windows.UI.Core;
2019
using Windows.UI.Xaml.Media.Imaging;
2120

2221
namespace Microsoft.Toolkit.Uwp.Connectivity
@@ -404,7 +403,7 @@ private void ObservableBluetoothLEDevice_PropertyChanged(object sender, Property
404403
/// <exception cref="Exception">Throws Exception when no permission to access device</exception>
405404
public async Task ConnectAsync()
406405
{
407-
await DispatcherQueue.ExecuteOnUIThreadAsync(
406+
await DispatcherQueue.EnqueueAsync(
408407
async () =>
409408
{
410409
if (BluetoothLEDevice == null)
@@ -478,7 +477,7 @@ public async Task DoInAppPairingAsync()
478477
/// <returns>The task of the update.</returns>
479478
public async Task UpdateAsync(DeviceInformationUpdate deviceUpdate)
480479
{
481-
await DispatcherQueue.ExecuteOnUIThreadAsync(
480+
await DispatcherQueue.EnqueueAsync(
482481
() =>
483482
{
484483
DeviceInfo.Update(deviceUpdate);
@@ -521,7 +520,7 @@ protected virtual void OnPropertyChanged([CallerMemberName] string propertyName
521520
/// <param name="args">The arguments.</param>
522521
private async void BluetoothLEDevice_NameChanged(BluetoothLEDevice sender, object args)
523522
{
524-
await DispatcherQueue.ExecuteOnUIThreadAsync(() => { Name = BluetoothLEDevice.Name; }, DispatcherQueuePriority.Normal);
523+
await DispatcherQueue.EnqueueAsync(() => { Name = BluetoothLEDevice.Name; }, DispatcherQueuePriority.Normal);
525524
}
526525

527526
/// <summary>
@@ -531,7 +530,7 @@ private async void BluetoothLEDevice_NameChanged(BluetoothLEDevice sender, objec
531530
/// <param name="args">The arguments.</param>
532531
private async void BluetoothLEDevice_ConnectionStatusChanged(BluetoothLEDevice sender, object args)
533532
{
534-
await DispatcherQueue.ExecuteOnUIThreadAsync(
533+
await DispatcherQueue.EnqueueAsync(
535534
() =>
536535
{
537536
IsPaired = DeviceInfo.Pairing.IsPaired;
@@ -544,7 +543,7 @@ await DispatcherQueue.ExecuteOnUIThreadAsync(
544543
/// </summary>
545544
private async void LoadGlyph()
546545
{
547-
await DispatcherQueue.ExecuteOnUIThreadAsync(
546+
await DispatcherQueue.EnqueueAsync(
548547
async () =>
549548
{
550549
var deviceThumbnail = await DeviceInfo.GetGlyphThumbnailAsync();

Microsoft.Toolkit.Uwp.Connectivity/BluetoothLEHelper/ObservableGattCharacteristics.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
using System.Linq;
88
using System.Runtime.CompilerServices;
99
using System.Threading.Tasks;
10-
using Microsoft.Toolkit.Uwp.Helpers;
10+
using Microsoft.Toolkit.Uwp.Extensions;
1111
using Windows.Devices.Bluetooth;
1212
using Windows.Devices.Bluetooth.GenericAttributeProfile;
1313
using Windows.Security.Cryptography;
@@ -469,7 +469,7 @@ protected virtual void OnPropertyChanged([CallerMemberName] string propertyName
469469
/// <param name="args">The <see cref="GattValueChangedEventArgs"/> instance containing the event data.</param>
470470
private async void Characteristic_ValueChanged(GattCharacteristic sender, GattValueChangedEventArgs args)
471471
{
472-
await DispatcherQueue.ExecuteOnUIThreadAsync(() => { SetValue(args.CharacteristicValue); }, DispatcherQueuePriority.Normal);
472+
await DispatcherQueue.EnqueueAsync(() => { SetValue(args.CharacteristicValue); }, DispatcherQueuePriority.Normal);
473473
}
474474

475475
/// <summary>

Microsoft.Toolkit.Uwp.SampleApp/SamplePages/DispatcherQueueHelper/DispatcherQueueHelperPage.xaml.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using Microsoft.Toolkit.Uwp.Helpers;
77
using Windows.System;
88
using Windows.UI.Xaml;
9+
using Microsoft.Toolkit.Uwp.Extensions;
910

1011
namespace Microsoft.Toolkit.Uwp.SampleApp.SamplePages
1112
{
@@ -21,7 +22,7 @@ private async void ExecuteFromDifferentThreadButton_Click(object sender, RoutedE
2122
var dispatcherQueue = DispatcherQueue.GetForCurrentThread();
2223
int crossThreadReturnedValue = await Task.Run<int>(async () =>
2324
{
24-
int returnedFromUIThread = await dispatcherQueue.ExecuteOnUIThreadAsync<int>(() =>
25+
int returnedFromUIThread = await dispatcherQueue.EnqueueAsync<int>(() =>
2526
{
2627
NormalTextBlock.Text = "Updated from a random thread!";
2728
return 1;

Microsoft.Toolkit.Uwp.UI/Cache/ImageCache.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,8 @@
77
using System.IO;
88
using System.Reflection;
99
using System.Threading.Tasks;
10-
using Microsoft.Toolkit.Uwp.Helpers;
10+
using Microsoft.Toolkit.Uwp.Extensions;
1111
using Windows.Storage;
12-
using Windows.Storage.Streams;
1312
using Windows.System;
1413
using Windows.UI.Xaml.Media.Imaging;
1514

@@ -63,7 +62,7 @@ protected override async Task<BitmapImage> InitializeTypeAsync(Stream stream, Li
6362
throw new FileNotFoundException();
6463
}
6564

66-
return await DispatcherQueue.ExecuteOnUIThreadAsync(async () =>
65+
return await DispatcherQueue.EnqueueAsync(async () =>
6766
{
6867
BitmapImage image = new BitmapImage();
6968

Microsoft.Toolkit.Uwp.UI/Extensions/ScrollViewer/ScrollViewerExtensions.MiddleClickScrolling.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
using System;
66
using System.Threading;
7-
using Microsoft.Toolkit.Uwp.Helpers;
7+
using Microsoft.Toolkit.Uwp.Extensions;
88
using Windows.Devices.Input;
99
using Windows.Foundation;
1010
using Windows.System;
@@ -369,7 +369,7 @@ private static bool IsCursorResourceAvailable()
369369

370370
private static async void RunInUIThread(DispatcherQueue dispatcherQueue, Action action)
371371
{
372-
await dispatcherQueue.ExecuteOnUIThreadAsync(action, DispatcherQueuePriority.Normal);
372+
await dispatcherQueue.EnqueueAsync(action, DispatcherQueuePriority.Normal);
373373
}
374374
}
375375
}

Microsoft.Toolkit.Uwp.UI/Helpers/ThemeListener.cs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,9 @@
33
// See the LICENSE file in the project root for more information.
44

55
using System;
6-
using System.Diagnostics;
76
using System.Runtime.CompilerServices;
87
using System.Threading.Tasks;
9-
using Microsoft.Toolkit.Uwp.Helpers;
8+
using Microsoft.Toolkit.Uwp.Extensions;
109
using Windows.Foundation.Metadata;
1110
using Windows.System;
1211
using Windows.UI.ViewManagement;
@@ -84,7 +83,7 @@ public ThemeListener(DispatcherQueue dispatcherQueue = null)
8483
private void Accessible_HighContrastChanged(AccessibilitySettings sender, object args)
8584
{
8685
#if DEBUG
87-
Debug.WriteLine("HighContrast Changed");
86+
System.Diagnostics.Debug.WriteLine("HighContrast Changed");
8887
#endif
8988

9089
UpdateProperties();
@@ -100,15 +99,15 @@ private async void Settings_ColorValuesChanged(UISettings sender, object args)
10099
internal Task OnColorValuesChanged()
101100
{
102101
// Getting called off thread, so we need to dispatch to request value.
103-
return DispatcherQueue.ExecuteOnUIThreadAsync(
102+
return DispatcherQueue.EnqueueAsync(
104103
() =>
105104
{
106105
// TODO: This doesn't stop the multiple calls if we're in our faked 'White' HighContrast Mode below.
107106
if (CurrentTheme != Application.Current.RequestedTheme ||
108107
IsHighContrast != _accessible.HighContrast)
109108
{
110109
#if DEBUG
111-
Debug.WriteLine("Color Values Changed");
110+
System.Diagnostics.Debug.WriteLine("Color Values Changed");
112111
#endif
113112

114113
UpdateProperties();
@@ -122,7 +121,7 @@ private void CoreWindow_Activated(Windows.UI.Core.CoreWindow sender, Windows.UI.
122121
IsHighContrast != _accessible.HighContrast)
123122
{
124123
#if DEBUG
125-
Debug.WriteLine("CoreWindow Activated Changed");
124+
System.Diagnostics.Debug.WriteLine("CoreWindow Activated Changed");
126125
#endif
127126

128127
UpdateProperties();

Microsoft.Toolkit.Uwp/Deferred/EventDeferral.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33
// See the LICENSE file in the project root for more information.
44

55
using System;
6-
using System.Collections.Generic;
7-
using System.Text;
86
using System.Threading;
97
using System.Threading.Tasks;
108

0 commit comments

Comments
 (0)