You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 03:16:10