Last active
November 12, 2024 22:36
-
-
Save LanceMcCarthy/4954ab92ca44c19eb4316d9d683efd50 to your computer and use it in GitHub Desktop.
Mica support in .NET MAUI
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ************************************************************************ // | |
// This implementation is inspired from the official WinUI3 backdrops examples | |
// https://github.com/microsoft/WinUI-Gallery/blob/winui3/XamlControlsGallery/ControlPagesSampleCode/SystemBackdrops/SystemBackdropsSample2.txt | |
// *********************************************************************** // | |
using Microsoft.Maui.LifecycleEvents; | |
#if WINDOWS10_0_17763_0_OR_GREATER | |
// The namespace of where the WindowsHelpers class resides | |
// In older versions of .NET MAUI, this was | |
//using YOUR_APP.Platforms.Windows | |
// In newer versions of .NET MAUI, it is now | |
using YOUR_APP.WinUI; | |
#endif | |
namespace YOUR_APP.Maui | |
{ | |
public static class MauiProgram | |
{ | |
public static MauiApp CreateMauiApp() | |
{ | |
var builder = MauiApp.CreateBuilder(); | |
builder | |
.UseMauiApp<App>() | |
.ConfigureFonts(fonts => | |
{ | |
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular"); | |
fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold"); | |
}); | |
// **** THIS SECTION IS WHAT IS RELEVANT FOR YOU ************ // | |
builder.ConfigureLifecycleEvents(events => | |
{ | |
#if WINDOWS10_0_17763_0_OR_GREATER | |
events.AddWindows(wndLifeCycleBuilder => | |
{ | |
wndLifeCycleBuilder.OnWindowCreated(window => | |
{ | |
window.TryMicaOrAcrylic(); // requires 'using YOUR_APP.WinUI;' | |
}); | |
}); | |
#endif | |
}); | |
// ************* END OF RELEVANT SECTION *********** // | |
return builder.Build(); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// **************************************************** // | |
// Place this class file in your Platforms/Windows folder | |
// **************************************************** // | |
using Microsoft.UI.Composition; | |
using Microsoft.UI.Composition.SystemBackdrops; | |
using Microsoft.UI.Xaml; | |
using WinRT; | |
namespace YOUR_APP.Platforms.Windows | |
{ | |
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; | |
}; | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// **************************************************** // | |
// Place this class file in your Platforms/Windows folder | |
// **************************************************** // | |
using System.Runtime.InteropServices; | |
using Windows.System; // Required for DllImport attribute and DispatcherQueue | |
namespace YOUR_APP.Maui.Platforms.Windows; | |
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); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This has been a long time coming. To all who are still trying to solve this issue... it's done.
full sample: https://github.com/kolkonos/MicaBackdropMAUI
As Lance mentioned, add the mica effect during the lifecycle event. I prefer the MikaKind.BaseAlt as it is more pronounced (more vivid color).
THEN in the AppShell.xaml.cs in the class constructor:
It's crucial that you set the opacity to 0 rather than setting the Background to null, as this would cause the framework to fallback to the default.
@ajsuydam