Skip to content

Commit 06b67f0

Browse files
authored
Fix: Fixed possible NullReferenceException with DispatcherQueue.EnqueueAsync() (#12196)
1 parent fd96bc1 commit 06b67f0

34 files changed

+138
-80
lines changed

src/Files.App/App.xaml.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,7 @@ public void OnActivated(AppActivationArguments activatedEventArgs)
270270
var data = activatedEventArgs.Data;
271271

272272
// InitializeApplication accesses UI, needs to be called on UI thread
273-
_ = Window.DispatcherQueue.EnqueueAsync(() => Window.InitializeApplication(data));
273+
_ = Window.DispatcherQueue.EnqueueOrInvokeAsync(() => Window.InitializeApplication(data));
274274
}
275275

276276
/// <summary>
@@ -475,7 +475,7 @@ private static void AppUnhandledException(Exception ex, bool shouldShowNotificat
475475
userSettingsService.AppSettingsService.RestoreTabsOnStartup = true;
476476
userSettingsService.GeneralSettingsService.LastCrashedTabList = lastSessionTabList;
477477

478-
Window.DispatcherQueue.EnqueueAsync(async () =>
478+
Window.DispatcherQueue.EnqueueOrInvokeAsync(async () =>
479479
{
480480
await Launcher.LaunchUriAsync(new Uri("files-uwp:"));
481481
}).Wait(1000);

src/Files.App/BaseLayout.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ internal set
257257
if (selectedItems.Count == 1)
258258
{
259259
SelectedItemsPropertiesViewModel.SelectedItemsCountString = $"{selectedItems.Count} {"ItemSelected/Text".GetLocalizedResource()}";
260-
DispatcherQueue.EnqueueAsync(async () =>
260+
DispatcherQueue.EnqueueOrInvokeAsync(async () =>
261261
{
262262
// Tapped event must be executed first
263263
await Task.Delay(50);
@@ -1355,7 +1355,7 @@ protected async void ValidateItemNameInputText(TextBox textBox, TextBoxBeforeTex
13551355
{
13561356
args.Cancel = true;
13571357

1358-
await DispatcherQueue.EnqueueAsync(() =>
1358+
await DispatcherQueue.EnqueueOrInvokeAsync(() =>
13591359
{
13601360
var oldSelection = textBox.SelectionStart + textBox.SelectionLength;
13611361
var oldText = textBox.Text;

src/Files.App/DataModels/NavigationControlItems/DriveItem.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ public static async Task<DriveItem> CreateFromPropertiesAsync(StorageFolder root
184184
item.DeviceID = deviceId;
185185
item.Root = root;
186186

187-
_ = App.Window.DispatcherQueue.EnqueueAsync(() => item.UpdatePropertiesAsync());
187+
_ = App.Window.DispatcherQueue.EnqueueOrInvokeAsync(() => item.UpdatePropertiesAsync());
188188

189189
return item;
190190
}

src/Files.App/DataModels/NavigationControlItems/LocationItem.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ public ulong SpaceUsed
9595
{
9696
SetProperty(ref spaceUsed, value);
9797

98-
App.Window.DispatcherQueue.EnqueueAsync(() => OnPropertyChanged(nameof(ToolTipText)));
98+
App.Window.DispatcherQueue.EnqueueOrInvokeAsync(() => OnPropertyChanged(nameof(ToolTipText)));
9999
}
100100
}
101101

src/Files.App/DataModels/SidebarPinnedModel.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -115,20 +115,20 @@ public async Task<LocationItem> CreateLocationItemFromPathAsync(string path)
115115
{
116116
var iconData = await FileThumbnailHelper.LoadIconFromStorageItemAsync(res.Result, 96u, ThumbnailMode.ListView);
117117
locationItem.IconData = iconData;
118-
locationItem.Icon = await App.Window.DispatcherQueue.EnqueueAsync(() => locationItem.IconData.ToBitmapAsync());
118+
locationItem.Icon = await App.Window.DispatcherQueue.EnqueueOrInvokeAsync(() => locationItem.IconData.ToBitmapAsync());
119119
}
120120

121121
if (locationItem.IconData is null)
122122
{
123123
locationItem.IconData = await FileThumbnailHelper.LoadIconWithoutOverlayAsync(path, 96u);
124124

125125
if (locationItem.IconData is not null)
126-
locationItem.Icon = await App.Window.DispatcherQueue.EnqueueAsync(() => locationItem.IconData.ToBitmapAsync());
126+
locationItem.Icon = await App.Window.DispatcherQueue.EnqueueOrInvokeAsync(() => locationItem.IconData.ToBitmapAsync());
127127
}
128128
}
129129
else
130130
{
131-
locationItem.Icon = await App.Window.DispatcherQueue.EnqueueAsync(() => UIHelpers.GetSidebarIconResource(Constants.ImageRes.Folder));
131+
locationItem.Icon = await App.Window.DispatcherQueue.EnqueueOrInvokeAsync(() => UIHelpers.GetSidebarIconResource(Constants.ImageRes.Folder));
132132
locationItem.IsInvalid = true;
133133
Debug.WriteLine($"Pinned item was invalid {res.ErrorCode}, item: {path}");
134134
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
using CommunityToolkit.WinUI;
2+
using Microsoft.UI.Dispatching;
3+
using System;
4+
using System.Threading.Tasks;
5+
6+
namespace Files.App.Extensions
7+
{
8+
// Window.DispatcherQueue seems to be null sometimes.
9+
// We don't know why, but as a workaround, we invoke the function directly if DispatcherQueue is null.
10+
public static class DispatcherQueueExtensions
11+
{
12+
public static Task EnqueueOrInvokeAsync(this DispatcherQueue? dispatcher, Func<Task> function, DispatcherQueuePriority priority = DispatcherQueuePriority.Normal)
13+
{
14+
if (dispatcher is not null)
15+
return dispatcher.EnqueueAsync(function, priority);
16+
else
17+
return function();
18+
}
19+
20+
public static Task<T> EnqueueOrInvokeAsync<T>(this DispatcherQueue? dispatcher, Func<Task<T>> function, DispatcherQueuePriority priority = DispatcherQueuePriority.Normal)
21+
{
22+
if (dispatcher is not null)
23+
return dispatcher.EnqueueAsync(function, priority);
24+
else
25+
return function();
26+
}
27+
28+
public static Task EnqueueOrInvokeAsync(this DispatcherQueue? dispatcher, Action function, DispatcherQueuePriority priority = DispatcherQueuePriority.Normal)
29+
{
30+
if (dispatcher is not null)
31+
return dispatcher.EnqueueAsync(function, priority);
32+
else
33+
{
34+
function();
35+
return Task.CompletedTask;
36+
}
37+
}
38+
39+
public static Task<T> EnqueueOrInvokeAsync<T>(this DispatcherQueue? dispatcher, Func<T> function, DispatcherQueuePriority priority = DispatcherQueuePriority.Normal)
40+
{
41+
if (dispatcher is not null)
42+
return dispatcher.EnqueueAsync(function, priority);
43+
else
44+
return Task.FromResult(function());
45+
}
46+
47+
}
48+
}

src/Files.App/Filesystem/Cloud/CloudDrivesManager.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using CommunityToolkit.Mvvm.DependencyInjection;
22
using CommunityToolkit.WinUI;
33
using Files.App.DataModels.NavigationControlItems;
4+
using Files.App.Extensions;
45
using Files.App.Helpers;
56
using Files.Shared;
67
using Files.Shared.Cloud;
@@ -53,7 +54,7 @@ public async Task UpdateDrivesAsync()
5354
try
5455
{
5556
cloudProviderItem.Root = await StorageFolder.GetFolderFromPathAsync(cloudProviderItem.Path);
56-
_ = App.Window.DispatcherQueue.EnqueueAsync(() => cloudProviderItem.UpdatePropertiesAsync());
57+
_ = App.Window.DispatcherQueue.EnqueueOrInvokeAsync(() => cloudProviderItem.UpdatePropertiesAsync());
5758
}
5859
catch (Exception ex)
5960
{
@@ -72,7 +73,7 @@ public async Task UpdateDrivesAsync()
7273
{
7374
cloudProviderItem.IconData = iconData;
7475
await App.Window.DispatcherQueue
75-
.EnqueueAsync(async () => cloudProviderItem.Icon = await iconData.ToBitmapAsync());
76+
.EnqueueOrInvokeAsync(async () => cloudProviderItem.Icon = await iconData.ToBitmapAsync());
7677
}
7778

7879
lock (drives)

src/Files.App/Filesystem/Search/FolderSearch.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -393,7 +393,7 @@ private ListedItem GetListedItemAsync(string itemPath, WIN32_FIND_DATA findData)
393393
{
394394
if (t.IsCompletedSuccessfully && t.Result is not null)
395395
{
396-
_ = FilesystemTasks.Wrap(() => App.Window.DispatcherQueue.EnqueueAsync(async () =>
396+
_ = FilesystemTasks.Wrap(() => App.Window.DispatcherQueue.EnqueueOrInvokeAsync(async () =>
397397
{
398398
listedItem.FileImage = await t.Result.ToBitmapAsync();
399399
}, Microsoft.UI.Dispatching.DispatcherQueuePriority.Low));

src/Files.App/Helpers/DynamicDialogFactory.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ public static DynamicDialog GetFor_RenameDialog()
9898
inputText.Loaded += (s, e) =>
9999
{
100100
// dispatching to the ui thread fixes an issue where the primary dialog button would steal focus
101-
_ = inputText.DispatcherQueue.EnqueueAsync(() => inputText.Focus(FocusState.Programmatic));
101+
_ = inputText.DispatcherQueue.EnqueueOrInvokeAsync(() => inputText.Focus(FocusState.Programmatic));
102102
};
103103

104104
dialog = new DynamicDialog(new DynamicDialogViewModel()

src/Files.App/Helpers/MenuFlyoutHelper.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using CommunityToolkit.WinUI;
2+
using Files.App.Extensions;
23
using Microsoft.UI.Xaml;
34
using Microsoft.UI.Xaml.Controls;
45
using System;
@@ -101,7 +102,7 @@ private static async void SetupItems(MenuFlyout menu)
101102
return;
102103
}
103104

104-
await menu.DispatcherQueue.EnqueueAsync(() =>
105+
await menu.DispatcherQueue.EnqueueOrInvokeAsync(() =>
105106
{
106107
menu.Items.Clear();
107108
AddItems(menu.Items, itemSource);

0 commit comments

Comments
 (0)