From 50e1549dc2a351e7a7e4a5d8a6ef03b5000a2c68 Mon Sep 17 00:00:00 2001 From: wherewhere Date: Sun, 12 Nov 2023 17:06:10 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=A0=E9=99=A4=20ThreadSwitcher=20=E4=BD=BF?= =?UTF-8?q?=E7=94=A8=E5=89=8D=E7=9A=84=E5=88=A4=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 因为它自己会判断 --- CoreAppUWP/Common/ThreadSwitcher.cs | 67 ++++++++++----- CoreAppUWP/Helpers/BackdropHelper.cs | 10 +-- CoreAppUWP/Helpers/ThemeHelper.cs | 85 ++++++------------- .../Pages/SettingsPages/SettingsPage.xaml.cs | 4 +- CoreAppUWP/Program.cs | 3 +- .../SettingsPages/SettingsViewModel.cs | 14 +-- 6 files changed, 79 insertions(+), 104 deletions(-) diff --git a/CoreAppUWP/Common/ThreadSwitcher.cs b/CoreAppUWP/Common/ThreadSwitcher.cs index 6fbee00..3e661c7 100644 --- a/CoreAppUWP/Common/ThreadSwitcher.cs +++ b/CoreAppUWP/Common/ThreadSwitcher.cs @@ -9,32 +9,55 @@ namespace CoreAppUWP.Common { + /// + /// The interface of helper type for switch thread. + /// + public interface IThreadSwitcher : INotifyCompletion + { + /// + /// Gets a value that indicates whether the asynchronous operation has completed. + /// + bool IsCompleted => true; + + /// + /// Ends the await on the completed task. + /// + void GetResult() { } + + /// + /// Gets an awaiter used to await this . + /// + /// An awaiter instance. + IThreadSwitcher GetAwaiter(); + } + /// /// A helper type for switch thread by . This type is not intended to be used directly from your code. /// /// A whose foreground thread to switch execution to. /// Specifies the priority for event dispatch. [EditorBrowsable(EditorBrowsableState.Never)] - public readonly record struct DispatcherThreadSwitcher(CoreDispatcher Dispatcher, CoreDispatcherPriority Priority = CoreDispatcherPriority.Normal) : INotifyCompletion + public readonly record struct CoreDispatcherThreadSwitcher(CoreDispatcher Dispatcher, CoreDispatcherPriority Priority = CoreDispatcherPriority.Normal) : IThreadSwitcher { /// /// Gets a value that indicates whether the asynchronous operation has completed. /// - public bool IsCompleted => Dispatcher.HasThreadAccess; + public bool IsCompleted => Dispatcher?.HasThreadAccess != false; - /// - /// Ends the await on the completed task. - /// + /// public void GetResult() { } /// - /// Gets an awaiter used to await this . + /// Gets an awaiter used to await this . /// /// An awaiter instance. - public DispatcherThreadSwitcher GetAwaiter() => this; + public CoreDispatcherThreadSwitcher GetAwaiter() => this; + + /// + IThreadSwitcher IThreadSwitcher.GetAwaiter() => this; /// - public void OnCompleted(Action continuation) => _ = Dispatcher.RunAsync(Priority, () => continuation()); + public void OnCompleted(Action continuation) => _ = Dispatcher?.RunAsync(Priority, () => continuation()); } /// @@ -43,26 +66,27 @@ public void GetResult() { } /// A whose foreground thread to switch execution to. /// Specifies the priority for event dispatch. [EditorBrowsable(EditorBrowsableState.Never)] - public readonly record struct DispatcherQueueThreadSwitcher(DispatcherQueue Dispatcher, DispatcherQueuePriority Priority = DispatcherQueuePriority.Normal) : INotifyCompletion + public readonly record struct DispatcherQueueThreadSwitcher(DispatcherQueue Dispatcher, DispatcherQueuePriority Priority = DispatcherQueuePriority.Normal) : IThreadSwitcher { /// /// Gets a value that indicates whether the asynchronous operation has completed. /// - public bool IsCompleted => Dispatcher.HasThreadAccess; + public bool IsCompleted => Dispatcher?.HasThreadAccess != false; - /// - /// Ends the await on the completed task. - /// + /// public void GetResult() { } /// - /// Gets an awaiter used to await this . + /// Gets an awaiter used to await this . /// /// An awaiter instance. public DispatcherQueueThreadSwitcher GetAwaiter() => this; /// - public void OnCompleted(Action continuation) => _ = Dispatcher.TryEnqueue(Priority, () => continuation()); + IThreadSwitcher IThreadSwitcher.GetAwaiter() => this; + + /// + public void OnCompleted(Action continuation) => _ = Dispatcher?.TryEnqueue(Priority, () => continuation()); } /// @@ -70,24 +94,25 @@ public void GetResult() { } /// /// Specifies the priority for event dispatch. [EditorBrowsable(EditorBrowsableState.Never)] - public readonly record struct ThreadPoolThreadSwitcher(WorkItemPriority Priority = WorkItemPriority.Normal) : INotifyCompletion + public readonly record struct ThreadPoolThreadSwitcher(WorkItemPriority Priority = WorkItemPriority.Normal) : IThreadSwitcher { /// /// Gets a value that indicates whether the asynchronous operation has completed. /// public bool IsCompleted => SynchronizationContext.Current == null; - /// - /// Ends the await on the completed task. - /// + /// public void GetResult() { } /// - /// Gets an awaiter used to await this . + /// Gets an awaiter used to await this . /// /// An awaiter instance. public ThreadPoolThreadSwitcher GetAwaiter() => this; + /// + IThreadSwitcher IThreadSwitcher.GetAwaiter() => this; + /// public void OnCompleted(Action continuation) => _ = ThreadPool.RunAsync(_ => continuation(), Priority); } @@ -111,7 +136,7 @@ public static class ThreadSwitcher /// A whose foreground thread to switch execution to. /// Specifies the priority for event dispatch. /// An object that you can . - public static DispatcherThreadSwitcher ResumeForegroundAsync(this CoreDispatcher dispatcher, CoreDispatcherPriority priority = CoreDispatcherPriority.Normal) => new(dispatcher, priority); + public static CoreDispatcherThreadSwitcher ResumeForegroundAsync(this CoreDispatcher dispatcher, CoreDispatcherPriority priority = CoreDispatcherPriority.Normal) => new(dispatcher, priority); /// /// A helper function—for use within a coroutine—that returns control to the caller, and then immediately resumes execution on a thread pool thread. diff --git a/CoreAppUWP/Helpers/BackdropHelper.cs b/CoreAppUWP/Helpers/BackdropHelper.cs index 1a1705e..31a8a5e 100644 --- a/CoreAppUWP/Helpers/BackdropHelper.cs +++ b/CoreAppUWP/Helpers/BackdropHelper.cs @@ -308,19 +308,13 @@ public static void SetAllBackdrop(BackdropType type) { ActiveWindows.Values.ForEach(async x => { - if (x.window.DispatcherQueue?.HasThreadAccess == false) - { - await x.window.DispatcherQueue.ResumeForegroundAsync(); - } + await x.window.DispatcherQueue.ResumeForegroundAsync(); x.SetBackdrop(type); }); ActiveDesktopWindows.Values.ForEach(async x => { - if (x.desktopWindow.DispatcherQueue?.HasThreadAccess == false) - { - await x.desktopWindow.DispatcherQueue.ResumeForegroundAsync(); - } + await x.desktopWindow.DispatcherQueue.ResumeForegroundAsync(); x.SetBackdrop(type); }); } diff --git a/CoreAppUWP/Helpers/ThemeHelper.cs b/CoreAppUWP/Helpers/ThemeHelper.cs index 3228f46..feab19c 100644 --- a/CoreAppUWP/Helpers/ThemeHelper.cs +++ b/CoreAppUWP/Helpers/ThemeHelper.cs @@ -41,7 +41,7 @@ public static ElementTheme GetActualTheme(Window window) => window == null ? SettingsHelper.Get(SettingsHelper.SelectedAppTheme) : window.DispatcherQueue?.HasThreadAccess == false - ? window.DispatcherQueue?.EnqueueAsync(() => + ? window.DispatcherQueue.EnqueueAsync(() => window.Content is FrameworkElement _rootElement && _rootElement.RequestedTheme != ElementTheme.Default ? _rootElement.RequestedTheme @@ -60,7 +60,7 @@ public static async ValueTask GetActualThemeAsync(Window window) = window == null ? SettingsHelper.Get(SettingsHelper.SelectedAppTheme) : window.DispatcherQueue?.HasThreadAccess == false - ? await window.DispatcherQueue?.EnqueueAsync(() => + ? await window.DispatcherQueue.EnqueueAsync(() => window.Content is FrameworkElement _rootElement && _rootElement.RequestedTheme != ElementTheme.Default ? _rootElement.RequestedTheme @@ -90,15 +90,15 @@ public static ElementTheme GetRootTheme() => public static ElementTheme GetRootTheme(Window window) => window == null ? ElementTheme.Default - : window.DispatcherQueue.HasThreadAccess - ? window.Content is FrameworkElement rootElement - ? rootElement.RequestedTheme - : ElementTheme.Default - : window.DispatcherQueue.EnqueueAsync(() => + : window.DispatcherQueue?.HasThreadAccess == false + ? window.DispatcherQueue.EnqueueAsync(() => window.Content is FrameworkElement _rootElement ? _rootElement.RequestedTheme : ElementTheme.Default, - DispatcherQueuePriority.High).AwaitByTaskCompleteSource(); + DispatcherQueuePriority.High).AwaitByTaskCompleteSource() + : window.Content is FrameworkElement rootElement + ? rootElement.RequestedTheme + : ElementTheme.Default; public static ValueTask GetRootThemeAsync() => GetRootThemeAsync(Window.Current ?? CurrentApplicationWindow); @@ -106,25 +106,21 @@ public static ValueTask GetRootThemeAsync() => public static async ValueTask GetRootThemeAsync(Window window) => window == null ? ElementTheme.Default - : window.DispatcherQueue.HasThreadAccess - ? window.Content is FrameworkElement rootElement - ? rootElement.RequestedTheme - : ElementTheme.Default - : await window.DispatcherQueue.EnqueueAsync(() => + : window.DispatcherQueue?.HasThreadAccess == false + ? await window.DispatcherQueue.EnqueueAsync(() => window.Content is FrameworkElement _rootElement ? _rootElement.RequestedTheme : ElementTheme.Default, - DispatcherQueuePriority.High); + DispatcherQueuePriority.High) + : window.Content is FrameworkElement rootElement + ? rootElement.RequestedTheme + : ElementTheme.Default; public static async void SetRootTheme(ElementTheme value) { WindowHelper.ActiveWindows.Values.ForEach(async window => { - if (window.DispatcherQueue?.HasThreadAccess == false) - { - await window.DispatcherQueue.ResumeForegroundAsync(); - } - + await window.DispatcherQueue.ResumeForegroundAsync(); if (window.Content is FrameworkElement rootElement) { rootElement.RequestedTheme = value; @@ -133,11 +129,7 @@ public static async void SetRootTheme(ElementTheme value) WindowHelper.ActiveDesktopWindows.Values.ForEach(async window => { - if (!window.DispatcherQueue.HasThreadAccess) - { - await window.DispatcherQueue.ResumeForegroundAsync(); - } - + await window.DispatcherQueue.ResumeForegroundAsync(); if (window.Content is FrameworkElement rootElement) { rootElement.RequestedTheme = value; @@ -153,11 +145,7 @@ public static async ValueTask SetRootThemeAsync(ElementTheme value) { await Task.WhenAll(WindowHelper.ActiveWindows.Values.Select(async window => { - if (window.DispatcherQueue?.HasThreadAccess == false) - { - await window.DispatcherQueue.ResumeForegroundAsync(); - } - + await window.DispatcherQueue.ResumeForegroundAsync(); if (window.Content is FrameworkElement rootElement) { rootElement.RequestedTheme = value; @@ -166,11 +154,7 @@ await Task.WhenAll(WindowHelper.ActiveWindows.Values.Select(async window => await Task.WhenAll(WindowHelper.ActiveDesktopWindows.Values.Select(async window => { - if (!window.DispatcherQueue.HasThreadAccess) - { - await window.DispatcherQueue.ResumeForegroundAsync(); - } - + await window.DispatcherQueue.ResumeForegroundAsync(); if (window.Content is FrameworkElement rootElement) { rootElement.RequestedTheme = value; @@ -191,6 +175,7 @@ public static void Initialize() RootTheme = SettingsHelper.Get(SettingsHelper.SelectedAppTheme); // Registering to color changes, thus we notice when user changes theme system wide + UISettings.ColorValuesChanged -= UISettings_ColorValuesChanged; UISettings.ColorValuesChanged += UISettings_ColorValuesChanged; } @@ -259,10 +244,7 @@ public static void UpdateExtendViewIntoTitleBar(bool IsExtendsTitleBar) { WindowHelper.ActiveWindows.Values.ForEach(async window => { - if (window.DispatcherQueue?.HasThreadAccess == false) - { - await window.DispatcherQueue.ResumeForegroundAsync(); - } + await window.DispatcherQueue.ResumeForegroundAsync(); CoreApplication.GetCurrentView().TitleBar.ExtendViewIntoTitleBar = IsExtendsTitleBar; }); @@ -270,10 +252,7 @@ public static void UpdateExtendViewIntoTitleBar(bool IsExtendsTitleBar) WindowHelper.ActiveDesktopWindows.Values.ForEach(async window => { - if (window.DispatcherQueue?.HasThreadAccess == false) - { - await window.DispatcherQueue.ResumeForegroundAsync(); - } + await window.DispatcherQueue.ResumeForegroundAsync(); window.ExtendsContentIntoTitleBar = IsExtendsTitleBar; }); } @@ -288,11 +267,7 @@ public static async void UpdateSystemCaptionButtonColors() WindowHelper.ActiveWindows.Values.ForEach(async window => { - if (window.DispatcherQueue?.HasThreadAccess == false) - { - await window.DispatcherQueue.ResumeForegroundAsync(); - } - + await window.DispatcherQueue.ResumeForegroundAsync(); bool ExtendViewIntoTitleBar = CoreApplication.GetCurrentView().TitleBar.ExtendViewIntoTitleBar; ApplicationViewTitleBar TitleBar = ApplicationView.GetForCurrentView().TitleBar; TitleBar.ForegroundColor = TitleBar.ButtonForegroundColor = ForegroundColor; @@ -304,11 +279,7 @@ public static async void UpdateSystemCaptionButtonColors() WindowHelper.ActiveDesktopWindows.Values.ForEach(async window => { - if (window.DispatcherQueue?.HasThreadAccess == false) - { - await window.DispatcherQueue.ResumeForegroundAsync(); - } - + await window.DispatcherQueue.ResumeForegroundAsync(); bool ExtendViewIntoTitleBar = window.ExtendsContentIntoTitleBar; AppWindowTitleBar TitleBar = window.AppWindow.TitleBar; TitleBar.ForegroundColor = TitleBar.ButtonForegroundColor = ForegroundColor; @@ -319,10 +290,7 @@ public static async void UpdateSystemCaptionButtonColors() public static async void UpdateSystemCaptionButtonColors(Window window) { - if (window.DispatcherQueue?.HasThreadAccess == false) - { - await window.DispatcherQueue.ResumeForegroundAsync(); - } + await window.DispatcherQueue.ResumeForegroundAsync(); bool IsDark = window?.Content is FrameworkElement rootElement ? rootElement.RequestedTheme.IsDarkTheme() : await IsDarkThemeAsync(); bool IsHighContrast = AccessibilitySettings.HighContrast; @@ -341,10 +309,7 @@ public static async void UpdateSystemCaptionButtonColors(DesktopWindow window) { if (!AppWindowTitleBar.IsCustomizationSupported()) { return; } - if (window.DispatcherQueue?.HasThreadAccess == false) - { - await window.DispatcherQueue.ResumeForegroundAsync(); - } + await window.DispatcherQueue.ResumeForegroundAsync(); bool IsDark = window?.Content is FrameworkElement rootElement ? rootElement.RequestedTheme.IsDarkTheme() : await IsDarkThemeAsync(); bool IsHighContrast = AccessibilitySettings.HighContrast; diff --git a/CoreAppUWP/Pages/SettingsPages/SettingsPage.xaml.cs b/CoreAppUWP/Pages/SettingsPages/SettingsPage.xaml.cs index b771b0d..81c23f2 100644 --- a/CoreAppUWP/Pages/SettingsPages/SettingsPage.xaml.cs +++ b/CoreAppUWP/Pages/SettingsPages/SettingsPage.xaml.cs @@ -161,9 +161,7 @@ void OnLaunched(DesktopWindowXamlSource source) private async void HyperlinkButton_Click(object sender, RoutedEventArgs e) { string tag = (sender as FrameworkElement).Tag?.ToString(); - if (!IsCoreWindow - && WindowHelper.ActiveWindows.Values.FirstOrDefault()?.DispatcherQueue is DispatcherQueue dispatcherQueue - && dispatcherQueue?.HasThreadAccess == false) + if (!IsCoreWindow && WindowHelper.ActiveWindows.Values.FirstOrDefault()?.DispatcherQueue is DispatcherQueue dispatcherQueue) { await dispatcherQueue.ResumeForegroundAsync(); } diff --git a/CoreAppUWP/Program.cs b/CoreAppUWP/Program.cs index 9fc3c7e..95ff38c 100644 --- a/CoreAppUWP/Program.cs +++ b/CoreAppUWP/Program.cs @@ -22,8 +22,6 @@ namespace CoreAppUWP { public static partial class Program { - private static HookRegistry hookRegistry; - private static unsafe bool IsPackagedApp { get @@ -63,6 +61,7 @@ private static void Main() ComWrappersSupport.InitializeComWrappers(); if (IsPackagedApp) { + HookRegistry hookRegistry = null; try { if (!IsSupportCoreWindow) diff --git a/CoreAppUWP/ViewModels/SettingsPages/SettingsViewModel.cs b/CoreAppUWP/ViewModels/SettingsPages/SettingsViewModel.cs index 31e9c61..f75fa2d 100644 --- a/CoreAppUWP/ViewModels/SettingsPages/SettingsViewModel.cs +++ b/CoreAppUWP/ViewModels/SettingsPages/SettingsViewModel.cs @@ -21,7 +21,7 @@ namespace CoreAppUWP.ViewModels.SettingsPages { public class SettingsViewModel : INotifyPropertyChanged { - public static Dictionary Caches { get; } = []; + public static ConditionalWeakTable Caches { get; } = []; public static string WASVersion { get; } = Assembly.GetAssembly(typeof(ExtendedActivationKind)).GetName().Version.ToString(3); @@ -102,10 +102,7 @@ protected static async void RaisePropertyChangedEvent([CallerMemberName] string { foreach (KeyValuePair cache in Caches) { - if (cache.Key?.HasThreadAccess == false) - { - await cache.Key.ResumeForegroundAsync(); - } + await cache.Key.ResumeForegroundAsync(); cache.Value.PropertyChanged?.Invoke(cache.Value, new PropertyChangedEventArgs(name)); } } @@ -117,10 +114,7 @@ protected static async void RaisePropertyChangedEvent(params string[] names) { foreach (KeyValuePair cache in Caches) { - if (cache.Key?.HasThreadAccess == false) - { - await cache.Key.ResumeForegroundAsync(); - } + await cache.Key.ResumeForegroundAsync(); names.ForEach(name => cache.Value.PropertyChanged?.Invoke(cache.Value, new PropertyChangedEventArgs(name))); } } @@ -139,7 +133,7 @@ protected void SetProperty(ref TProperty property, TProperty value, [ public SettingsViewModel(DispatcherQueue dispatcher) { Dispatcher = dispatcher ?? DispatcherQueue.GetForCurrentThread(); - Caches[dispatcher] = this; + Caches.AddOrUpdate(dispatcher, this); } private async ValueTask GetAboutTextBlockTextAsync(bool reset)