Skip to content

Commit

Permalink
Fix issue where packaged apps don't respond to Windows theme changes (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
Kinnara committed Oct 3, 2020
1 parent a23d5bc commit 57b71b4
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 79 deletions.
83 changes: 46 additions & 37 deletions ModernWpf/Helpers/ColorsHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@
using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Media;
using System.Windows.Threading;
using Microsoft.Win32;
using ModernWpf.Media.ColorPalette;
using Windows.UI.ViewManagement;

namespace ModernWpf
{
internal class ColorsHelper
internal class ColorsHelper : DispatcherObject
{
private const string AccentKey = "SystemAccentColor";
private const string AccentDark1Key = "SystemAccentColorDark1";
Expand All @@ -21,7 +23,7 @@ internal class ColorsHelper
internal static readonly Color DefaultAccentColor = Color.FromRgb(0x00, 0x78, 0xD7);

private readonly ResourceDictionary _colors = new ResourceDictionary();
private object _uiSettings;
private UISettings _uiSettings;

private Color _systemBackground;
private Color _systemAccent;
Expand All @@ -34,17 +36,19 @@ private ColorsHelper()
}
}

public static bool SystemColorsSupported { get; } = OSVersionHelper.IsWindows10;
public static bool SystemColorsSupported { get; } = OSVersionHelper.IsWindows10OrGreater;

public static ColorsHelper Current { get; } = new ColorsHelper();

public ResourceDictionary Colors => _colors;

public ApplicationTheme? SystemTheme { get; private set; }

public Color SystemAccentColor => _systemAccent;

public event EventHandler SystemThemeChanged;

public event EventHandler AccentColorChanged;
public event EventHandler SystemAccentColorChanged;

[MethodImpl(MethodImplOptions.NoInlining)]
public void FetchSystemAccentColors()
Expand Down Expand Up @@ -108,48 +112,53 @@ public static void UpdateBrushes(ResourceDictionary themeDictionary, ResourceDic
}

[MethodImpl(MethodImplOptions.NoInlining)]
internal static Color GetSystemAccentColor()
private void ListenToSystemColorChanges()
{
var uiSettings = new UISettings();
return uiSettings.GetColorValue(UIColorType.Accent).ToColor();
_uiSettings = new UISettings();
_uiSettings.ColorValuesChanged += OnColorValuesChanged;

if (PackagedAppHelper.IsPackagedApp)
{
SystemEvents.UserPreferenceChanged += OnUserPreferenceChanged;
}

_systemBackground = _uiSettings.GetColorValue(UIColorType.Background).ToColor();
_systemAccent = _uiSettings.GetColorValue(UIColorType.Accent).ToColor();
UpdateSystemAppTheme();
}

[MethodImpl(MethodImplOptions.NoInlining)]
private void ListenToSystemColorChanges()
private void OnColorValuesChanged(UISettings sender, object args)
{
var uiSettings = new UISettings();

_systemBackground = uiSettings.GetColorValue(UIColorType.Background).ToColor();
_systemAccent = uiSettings.GetColorValue(UIColorType.Accent).ToColor();
Dispatcher.BeginInvoke(UpdateColorValues);
}

uiSettings.ColorValuesChanged += (sender, args) =>
[MethodImpl(MethodImplOptions.NoInlining)]
private void OnUserPreferenceChanged(object sender, UserPreferenceChangedEventArgs e)
{
if (e.Category == UserPreferenceCategory.General)
{
#if DEBUG
//for (int i = 0; i <= 8; i++)
//{
// var colorType = (UIColorType)i;
// Debug.WriteLine(colorType + " = " + sender.GetColorValue(colorType));
//}
#endif
var background = sender.GetColorValue(UIColorType.Background).ToColor();
if (_systemBackground != background)
{
_systemBackground = background;
UpdateSystemAppTheme();
SystemThemeChanged?.Invoke(null, EventArgs.Empty);
}
var accent = sender.GetColorValue(UIColorType.Accent).ToColor();
if (_systemAccent != accent)
{
_systemAccent = accent;
AccentColorChanged?.Invoke(null, EventArgs.Empty);
}
};
UpdateColorValues();
}
}

