Skip to content

Commit

Permalink
Merge branch 'wherewhere:main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
Clrs17 authored Nov 4, 2023
2 parents 1bc5d96 + b6c4bbd commit 6fff088
Show file tree
Hide file tree
Showing 12 changed files with 352 additions and 20 deletions.
27 changes: 14 additions & 13 deletions CoreAppUWP/App.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,30 +49,30 @@ private void EnsureWindow(LaunchActivatedEventArgs e)
}

Window window = Window.Current;
WindowHelper.TrackWindow(window);

// 不要在窗口已包含内容时重复应用程序初始化,
// 只需确保窗口处于活动状态
// 不要在窗口已包含内容时重复应用程序初始化,
// 只需确保窗口处于活动状态
if (window.Content is not Frame rootFrame)
{
if (SettingsHelper.Get<bool>(SettingsHelper.IsExtendsTitleBar))
{
CoreApplication.GetCurrentView().TitleBar.ExtendViewIntoTitleBar = true;
}

// 创建要充当导航上下文的框架,并导航到第一页
// 创建要充当导航上下文的框架,并导航到第一页
rootFrame = new Frame();

rootFrame.NavigationFailed += OnNavigationFailed;

if (e.UWPLaunchActivatedEventArgs.PreviousExecutionState == Windows.ApplicationModel.Activation.ApplicationExecutionState.Terminated)
{
//TODO: 从之前挂起的应用程序加载状态
//TODO: 从之前挂起的应用程序加载状态
}

// 将框架放在当前窗口中
// 将框架放在当前窗口中
window.Content = rootFrame;

WindowHelper.TrackWindow(window);
ThemeHelper.Initialize();
}

Expand All @@ -87,21 +87,22 @@ private void EnsureWindow(LaunchActivatedEventArgs e)

if (rootFrame.Content == null)
{
// 当导航堆栈尚未还原时,导航到第一页,
// 并通过将所需信息作为导航参数传入来配置
// 参数
// 当导航堆栈尚未还原时,导航到第一页,
// 并通过将所需信息作为导航参数传入来配置
// 参数
rootFrame.Navigate(typeof(MainPage), e);
BackdropHelper.SetBackdrop(window, SettingsHelper.Get<BackdropType>(SettingsHelper.SelectedBackdrop));
}

// 确保当前窗口处于活动状态
// 确保当前窗口处于活动状态
window.Activate();
}

