Fixing notification activations.
This commit is contained in:
@@ -468,33 +468,14 @@ public partial class MailListPageViewModel : MailBaseViewModel,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sens a new message to synchronize current folder.
|
/// Creates test notifications for the currently selected items.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[RelayCommand]
|
[RelayCommand]
|
||||||
private void SyncFolder()
|
private async Task SyncFolder()
|
||||||
{
|
{
|
||||||
if (!CanSynchronize) return;
|
if (!CanSynchronize || MailCollection.SelectedItemsCount == 0) return;
|
||||||
|
|
||||||
// Only synchronize listed folders.
|
await _notificationBuilder.CreateNotificationsAsync(MailCollection.SelectedItems.Select(a => a.MailCopy));
|
||||||
|
|
||||||
// When doing linked inbox sync, we need to save the sync id to report progress back only once.
|
|
||||||
// Otherwise, we will report progress for each folder and that's what we don't want.
|
|
||||||
|
|
||||||
trackingSynchronizationId = Guid.NewGuid();
|
|
||||||
completedTrackingSynchronizationCount = 0;
|
|
||||||
|
|
||||||
foreach (var folder in ActiveFolder.HandlingFolders)
|
|
||||||
{
|
|
||||||
var options = new MailSynchronizationOptions()
|
|
||||||
{
|
|
||||||
AccountId = folder.MailAccountId,
|
|
||||||
Type = MailSynchronizationType.CustomFolders,
|
|
||||||
SynchronizationFolderIds = [folder.Id],
|
|
||||||
GroupedSynchronizationTrackingId = trackingSynchronizationId
|
|
||||||
};
|
|
||||||
|
|
||||||
Messenger.Send(new NewMailSynchronizationRequested(options));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[RelayCommand]
|
[RelayCommand]
|
||||||
|
|||||||
+152
-45
@@ -4,8 +4,8 @@ using System.Collections.Generic;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using System.Threading;
|
||||||
using CommunityToolkit.Mvvm.Messaging;
|
using CommunityToolkit.Mvvm.Messaging;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.UI.Dispatching;
|
using Microsoft.UI.Dispatching;
|
||||||
@@ -59,8 +59,11 @@ public partial class App : WinoApplication,
|
|||||||
private bool _windowManagerConfigured;
|
private bool _windowManagerConfigured;
|
||||||
private bool _hasConfiguredAccounts;
|
private bool _hasConfiguredAccounts;
|
||||||
private bool _isExiting;
|
private bool _isExiting;
|
||||||
|
private bool _activationInfrastructureInitialized;
|
||||||
|
private int _initialNotificationActivationHandled;
|
||||||
private CancellationTokenSource? _autoSynchronizationLoopCts;
|
private CancellationTokenSource? _autoSynchronizationLoopCts;
|
||||||
private readonly SemaphoreSlim _autoSynchronizationSemaphore = new(1, 1);
|
private readonly SemaphoreSlim _autoSynchronizationSemaphore = new(1, 1);
|
||||||
|
private readonly SemaphoreSlim _activationInfrastructureSemaphore = new(1, 1);
|
||||||
private readonly ConcurrentDictionary<Guid, int> _inboxSyncCounters = [];
|
private readonly ConcurrentDictionary<Guid, int> _inboxSyncCounters = [];
|
||||||
private NativeTrayIcon? _trayIcon;
|
private NativeTrayIcon? _trayIcon;
|
||||||
|
|
||||||
@@ -373,21 +376,35 @@ public partial class App : WinoApplication,
|
|||||||
}
|
}
|
||||||
|
|
||||||
private bool IsStartupTaskLaunch() => AppInstance.GetCurrent().GetActivatedEventArgs()?.Kind == ExtendedActivationKind.StartupTask;
|
private bool IsStartupTaskLaunch() => AppInstance.GetCurrent().GetActivatedEventArgs()?.Kind == ExtendedActivationKind.StartupTask;
|
||||||
public bool IsAppRunning() => MainWindow != null;
|
public bool IsAppRunning()
|
||||||
|
|
||||||
protected override async void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args)
|
|
||||||
{
|
{
|
||||||
base.OnLaunched(args);
|
var windowManager = Services.GetService<IWinoWindowManager>();
|
||||||
|
|
||||||
|
return MainWindow != null ||
|
||||||
|
windowManager?.GetWindow(WinoWindowKind.Shell) != null ||
|
||||||
|
windowManager?.GetWindow(WinoWindowKind.Welcome) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool HasShellWindow()
|
||||||
|
=> Services.GetRequiredService<IWinoWindowManager>().GetWindow(WinoWindowKind.Shell) is IWinoShellWindow;
|
||||||
|
|
||||||
|
private async Task EnsureActivationInfrastructureAsync()
|
||||||
|
{
|
||||||
|
if (_activationInfrastructureInitialized)
|
||||||
|
return;
|
||||||
|
|
||||||
|
await _activationInfrastructureSemaphore.WaitAsync();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (_activationInfrastructureInitialized)
|
||||||
|
return;
|
||||||
|
|
||||||
// Always register notification callbacks.
|
|
||||||
TryRegisterAppNotifications();
|
TryRegisterAppNotifications();
|
||||||
|
|
||||||
await Services.GetRequiredService<ReleaseLocalAccountDataCleanupService>()
|
await Services.GetRequiredService<ReleaseLocalAccountDataCleanupService>()
|
||||||
.RunIfNeededAsync();
|
.RunIfNeededAsync();
|
||||||
|
|
||||||
// Initialize required services regardless of launch activation type.
|
|
||||||
// All activation scenarios require these services to be ready.
|
|
||||||
// Note: Theme service is initialized separately after window creation.
|
|
||||||
await InitializeServicesAsync();
|
await InitializeServicesAsync();
|
||||||
|
|
||||||
_synchronizationManager = Services.GetRequiredService<ISynchronizationManager>();
|
_synchronizationManager = Services.GetRequiredService<ISynchronizationManager>();
|
||||||
@@ -397,8 +414,33 @@ public partial class App : WinoApplication,
|
|||||||
EnsureWindowManagerConfigured();
|
EnsureWindowManagerConfigured();
|
||||||
EnsureTrayIconCreated();
|
EnsureTrayIconCreated();
|
||||||
|
|
||||||
var hasAnyAccount = (await _accountService.GetAccountsAsync()).Any();
|
_hasConfiguredAccounts = (await _accountService.GetAccountsAsync()).Any();
|
||||||
_hasConfiguredAccounts = hasAnyAccount;
|
|
||||||
|
if (_hasConfiguredAccounts)
|
||||||
|
{
|
||||||
|
_preferencesService.PreferenceChanged -= PreferencesServiceChanged;
|
||||||
|
_preferencesService.PreferenceChanged += PreferencesServiceChanged;
|
||||||
|
RestartAutoSynchronizationLoop();
|
||||||
|
}
|
||||||
|
|
||||||
|
_activationInfrastructureInitialized = true;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_activationInfrastructureSemaphore.Release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool TryMarkInitialNotificationActivationHandled()
|
||||||
|
=> Interlocked.Exchange(ref _initialNotificationActivationHandled, 1) == 0;
|
||||||
|
|
||||||
|
protected override async void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args)
|
||||||
|
{
|
||||||
|
base.OnLaunched(args);
|
||||||
|
|
||||||
|
await EnsureActivationInfrastructureAsync();
|
||||||
|
|
||||||
|
var hasAnyAccount = _hasConfiguredAccounts;
|
||||||
if (!IsStartupTaskLaunch() && !hasAnyAccount)
|
if (!IsStartupTaskLaunch() && !hasAnyAccount)
|
||||||
{
|
{
|
||||||
CreateWelcomeWindow();
|
CreateWelcomeWindow();
|
||||||
@@ -408,14 +450,11 @@ public partial class App : WinoApplication,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_preferencesService.PreferenceChanged -= PreferencesServiceChanged;
|
|
||||||
_preferencesService.PreferenceChanged += PreferencesServiceChanged;
|
|
||||||
|
|
||||||
RestartAutoSynchronizationLoop();
|
|
||||||
|
|
||||||
// Check if launched from toast notification.
|
// Check if launched from toast notification.
|
||||||
if (IsNotificationActivation(out AppNotificationActivatedEventArgs toastArgs))
|
if (IsNotificationActivation(out AppNotificationActivatedEventArgs toastArgs) &&
|
||||||
|
TryMarkInitialNotificationActivationHandled())
|
||||||
{
|
{
|
||||||
|
LogActivation($"Processing notification activation from OnLaunched. Arguments: {toastArgs.Argument}");
|
||||||
await HandleToastActivationAsync(toastArgs);
|
await HandleToastActivationAsync(toastArgs);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -459,6 +498,23 @@ public partial class App : WinoApplication,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task HandleInitialActivationAsync()
|
||||||
|
{
|
||||||
|
var activationArgs = AppInstance.GetCurrent().GetActivatedEventArgs();
|
||||||
|
|
||||||
|
if (activationArgs.Kind != ExtendedActivationKind.AppNotification ||
|
||||||
|
activationArgs.Data is not AppNotificationActivatedEventArgs toastArgs ||
|
||||||
|
!TryMarkInitialNotificationActivationHandled())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LogActivation($"Processing initial notification activation from application startup. Arguments: {toastArgs.Argument}");
|
||||||
|
|
||||||
|
await EnsureActivationInfrastructureAsync();
|
||||||
|
await HandleToastActivationAsync(toastArgs);
|
||||||
|
}
|
||||||
|
|
||||||
private void AppNotificationInvoked(AppNotificationManager sender, AppNotificationActivatedEventArgs args)
|
private void AppNotificationInvoked(AppNotificationManager sender, AppNotificationActivatedEventArgs args)
|
||||||
{
|
{
|
||||||
// AppNotification callbacks are not guaranteed to run on the UI thread.
|
// AppNotification callbacks are not guaranteed to run on the UI thread.
|
||||||
@@ -466,6 +522,7 @@ public partial class App : WinoApplication,
|
|||||||
if (MainWindow?.DispatcherQueue?.TryEnqueue(() => _ = HandleToastActivationAsync(args)) == true)
|
if (MainWindow?.DispatcherQueue?.TryEnqueue(() => _ = HandleToastActivationAsync(args)) == true)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
LogActivation($"Processing notification activation from NotificationInvoked. Arguments: {args.Argument}");
|
||||||
_ = HandleToastActivationAsync(args);
|
_ = HandleToastActivationAsync(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -491,6 +548,8 @@ public partial class App : WinoApplication,
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private async Task HandleToastActivationAsync(AppNotificationActivatedEventArgs toastArgs)
|
private async Task HandleToastActivationAsync(AppNotificationActivatedEventArgs toastArgs)
|
||||||
{
|
{
|
||||||
|
LogActivation($"Handling app notification activation. Arguments: {toastArgs.Argument}");
|
||||||
|
|
||||||
var toastArguments = NotificationArguments.Parse(toastArgs.Argument);
|
var toastArguments = NotificationArguments.Parse(toastArgs.Argument);
|
||||||
|
|
||||||
if (toastArguments.TryGetValue(Constants.ToastStoreUpdateActionKey, out string storeUpdateAction) &&
|
if (toastArguments.TryGetValue(Constants.ToastStoreUpdateActionKey, out string storeUpdateAction) &&
|
||||||
@@ -534,19 +593,62 @@ public partial class App : WinoApplication,
|
|||||||
|
|
||||||
await HandleToastActionAsync(action, mailItemUniqueId);
|
await HandleToastActionAsync(action, mailItemUniqueId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LogActivation("App notification activation did not match any known handler.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<IWinoShellWindow?> EnsureShellWindowAsync(WinoApplicationMode mode, bool activateWindow, bool suppressStartupFlows = true)
|
||||||
|
{
|
||||||
|
var windowManager = Services.GetRequiredService<IWinoWindowManager>();
|
||||||
|
var navigationService = Services.GetRequiredService<INavigationService>();
|
||||||
|
var shellWindow = windowManager.GetWindow(WinoWindowKind.Shell) as IWinoShellWindow;
|
||||||
|
|
||||||
|
if (shellWindow == null)
|
||||||
|
{
|
||||||
|
LogActivation($"Creating shell window for {mode} activation.");
|
||||||
|
|
||||||
|
CreateWindow(
|
||||||
|
null,
|
||||||
|
GetModeLaunchArgument(mode),
|
||||||
|
new ShellModeActivationContext
|
||||||
|
{
|
||||||
|
SuppressStartupFlows = suppressStartupFlows
|
||||||
|
});
|
||||||
|
|
||||||
|
await NewThemeService.InitializeAsync();
|
||||||
|
|
||||||
|
if (_hasConfiguredAccounts)
|
||||||
|
{
|
||||||
|
await LoadInitialWinoAccountAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
shellWindow = windowManager.GetWindow(WinoWindowKind.Shell) as IWinoShellWindow ?? MainWindow as IWinoShellWindow;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
navigationService.ChangeApplicationMode(mode, new ShellModeActivationContext
|
||||||
|
{
|
||||||
|
SuppressStartupFlows = suppressStartupFlows
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (activateWindow && shellWindow is WindowEx window)
|
||||||
|
{
|
||||||
|
await ActivateWindowAsync(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
return shellWindow;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task HandleStoreUpdateToastAsync()
|
private async Task HandleStoreUpdateToastAsync()
|
||||||
{
|
{
|
||||||
if (!IsAppRunning())
|
if (!IsAppRunning())
|
||||||
{
|
|
||||||
await CreateAndActivateWindow(null!);
|
await CreateAndActivateWindow(null!);
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
EnsureMainWindowVisibleAndForeground();
|
EnsureMainWindowVisibleAndForeground();
|
||||||
}
|
|
||||||
|
|
||||||
var storeUpdateService = Services.GetRequiredService<IStoreUpdateService>();
|
var storeUpdateService = Services.GetRequiredService<IStoreUpdateService>();
|
||||||
await storeUpdateService.StartUpdateAsync();
|
await storeUpdateService.StartUpdateAsync();
|
||||||
@@ -563,14 +665,7 @@ public partial class App : WinoApplication,
|
|||||||
|
|
||||||
var target = new CalendarItemTarget(calendarItem, CalendarEventTargetType.Single);
|
var target = new CalendarItemTarget(calendarItem, CalendarEventTargetType.Single);
|
||||||
|
|
||||||
if (!IsAppRunning())
|
await EnsureShellWindowAsync(WinoApplicationMode.Calendar, activateWindow: true);
|
||||||
{
|
|
||||||
await CreateAndActivateWindow(null!);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
EnsureMainWindowVisibleAndForeground();
|
|
||||||
}
|
|
||||||
|
|
||||||
navigationService.ChangeApplicationMode(Core.Domain.Enums.WinoApplicationMode.Calendar);
|
navigationService.ChangeApplicationMode(Core.Domain.Enums.WinoApplicationMode.Calendar);
|
||||||
navigationService.Navigate(WinoPage.EventDetailsPage, target);
|
navigationService.Navigate(WinoPage.EventDetailsPage, target);
|
||||||
@@ -613,10 +708,18 @@ public partial class App : WinoApplication,
|
|||||||
var navigationService = Services.GetRequiredService<INavigationService>();
|
var navigationService = Services.GetRequiredService<INavigationService>();
|
||||||
|
|
||||||
var account = await mailService.GetMailAccountByUniqueIdAsync(mailItemUniqueId);
|
var account = await mailService.GetMailAccountByUniqueIdAsync(mailItemUniqueId);
|
||||||
if (account == null) return;
|
if (account == null)
|
||||||
|
{
|
||||||
|
LogActivation($"Notification navigation mail account was not found for {mailItemUniqueId}.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var mailItem = await mailService.GetSingleMailItemAsync(mailItemUniqueId);
|
var mailItem = await mailService.GetSingleMailItemAsync(mailItemUniqueId);
|
||||||
if (mailItem == null) return;
|
if (mailItem == null)
|
||||||
|
{
|
||||||
|
LogActivation($"Notification navigation mail item was not found for {mailItemUniqueId}.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var message = new AccountMenuItemExtended(mailItem.AssignedFolder.Id, mailItem);
|
var message = new AccountMenuItemExtended(mailItem.AssignedFolder.Id, mailItem);
|
||||||
|
|
||||||
@@ -624,19 +727,15 @@ public partial class App : WinoApplication,
|
|||||||
var launchProtocolService = Services.GetRequiredService<ILaunchProtocolService>();
|
var launchProtocolService = Services.GetRequiredService<ILaunchProtocolService>();
|
||||||
launchProtocolService.LaunchParameter = message;
|
launchProtocolService.LaunchParameter = message;
|
||||||
|
|
||||||
// Create window if not already created.
|
var shellWindowAlreadyExists = HasShellWindow();
|
||||||
if (!IsAppRunning())
|
|
||||||
{
|
await EnsureShellWindowAsync(WinoApplicationMode.Mail, activateWindow: true);
|
||||||
// Pass null for args since we're handling toast navigation
|
|
||||||
await CreateAndActivateWindow(null!);
|
|
||||||
navigationService.ChangeApplicationMode(Core.Domain.Enums.WinoApplicationMode.Mail);
|
navigationService.ChangeApplicationMode(Core.Domain.Enums.WinoApplicationMode.Mail);
|
||||||
}
|
|
||||||
else
|
if (shellWindowAlreadyExists)
|
||||||
{
|
{
|
||||||
// App is already running - send message and bring window to front.
|
|
||||||
navigationService.ChangeApplicationMode(Core.Domain.Enums.WinoApplicationMode.Mail);
|
|
||||||
WeakReferenceMessenger.Default.Send(message);
|
WeakReferenceMessenger.Default.Send(message);
|
||||||
EnsureMainWindowVisibleAndForeground();
|
launchProtocolService.LaunchParameter = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -661,7 +760,7 @@ public partial class App : WinoApplication,
|
|||||||
var package = new MailOperationPreperationRequest(action, mailItem);
|
var package = new MailOperationPreperationRequest(action, mailItem);
|
||||||
|
|
||||||
// Check if app is already running (has a window).
|
// Check if app is already running (has a window).
|
||||||
if (IsAppRunning())
|
if (HasShellWindow())
|
||||||
{
|
{
|
||||||
// App is running - use the simple delegator pattern.
|
// App is running - use the simple delegator pattern.
|
||||||
// The synchronization will happen in the background.
|
// The synchronization will happen in the background.
|
||||||
@@ -1285,14 +1384,16 @@ public partial class App : WinoApplication,
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void HandleRedirectedActivation(AppActivationArguments args)
|
public void HandleRedirectedActivation(AppActivationArguments args)
|
||||||
{
|
{
|
||||||
// Dispatch to UI thread since this is called from Program.OnActivated
|
async Task HandleRedirectedActivationAsync()
|
||||||
MainWindow?.DispatcherQueue.TryEnqueue(async () =>
|
|
||||||
{
|
{
|
||||||
|
await EnsureActivationInfrastructureAsync();
|
||||||
|
|
||||||
// Handle different activation kinds
|
// Handle different activation kinds
|
||||||
if (args.Kind == ExtendedActivationKind.AppNotification)
|
if (args.Kind == ExtendedActivationKind.AppNotification)
|
||||||
{
|
{
|
||||||
// Handle toast notification activation
|
// Handle toast notification activation
|
||||||
var toastArgs = (AppNotificationActivatedEventArgs)args.Data;
|
var toastArgs = (AppNotificationActivatedEventArgs)args.Data;
|
||||||
|
LogActivation($"Processing redirected notification activation. Arguments: {toastArgs.Argument}");
|
||||||
_ = HandleToastActivationAsync(toastArgs);
|
_ = HandleToastActivationAsync(toastArgs);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -1324,7 +1425,13 @@ public partial class App : WinoApplication,
|
|||||||
Services.GetRequiredService<IWinoWindowManager>().ActivateWindow(mainWindow);
|
Services.GetRequiredService<IWinoWindowManager>().ActivateWindow(mainWindow);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
|
// Dispatch to UI thread since this is called from Program.OnActivated.
|
||||||
|
if (MainWindow?.DispatcherQueue.TryEnqueue(() => _ = HandleRedirectedActivationAsync()) == true)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_ = HandleRedirectedActivationAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string GetModeLaunchArgument(WinoApplicationMode mode)
|
private static string GetModeLaunchArgument(WinoApplicationMode mode)
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ namespace Wino.Mail.WinUI;
|
|||||||
|
|
||||||
internal sealed class NotificationArguments
|
internal sealed class NotificationArguments
|
||||||
{
|
{
|
||||||
|
private static readonly char[] PairSeparators = ['&', ';'];
|
||||||
private static readonly NotificationArguments Empty = new(new Dictionary<string, string>(StringComparer.Ordinal));
|
private static readonly NotificationArguments Empty = new(new Dictionary<string, string>(StringComparer.Ordinal));
|
||||||
|
|
||||||
private readonly IReadOnlyDictionary<string, string> _values;
|
private readonly IReadOnlyDictionary<string, string> _values;
|
||||||
@@ -24,7 +25,7 @@ internal sealed class NotificationArguments
|
|||||||
|
|
||||||
var values = new Dictionary<string, string>(StringComparer.Ordinal);
|
var values = new Dictionary<string, string>(StringComparer.Ordinal);
|
||||||
|
|
||||||
foreach (var pair in encodedArguments.Split('&', StringSplitOptions.RemoveEmptyEntries))
|
foreach (var pair in encodedArguments.Split(PairSeparators, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries))
|
||||||
{
|
{
|
||||||
var separatorIndex = pair.IndexOf('=');
|
var separatorIndex = pair.IndexOf('=');
|
||||||
if (separatorIndex < 0)
|
if (separatorIndex < 0)
|
||||||
|
|||||||
@@ -34,7 +34,8 @@ public class Program
|
|||||||
var context = new DispatcherQueueSynchronizationContext(
|
var context = new DispatcherQueueSynchronizationContext(
|
||||||
DispatcherQueue.GetForCurrentThread());
|
DispatcherQueue.GetForCurrentThread());
|
||||||
SynchronizationContext.SetSynchronizationContext(context);
|
SynchronizationContext.SetSynchronizationContext(context);
|
||||||
_ = new App();
|
var app = new App();
|
||||||
|
_ = app.HandleInitialActivationAsync();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user