WinUI 3应用中DesktopAcrylicController崩溃问题求助
WinUI 3 亚克力背景运行时异常问题
我在WinUI 3中尝试使用亚克力画笔,按照文档要求实现了WindowsSystemDispatcherQueueHelper辅助类,但运行时在m_acrylicController.AddSystemBackdropTarget(window.As<ICompositionSupportsSystemBackdrop>());这一行抛出异常。
相关代码
BackdropService 代码
using Microsoft.UI.Composition.SystemBackdrops; using Microsoft.UI.Composition; using Microsoft.UI.Xaml; using Microsoft.UI; using WinRT; namespace Alessia.Helpers { static class BackdropService { public static bool TrySetAcrylicBackdrop(Window window) { if (DesktopAcrylicController.IsSupported()) { m_sdqHelper ??= new(); m_sdqHelper.EnsureWindowsSystemDispatcherQueueController(); // Hooking up the policy object m_configurationSource ??= new(); window.Activated += OnWindowActivated; window.Closed += OnWindowClosed; (window.Content as FrameworkElement).ActualThemeChanged += OnActualThemeChanged; // Initial configuration state. m_configurationSource.IsInputActive = true; SetConfigurationSourceTheme(window.Content as FrameworkElement); m_acrylicController ??= new() { TintColor = Colors.Red }; // 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 } } }
WindowsSystemDispatcherQueueHelper 辅助类代码
using System.Runtime.InteropServices; namespace Alessia.Helpers { sealed class WindowsSystemDispatcherQueueHelper { [StructLayout(LayoutKind.Sequential)] struct DispatcherQueueOptions { internal int dwSize; internal int threadType; internal int apartmentType; } [DllImport("CoreMessaging.dll")] private static extern int CreateDispatcherQueueController([In] DispatcherQueueOptions options, [In, Out, MarshalAs(UnmanagedType.IUnknown)] ref object dispatcherQueueController); public void EnsureWindowsSystemDispatcherQueueController() { if (Windows.System.DispatcherQueue.GetForCurrentThread() != null) // one already exists, so we'll just use it. return; if (m_dispatcherQueueController == null) { DispatcherQueueOptions options; options.dwSize = Marshal.SizeOf(typeof(DispatcherQueueOptions)); options.threadType = 2; // DQTYPE_THREAD_CURRENT options.apartmentType = 2; // DQTAT_COM_STA _ = CreateDispatcherQueueController(options, ref m_dispatcherQueueController); } } object m_dispatcherQueueController = null; } }
异常信息
异常截图:
异常提示:System.Runtime.InteropServices.COMException: '请求的操作无法在有用户输入挂起时执行。 (0x80004005 (E_FAIL))'
解决方法
1. 调整调用时机
必须在窗口内容完全加载后再调用TrySetAcrylicBackdrop,推荐在窗口的Loaded事件中触发,而非构造函数:
public MainWindow() { this.InitializeComponent(); this.Loaded += MainWindow_Loaded; } private void MainWindow_Loaded(object sender, RoutedEventArgs e) { BackdropService.TrySetAcrylicBackdrop(this); }
2. 修复DispatcherQueue创建逻辑
补充返回值检查确保创建成功,同时调整线程公寓类型为DQTAT_COM_NONE(值为1):
// 修改后的EnsureWindowsSystemDispatcherQueueController方法 public void EnsureWindowsSystemDispatcherQueueController() { if (Windows.System.DispatcherQueue.GetForCurrentThread() != null) return; if (m_dispatcherQueueController == null) { DispatcherQueueOptions options; options.dwSize = Marshal.SizeOf(typeof(DispatcherQueueOptions)); options.threadType = 2; // DQTYPE_THREAD_CURRENT options.apartmentType = 1; // DQTAT_COM_NONE int result = CreateDispatcherQueueController(options, ref m_dispatcherQueueController); if (result != 0) { throw new System.ComponentModel.Win32Exception(result); } } }
3. 补充缺失的静态字段与事件处理
原BackdropService类缺少三个静态字段及对应的事件处理方法,需补充完整:
static class BackdropService { private static WindowsSystemDispatcherQueueHelper m_sdqHelper; private static SystemBackdropConfiguration m_configurationSource; private static DesktopAcrylicController m_acrylicController; // ... 原有TrySetAcrylicBackdrop方法 ... private static void OnWindowActivated(object sender, WindowActivatedEventArgs args) { m_configurationSource.IsInputActive = args.WindowActivationState != WindowActivationState.Deactivated; } private static void OnWindowClosed(object sender, WindowEventArgs args) { if (sender is Window window) { window.Activated -= OnWindowActivated; window.Closed -= OnWindowClosed; (window.Content as FrameworkElement).ActualThemeChanged -= OnActualThemeChanged; m_acrylicController?.Dispose(); m_acrylicController = null; m_configurationSource = null; m_sdqHelper = null; } } private static void OnActualThemeChanged(FrameworkElement sender, object args) { SetConfigurationSourceTheme(sender); } private static void SetConfigurationSourceTheme(FrameworkElement frameworkElement) { switch (frameworkElement.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; } } }
4. 增加Content非空校验
在TrySetAcrylicBackdrop开头添加窗口Content的非空判断,避免空引用间接引发异常:
public static bool TrySetAcrylicBackdrop(Window window) { if (window.Content == null) { return false; } // ... 原有代码 ... }
内容的提问来源于stack exchange,提问作者ImMike-SB
相关产品推荐
相关产品推荐

