Skip to content

Instantly share code, notes, and snippets.

@Mywk
Last active May 17, 2021 15:25
Show Gist options
  • Save Mywk/eeea638ef2c56c437fe3642be2a5497c to your computer and use it in GitHub Desktop.
Save Mywk/eeea638ef2c56c437fe3642be2a5497c to your computer and use it in GitHub Desktop.
AcrylicWindow - Extension of MetroWindow with BlurBehind and compatibility with both MahApps and MaterialDesignInXamlToolkit
/// <summary>
/// Extended MetroWindow with BlurBehind and compatibility with both MahApps and MaterialDesignInXamlToolkit
/// </summary>
public class AcrylicWindow : MetroWindow
{
internal enum AccentState
{
ACCENT_DISABLED = 1, // Disabled
ACCENT_ENABLE_GRADIENT = 0, // No idea, it's gray no matter what
ACCENT_ENABLE_TRANSPARENTGRADIENT = 2, // Painted with accent colour
ACCENT_ENABLE_BLURBEHIND = 3, // Blurbehind effect
ACCENT_INVALID_STATE = 4 // Invalid state
}
[StructLayout(LayoutKind.Sequential)]
internal struct AccentPolicy
{
public AccentState AccentState;
public int AccentFlags;
public int GradientColor;
public int AnimationId;
}
[StructLayout(LayoutKind.Sequential)]
internal struct WindowCompositionAttributeData
{
public WindowCompositionAttribute Attribute; // Query attributes
public IntPtr Data; // Data buffer
public int SizeOfData; // Data size
}
internal enum WindowCompositionAttribute // Same as NtUserGetWindowCompositionAttribute?
{
WCA_ACCENT_POLICY = 19
}
public AcrylicWindow() : base() {
// Transparency is required for this to work
this.AllowsTransparency = true;
}
/// <summary>
/// Sets various DWM window attributes
/// </summary>
/// <param name="hwnd">The window to modify</param>
/// <param name="data">Pointer to the structure with the attribute data</param>
/// <returns> Nonzero on success, zero otherwise. You can call GetLastError on failure.</returns>
[DllImport("user32.dll")]
internal static extern int SetWindowCompositionAttribute(IntPtr hwnd, ref WindowCompositionAttributeData data);
private bool isDarkTheme = false;
/// <summary>
/// This property can be used to find out if the current window is using the dark theme
/// </summary>
public bool IsDarkTheme
{
get { return isDarkTheme; }
private set { isDarkTheme = value; }
}
/// <summary>
/// Copy the current MahApps theme to MaterialDesignTheme
/// </summary>
public void FixMaterialDesignTheme()
{
// Detect the current theme
ControlzEx.Theming.Theme currentTheme = ThemeManager.Current.DetectTheme(Application.Current);
IsDarkTheme = currentTheme.BaseColorScheme.ToUpperInvariant() == "DARK";
// Compatibility for MaterialDesignTheme
var paletteHelper = new PaletteHelper();
ITheme theme = paletteHelper.GetTheme();
IBaseTheme baseTheme = IsDarkTheme ? new MaterialDesignDarkTheme() : (IBaseTheme)new MaterialDesignLightTheme();
theme.SetBaseTheme(baseTheme);
theme.SetPrimaryColor(currentTheme.PrimaryAccentColor);
theme.SetSecondaryColor(currentTheme.PrimaryAccentColor);
paletteHelper.SetTheme(theme);
// Set correct ThemeBackground and background transparency
this.SetResourceReference(BackgroundProperty, "MahApps.Brushes.ThemeBackground");
var color = this.Background.Clone();
color.Opacity = 0.90;
this.Background = color;
}
/// <summary>
/// Invoked whenever application code or internal processes (such as a rebuilding layout pass) call ApplyTemplate.
/// </summary>
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
EnableBlurBehind();
// Set theme for whole window
ThemeManager.Current.ThemeSyncMode = ThemeSyncMode.SyncAll;
ThemeManager.Current.SyncTheme();
ThemeManager.Current.ThemeChanged += Current_ThemeChanged;
FixMaterialDesignTheme();
}
/// <summary>
/// Called when the windows theme changes
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Current_ThemeChanged(object sender, ControlzEx.Theming.ThemeChangedEventArgs e)
{
FixMaterialDesignTheme();
}
/// <summary>
/// Enables BlurBehind for our fancy window
/// </summary>
internal void EnableBlurBehind()
{
var windowHelper = new WindowInteropHelper(this);
var accent = new AccentPolicy();
var accentStructSize = Marshal.SizeOf(accent);
accent.AccentState = AccentState.ACCENT_ENABLE_BLURBEHIND;
accent.AccentFlags = 2;
accent.GradientColor = 0x00FFFFFF;
var accentPtr = Marshal.AllocHGlobal(accentStructSize);
Marshal.StructureToPtr(accent, accentPtr, false);
var data = new WindowCompositionAttributeData();
data.Attribute = WindowCompositionAttribute.WCA_ACCENT_POLICY;
data.SizeOfData = accentStructSize;
data.Data = accentPtr;
SetWindowCompositionAttribute(windowHelper.Handle, ref data);
Marshal.FreeHGlobal(accentPtr);
}
}
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<!-- This should be all you need to setup the color theme -->
<materialDesignMahApps:MahAppsBundledTheme x:Name="mahAppsBundledTheme" BaseTheme="Inherit" PrimaryColor="DeepPurple" SecondaryColor="Purple"/>
<!-- MahApps -->
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" />
<!-- Material Design -->
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Defaults.xaml" />
<!-- Material Design: MahApps Compatibility -->
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.MahApps;component/Themes/MaterialDesignTheme.MahApps.Defaults.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment