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

.NET MAUI Shell桌面应用:亚克力窗口标题栏自定义与内容延伸

.NET MAUI Shell应用:实现内容延伸至标题栏(配合亚克力效果)

我正在开发面向Windows 10/11和macOS平台的.NET MAUI Shell应用,想要实现两个核心效果:窗口启用亚克力(Acrylic)效果,同时让应用内容延伸至标题栏区域。目前已经完成了亚克力窗口的实现,但找不到让内容延伸到标题栏的方法。

效果对比

目标效果

目标效果示意图

当前已实现效果

当前亚克力窗口效果

请问如何实现应用内容向标题栏区域延伸?

当前实现代码

MauiProgram.cs

public static class MauiProgram
{
    public static MauiApp CreateMauiApp()
    {
        var builder = MauiApp.CreateBuilder();
        builder
            .UseMauiApp<App>()
            .UseMauiCommunityToolkit()
            .ConfigureFonts(fonts =>
            {
                fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
                fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
                fonts.AddFont("Segoe Fluent Icons.ttf", "SegoeFluentIcons");
            })
            .ConfigureLifecycleEvents(events =>
        {

#if WINDOWS10_0_17763_0_OR_GREATER

            events.AddWindows(wndLifeCycleBuilder =>
            {
                wndLifeCycleBuilder.OnWindowCreated(window =>
                {
                    window.TryMicaOrAcrylic(); // Platforms/Windows/WindowsHelpers.cs
                });
            });



#endif
        });

        builder.Services.AddSingleton<PhoenixPipe>();

    builder.Services.AddTransient<OverviewPage>();
    builder.Services.AddTransient<OverviewViewModel>();
        
    builder.Services.AddTransient<BlocksPage>();
    builder.Services.AddTransient<BlocksViewModel>();

    builder.Services.AddTransient<NewBlockPage>();
    builder.Services.AddTransient<NewBlockViewModel>();


        Routing.RegisterRoute("block_new", typeof(NewBlockPage));
        Routing.RegisterRoute("block_edit", typeof(BlockEditPage));




#if DEBUG
        builder.Logging.AddDebug();
        #endif

        return builder.Build();
    }
}

Platforms/Windows/WindowsHelpers.cs(用于创建亚克力窗口)

public static class WindowHelpers
{
    public static void TryMicaOrAcrylic(this Microsoft.UI.Xaml.Window window)
    {
        
        var dispatcherQueueHelper = new WindowsSystemDispatcherQueueHelper(); // in Platforms.Windows folder
        dispatcherQueueHelper.EnsureWindowsSystemDispatcherQueueController();

        // Hooking up the policy object
        var configurationSource = new SystemBackdropConfiguration();
        configurationSource.IsInputActive = true;

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

        // Let's try Mica first
        if (MicaController.IsSupported())
        {
            var micaController = new MicaController();
            micaController.AddSystemBackdropTarget(window.As<ICompositionSupportsSystemBackdrop>());
            micaController.SetSystemBackdropConfiguration(configurationSource);

            window.Activated += (object sender, WindowActivatedEventArgs args) =>
            {
                if (args.WindowActivationState is WindowActivationState.CodeActivated or WindowActivationState.PointerActivated)
                {
                    // Handle situation where a window is activated and placed on top of other active windows.
                    if (micaController == null)
                    {
                        micaController = new MicaController();
                        micaController.AddSystemBackdropTarget(window.As<ICompositionSupportsSystemBackdrop>()); // Requires 'using WinRT;'
                        micaController.SetSystemBackdropConfiguration(configurationSource);
                    }

                    if (configurationSource != null)
                        configurationSource.IsInputActive = args.WindowActivationState != WindowActivationState.Deactivated;
                }
            };

            window.Closed += (object sender, WindowEventArgs args) =>
            {
                if (micaController != null)
                {
                    micaController.Dispose();
                    micaController = null;
                }

                configurationSource = null;
            };
        }
        // If no Mica, maybe we can use Acrylic instead
        else if (DesktopAcrylicController.IsSupported())
        {
            var acrylicController = new DesktopAcrylicController();
            acrylicController.AddSystemBackdropTarget(window.As<ICompositionSupportsSystemBackdrop>());
            acrylicController.SetSystemBackdropConfiguration(configurationSource);

            window.Activated += (object sender, WindowActivatedEventArgs args) =>
            {
                if (args.WindowActivationState is WindowActivationState.CodeActivated or WindowActivationState.PointerActivated)
                {
                    // Handle situation where a window is activated and placed on top of other active windows.
                    if (acrylicController == null)
                    {
                        acrylicController = new DesktopAcrylicController();
                        acrylicController.AddSystemBackdropTarget(window.As<ICompositionSupportsSystemBackdrop>()); // Requires 'using WinRT;'
                        acrylicController.SetSystemBackdropConfiguration(configurationSource);
                    }
                }

                if (configurationSource != null)
                    configurationSource.IsInputActive = args.WindowActivationState != WindowActivationState.Deactivated;
            };


            window.Closed += (object sender, WindowEventArgs args) =>
            {
                if (acrylicController != null)
                {
                    acrylicController.Dispose();
                    acrylicController = null;
                }

                configurationSource = null;
            };
        }
    
    }
}

Platforms/Windows/WindowsSystemDispatcherQueueHelper.cs

public 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);

    object m_dispatcherQueueController = null;

    public void EnsureWindowsSystemDispatcherQueueController()
    {
        if (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);
        }
    }
}

内容的提问来源于stack exchange,提问作者Jeremy Ashcraft

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 08:18:08