_uiSettings = uiSettings;
[MethodImpl(MethodImplOptions.NoInlining)]
private void UpdateColorValues()
{
var background = _uiSettings.GetColorValue(UIColorType.Background).ToColor();
if (_systemBackground != background)
{
_systemBackground = background;
UpdateSystemAppTheme();
SystemThemeChanged?.Invoke(null, EventArgs.Empty);
}

UpdateSystemAppTheme();
var accent = _uiSettings.GetColorValue(UIColorType.Accent).ToColor();
if (_systemAccent != accent)
{
_systemAccent = accent;
SystemAccentColorChanged?.Invoke(null, EventArgs.Empty);
}
}

private void UpdateSystemAppTheme()
Expand Down
12 changes: 9 additions & 3 deletions ModernWpf/Helpers/OSVersionHelper.cs
Original file line number Diff line number Diff line change
@@ -1,20 +1,26 @@
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;

namespace ModernWpf
{
internal static class OSVersionHelper
{
private static readonly Version _osVersion = GetOSVersion();

internal static bool IsWindowsNT { get; } = Environment.OSVersion.Platform == PlatformID.Win32NT;

internal static bool IsWindows10 { get; } = IsWindowsNT && IsWindows10Impl();
internal static bool IsWindows8OrGreater { get; } = IsWindowsNT && _osVersion >= new Version(6, 2);

internal static bool IsWindows10OrGreater { get; } = IsWindowsNT && _osVersion >= new Version(10, 0);

private static bool IsWindows10Impl()
private static Version GetOSVersion()
{
var osv = new RTL_OSVERSIONINFOEX();
osv.dwOSVersionInfoSize = (uint)Marshal.SizeOf(osv);
int ret = RtlGetVersion(out osv);
return ret == 0 && osv.dwMajorVersion >= 10;
Debug.Assert(ret == 0);
return new Version((int)osv.dwMajorVersion, (int)osv.dwMinorVersion, (int)osv.dwBuildNumber);
}

[DllImport("ntdll.dll")]
Expand Down
33 changes: 33 additions & 0 deletions ModernWpf/Helpers/PackagedAppHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using System.Runtime.InteropServices;
using System.Text;

namespace ModernWpf
{
internal static class PackagedAppHelper
{
private const long APPMODEL_ERROR_NO_PACKAGE = 15700L;

public static bool IsPackagedApp
{
get
{
if (OSVersionHelper.IsWindows8OrGreater)
{
int length = 0;
var sb = new StringBuilder(0);
GetCurrentPackageFullName(ref length, sb);

sb.Length = length;
int result = GetCurrentPackageFullName(ref length, sb);

return result != APPMODEL_ERROR_NO_PACKAGE;
}

return false;
}
}

[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern int GetCurrentPackageFullName(ref int packageFullNameLength, StringBuilder packageFullName);
}
}
22 changes: 8 additions & 14 deletions ModernWpf/ThemeManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ private void UpdateActualAccentColor()
{
if (UsingSystemAccentColor)
{
ActualAccentColor = ColorsHelper.GetSystemAccentColor();
ActualAccentColor = ColorsHelper.Current.SystemAccentColor;
}
else
{
Expand Down Expand Up @@ -786,7 +786,7 @@ internal void Initialize()
appResources.MergedDictionaries.RemoveAll<IntellisenseResourcesBase>();

ColorsHelper.Current.SystemThemeChanged += OnSystemThemeChanged;
ColorsHelper.Current.AccentColorChanged += OnSystemAccentColorChanged;
ColorsHelper.Current.SystemAccentColorChanged += OnSystemAccentColorChanged;
appResources.MergedDictionaries.Insert(0, ColorsHelper.Current.Colors);

UpdateActualAccentColor();
Expand All @@ -803,24 +803,18 @@ internal void Initialize()

private void OnSystemThemeChanged(object sender, EventArgs e)
{
Dispatcher.BeginInvoke(() =>
if (UsingSystemTheme)
{
if (UsingSystemTheme)
{
UpdateActualApplicationTheme();
}
});
UpdateActualApplicationTheme();
}
}

private void OnSystemAccentColorChanged(object sender, EventArgs e)
{
Dispatcher.BeginInvoke(() =>
if (UsingSystemAccentColor)
{
if (UsingSystemAccentColor)
{
UpdateActualAccentColor();
}
});
UpdateActualAccentColor();
}
}

private void OnSystemParametersChanged(object sender, PropertyChangedEventArgs e)
Expand Down
58 changes: 33 additions & 25 deletions ModernWpf/UISettingsResources.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Threading;
using Microsoft.Win32;
using Windows.Foundation.Metadata;
using Windows.UI.ViewManagement;

Expand All @@ -11,7 +12,8 @@ internal class UISettingsResources : ResourceDictionary
private const string UniversalApiContractName = "Windows.Foundation.UniversalApiContract";
private const string AutoHideScrollBarsKey = "AutoHideScrollBars";

private object _uiSettings;
private readonly Dispatcher _dispatcher = Dispatcher.CurrentDispatcher;
private UISettings _uiSettings;

public UISettingsResources()
{
Expand All @@ -20,7 +22,7 @@ public UISettingsResources()
return;
}

if (OSVersionHelper.IsWindows10)
if (OSVersionHelper.IsWindows10OrGreater)
{
Initialize();
}
Expand All @@ -29,51 +31,56 @@ public UISettingsResources()
[MethodImpl(MethodImplOptions.NoInlining)]
private void Initialize()
{
var uiSettings = new UISettings();
_uiSettings = new UISettings();

if (ApiInformation.IsApiContractPresent(UniversalApiContractName, 4))
{
InitializeForContract4(uiSettings);
InitializeForContract4();
}

if (ApiInformation.IsApiContractPresent(UniversalApiContractName, 8))
{
InitializeForContract8(uiSettings);
InitializeForContract8();
}

_uiSettings = uiSettings;
}

[MethodImpl(MethodImplOptions.NoInlining)]
private void InitializeForContract4(UISettings settings)
private void InitializeForContract4()
{
settings.AdvancedEffectsEnabledChanged += (sender, args) =>
_uiSettings.AdvancedEffectsEnabledChanged += (sender, args) =>
{
Application.Current.Dispatcher.BeginInvoke(() =>
{
ApplyAdvancedEffectsEnabled(sender.AdvancedEffectsEnabled);
});
_dispatcher.BeginInvoke(ApplyAdvancedEffectsEnabled);
};
ApplyAdvancedEffectsEnabled(settings.AdvancedEffectsEnabled);

if (PackagedAppHelper.IsPackagedApp)
{
SystemEvents.UserPreferenceChanged += (sender, args) =>
{
if (args.Category == UserPreferenceCategory.General)
{
ApplyAdvancedEffectsEnabled();
}
};
}

ApplyAdvancedEffectsEnabled();
}

[MethodImpl(MethodImplOptions.NoInlining)]
private void InitializeForContract8(UISettings settings)
private void InitializeForContract8()
{
settings.AutoHideScrollBarsChanged += (sender, args) =>
_uiSettings.AutoHideScrollBarsChanged += (sender, args) =>
{
Application.Current.Dispatcher.BeginInvoke(() =>
{
ApplyAutoHideScrollBars(sender.AutoHideScrollBars);
});
_dispatcher.BeginInvoke(ApplyAutoHideScrollBars);
};
ApplyAutoHideScrollBars(settings.AutoHideScrollBars);
ApplyAutoHideScrollBars();
}

private void ApplyAdvancedEffectsEnabled(bool value)
[MethodImpl(MethodImplOptions.NoInlining)]
private void ApplyAdvancedEffectsEnabled()
{
var key = SystemParameters.DropShadowKey;
if (value)
if (_uiSettings.AdvancedEffectsEnabled)
{
Remove(key);
}
Expand All @@ -83,9 +90,10 @@ private void ApplyAdvancedEffectsEnabled(bool value)
}
}

private void ApplyAutoHideScrollBars(bool value)
[MethodImpl(MethodImplOptions.NoInlining)]
private void ApplyAutoHideScrollBars()
{
this[AutoHideScrollBarsKey] = value;
this[AutoHideScrollBarsKey] = _uiSettings.AutoHideScrollBars;
}
}
}

0 comments on commit 57b71b4

Please sign in to comment.