1

I'm trying to style my app similarly to the image below, where the window is acrylic, and the app contents extend into the Title Bar area. I'm using a .NET MAUI shell app, and targeting platforms Windows 10/11 & MacOS. So far, I have an acrylic window, but cannot seem to figure out how to get the app contents to extend into the Title Bar area.

Here is a reference image to show what my goal is: enter image description here

So far, I have an acrylic window... enter image description here

How can I extend the app contents into the Title Bar area?

My Code:

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 (used for creating the acrylic window)

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);
            }
        }
    }
  • Do you want to remove the top white space of the page? – Jessie Zhang -MSFT Jul 06 '23 at 08:36
  • @JessieZhang-MSFT Ultimately I would like to achieve the look of the app in the first photo- where there is an acrylic navigation menu on the left, and where the app blends seamlessly into the Title Bar. If there is a way to remove/hide the Title Bar completely, and then recreate the Caption Buttons (min, max, close) in the app body, I suppose that would work. Or maybe there is a way to get the app body to overlap the Title Bar? – Jeremy Ashcraft Jul 06 '23 at 19:18
  • Try https://stackoverflow.com/a/73498292/199364. I don't know if that recreates those buttons. – ToolmakerSteve Jul 06 '23 at 20:28
  • if I were to remove the title bar, is there a way to re-create a custom title bar in the application body? – Jeremy Ashcraft Jul 07 '23 at 04:15

1 Answers1

0

is there a way to re-create a custom title bar in the application body?

Yes, you can customize the TitleView in a Shell application.

For example:

<ContentPage ...>
    <Shell.TitleView>
        <Image Source="xamarin_logo.png"
               HorizontalOptions="Center"
               VerticalOptions="Center" />
    </Shell.TitleView>
    ...
   </ContentPage>

For more information, please check official document: Display views in the navigation bar.

Jessie Zhang -MSFT
  • 9,830
  • 1
  • 7
  • 19