/// <summary>
/// 导航到特定页失败时调用
/// 导航到特定页失败时调用
/// </summary>
///<param name="sender">导航失败的框架</param>
///<param name="e">有关导航失败的详细信息</param>
///<param name="sender">导航失败的框架</param>
///<param name="e">有关导航失败的详细信息</param>
private void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
{
throw new Exception("Failed to load Page " + e.SourcePageType.FullName);
Expand Down
250 changes: 250 additions & 0 deletions CoreAppUWP/Helpers/BackdropHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,250 @@
using CoreAppUWP.Common;
using Microsoft.UI.Composition;
using Microsoft.UI.Composition.SystemBackdrops;
using Microsoft.UI.Xaml;
using System;
using System.Collections.Generic;
using Windows.UI;
using WinRT; // required to support Window.As<ICompositionSupportsSystemBackdrop>()

namespace CoreAppUWP.Helpers
{
public enum BackdropType
{
Mica,
MicaAlt,
DesktopAcrylic,
DefaultColor,
}

public partial class BackdropHelper
{
private readonly Window window;
private readonly WindowsSystemDispatcherQueueHelper m_wsdqHelper;
private MicaController m_micaController;
private DesktopAcrylicController m_acrylicController;
private SystemBackdropConfiguration m_configurationSource;

public BackdropType? Backdrop { get; private set; } = null;
public WeakEvent<BackdropType?> BackdropTypeChanged { get; } = [];

public BackdropHelper(Window window)
{
this.window = window;
m_wsdqHelper = new WindowsSystemDispatcherQueueHelper();
m_wsdqHelper.EnsureWindowsSystemDispatcherQueueController();
}

public void SetBackdrop(BackdropType type)
{
if (type == Backdrop) { return; }

// Reset to default color. If the requested type is supported, we'll update to that.
// Note: This sample completely removes any previous controller to reset to the default
// state. This is done so this sample can show what is expected to be the most
// common pattern of an app simply choosing one controller type which it sets at
// startup. If an app wants to toggle between Mica and Acrylic it could simply
// call RemoveSystemBackdropTarget() on the old controller and then setup the new
// controller, reusing any existing m_configurationSource and Activated/Closed
// event handlers.
Backdrop = BackdropType.DefaultColor;
if (m_micaController != null)
{
m_micaController.Dispose();
m_micaController = null;
}
if (m_acrylicController != null)
{
m_acrylicController.Dispose();
m_acrylicController = null;
}
window.Closed -= Window_Closed;
window.Activated -= Window_Activated;
((FrameworkElement)window.Content).ActualThemeChanged -= Window_ThemeChanged;
m_configurationSource = null;

if (type is BackdropType.Mica or BackdropType.MicaAlt)
{
if (TrySetMicaBackdrop(type == BackdropType.MicaAlt ? MicaKind.BaseAlt : MicaKind.Base))
{
Backdrop = type;
}
//else
//{
// // Mica isn't supported. Try Acrylic.
// type = BackdropType.DesktopAcrylic;
//}
}
if (type == BackdropType.DesktopAcrylic)
{
if (TrySetAcrylicBackdrop())
{
Backdrop = type;
}
}

BackdropTypeChanged.Invoke(Backdrop);
}

private bool TrySetMicaBackdrop(MicaKind kind = MicaKind.Base)
{
if (MicaController.IsSupported())
{
// Hooking up the policy object
m_configurationSource = new SystemBackdropConfiguration();

window.Closed += Window_Closed;
window.Activated += Window_Activated;
((FrameworkElement)window.Content).ActualThemeChanged += Window_ThemeChanged;

// Initial configuration state.
m_configurationSource.IsInputActive = true;
SetConfigurationSourceTheme();

m_micaController = new MicaController { Kind = kind };

// Enable the system backdrop.
// Note: Be sure to have "using WinRT;" to support the Window.As<...>() call.
m_micaController.AddSystemBackdropTarget(window.As<ICompositionSupportsSystemBackdrop>());
m_micaController.SetSystemBackdropConfiguration(m_configurationSource);
return true; // succeeded
}

return false; // Mica is not supported on this system
}

private bool TrySetAcrylicBackdrop()
{
if (DesktopAcrylicController.IsSupported())
{
// Hooking up the policy object
m_configurationSource = new SystemBackdropConfiguration();

window.Closed += Window_Closed;
window.Activated += Window_Activated;
((FrameworkElement)window.Content).ActualThemeChanged += Window_ThemeChanged;

// Initial configuration state.
m_configurationSource.IsInputActive = true;
SetConfigurationSourceTheme();

Color BackgroundColor = ThemeHelper.IsDarkTheme() ? Color.FromArgb(255, 32, 32, 32) : Color.FromArgb(255, 243, 243, 243);
m_acrylicController = new DesktopAcrylicController { TintColor = BackgroundColor, FallbackColor = BackgroundColor };

// Enable the system backdrop.
// Note: Be sure to have "using WinRT;" to support the Window.As<...>() call.
m_acrylicController.AddSystemBackdropTarget(window.As<ICompositionSupportsSystemBackdrop>());
m_acrylicController.SetSystemBackdropConfiguration(m_configurationSource);
return true; // succeeded
}

return false; // Acrylic is not supported on this system
}

private void Window_Activated(object sender, WindowActivatedEventArgs args)
{
m_configurationSource.IsInputActive = args.WindowActivationState != WindowActivationState.Deactivated;
}

private void Window_Closed(object sender, WindowEventArgs args)
{
// Make sure any Mica/Acrylic controller is disposed so it doesn't try to
// use this closed window.
if (m_micaController != null)
{
m_micaController.Dispose();
m_micaController = null;
}
if (m_acrylicController != null)
{
m_acrylicController.Dispose();
m_acrylicController = null;
}
((FrameworkElement)window.Content).ActualThemeChanged -= Window_ThemeChanged;
window.Activated -= Window_Activated;
m_configurationSource = null;
}

private void Window_ThemeChanged(FrameworkElement sender, object args)
{
if (m_configurationSource != null)
{
SetConfigurationSourceTheme();
}
if (m_acrylicController != null)
{
Color BackgroundColor = sender.ActualTheme.IsDarkTheme() ? Color.FromArgb(255, 32, 32, 32) : Color.FromArgb(255, 243, 243, 243);
m_acrylicController.TintColor = m_acrylicController.FallbackColor = BackgroundColor;
}
}

private void SetConfigurationSourceTheme()
{
switch (((FrameworkElement)window.Content).ActualTheme)
{
case ElementTheme.Dark: m_configurationSource.Theme = SystemBackdropTheme.Dark; break;
case ElementTheme.Light: m_configurationSource.Theme = SystemBackdropTheme.Light; break;
case ElementTheme.Default: m_configurationSource.Theme = SystemBackdropTheme.Default; break;
}
}
}

public partial class BackdropHelper
{
public static void RegisterWindow(Window window)
{
if (!ActiveWindows.ContainsKey(window))
{
window.Closed += (sender, args) =>
{
ActiveWindows.Remove(window);
window = null;
};
ActiveWindows[window] = new BackdropHelper(window);
}
}

public static void SetBackdrop(Window window, BackdropType type)
{
if (ActiveWindows.TryGetValue(window, out BackdropHelper backdrop))
{
backdrop.SetBackdrop(type);
}
}

public static void SetAllBackdrop(BackdropType type)
{
ActiveWindows.Values.ForEach(async x =>
{
if (x.window.Dispatcher?.HasThreadAccess == false)
{
await x.window.Dispatcher.ResumeForegroundAsync();
}
x.SetBackdrop(type);
});
}

public static BackdropType? GetBackdrop(Window window)
{
return ActiveWindows.TryGetValue(window, out BackdropHelper backdrop) ? backdrop.Backdrop : null;
}

public static void AddBackdropTypeChanged(Window window, Action<BackdropType?> typedEventHandler)
{
if (ActiveWindows.TryGetValue(window, out BackdropHelper backdrop))
{
backdrop.BackdropTypeChanged.Add(typedEventHandler);
}
}

public static void RemoveBackdropTypeChanged(Window window, Action<BackdropType?> typedEventHandler)
{
if (ActiveWindows.TryGetValue(window, out BackdropHelper backdrop))
{
backdrop.BackdropTypeChanged.Remove(typedEventHandler);
}
}

public static Dictionary<Window, BackdropHelper> ActiveWindows { get; } = [];
}
}
45 changes: 45 additions & 0 deletions CoreAppUWP/Helpers/DispatcherQueueHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
using System;
using System.Runtime.InteropServices; // For DllImport
using Windows.System;

namespace CoreAppUWP.Helpers
{
public partial class WindowsSystemDispatcherQueueHelper
{
[StructLayout(LayoutKind.Sequential)]
private struct DispatcherQueueOptions
{
internal int DWSize;
internal int ThreadType;
internal int ApartmentType;
}

[LibraryImport("CoreMessaging.dll")]
private static unsafe partial int CreateDispatcherQueueController(DispatcherQueueOptions options, IntPtr* instance);

private IntPtr m_dispatcherQueueController = IntPtr.Zero;
public void EnsureWindowsSystemDispatcherQueueController()
{
if (DispatcherQueue.GetForCurrentThread() != null)
{
// one already exists, so we'll just use it.
return;
}

if (m_dispatcherQueueController == IntPtr.Zero)
{
DispatcherQueueOptions options;
options.DWSize = Marshal.SizeOf(typeof(DispatcherQueueOptions));
options.ThreadType = 2; // DQTYPE_THREAD_CURRENT
options.ApartmentType = 2; // DQTAT_COM_STA

unsafe
{
IntPtr dispatcherQueueController;
_ = CreateDispatcherQueueController(options, &dispatcherQueueController);
m_dispatcherQueueController = dispatcherQueueController;
}
}
}
}
}
6 changes: 5 additions & 1 deletion CoreAppUWP/Helpers/SettingsHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
using MetroLog;
using MetroLog.Targets;
using Microsoft.UI.Xaml;
using System;
using System.IO;
using System.Text.Json;
using System.Threading.Tasks;
Expand All @@ -15,6 +14,7 @@ namespace CoreAppUWP.Helpers
public static partial class SettingsHelper
{
public const string SelectedAppTheme = nameof(SelectedAppTheme);
public const string SelectedBackdrop = nameof(SelectedBackdrop);
public const string IsExtendsTitleBar = nameof(IsExtendsTitleBar);

public static Type Get<Type>(string key) => LocalObject.Read<Type>(key);
Expand All @@ -28,6 +28,10 @@ public static void SetDefaultSettings()
{
LocalObject.Save(SelectedAppTheme, ElementTheme.Default);
}
if (!LocalObject.KeyExists(SelectedBackdrop))
{
LocalObject.Save(SelectedBackdrop, BackdropType.Mica);
}
if (!LocalObject.KeyExists(IsExtendsTitleBar))
{
LocalObject.Save(IsExtendsTitleBar, true);
Expand Down
1 change: 0 additions & 1 deletion CoreAppUWP/Helpers/ThemeHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,6 @@ public static void UpdateExtendViewIntoTitleBar(bool IsExtendsTitleBar)
{
await window.Dispatcher.ResumeForegroundAsync();
}
CoreApplication.GetCurrentView().TitleBar.ExtendViewIntoTitleBar = IsExtendsTitleBar;
});
}
Expand Down
Loading

0 comments on commit 6fff088

Please sign in to comment.