Skip to content

Conversation

krlvm
Copy link

@krlvm krlvm commented Oct 12, 2021

Hello.

I'm developing a small application that resembles Windows 10 taskbar flyouts and I need to react to accent color change when "Show accent color on the following surfaces: Start, taskbar, and action center" setting is enabled. After subscribing to accent color change event (AccentColors.StaticPropertyChanged += Theme_AccentColorChanged, Theme_AccentColorChanged method is querying registry, modifies AcrylicWindow properties and refreshes the tray icon) and changing the accent color my application freezes and crashes.

After some investigations, I've noticed that changing accent color on Windows 10 (at least, since 1903, I'm using 21H1, which is based on 20H1) is way slower than on Windows 8, 7, Vista or Windows 10 1507 (did not test on other versions < 1903). That's because the latest Windows 10 versions contains a bug which foces system to issue multiple (seems to be at least 10) WM_DWMCOLORIZATIONCOLORCHANGED messages.

I've modified FluentWPF code to issue 14 times less event calls, because in the current implementation changing of each property fires event handlers immediately, when it calls it once after Initialize() in this patch.

Thank you for creating this project again.

@selastingeorge
Copy link

selastingeorge commented Oct 12, 2021

For windows 10 Build 10240 and above instead of listening to the WM_DWMCOLORIZATIONCOLORCHANGED message, using UISettings class from Windows.UI.Composition Seems to be the best Solution. The UISettings Class have ColorValuesChanged
event which only fires once when the accent color is changed. But you need to add Microsoft.Windows.SDK.Contracts nuget package or CSWinRT package to get access to this Class. Here is a Demo:

    public class AccentColors
    {
        private static readonly UISettings settings;

        private static SolidColorBrush systemAccent;
        private static SolidColorBrush systemAccentDark1;
        private static SolidColorBrush systemAccentDark2;
        private static SolidColorBrush systemAccentDark3;
        private static SolidColorBrush systemAccentLight1;
        private static SolidColorBrush systemAccentLight2;
        private static SolidColorBrush systemAccentLight3;

        public static event EventHandler<PropertyChangedEventArgs> StaticPropertyChanged;

        static AccentColors()
        {
            settings = new UISettings();
            settings.ColorValuesChanged += OnClolorValuesChanged;
            Initialize();
        }

        private static void Initialize()
        {
            SystemAccent = GetBrush(settings.GetColorValue(UIColorType.Accent));
            SystemAccentDark1 = GetBrush(settings.GetColorValue(UIColorType.AccentDark1));
            SystemAccentDark2 = GetBrush(settings.GetColorValue(UIColorType.AccentDark2));
            SystemAccentDark3 = GetBrush(settings.GetColorValue(UIColorType.AccentDark3));
            SystemAccentLight1 = GetBrush(settings.GetColorValue(UIColorType.AccentLight1));
            SystemAccentLight2 = GetBrush(settings.GetColorValue(UIColorType.AccentLight2));
            SystemAccentLight3 = GetBrush(settings.GetColorValue(UIColorType.AccentLight3));
        }

        private static SolidColorBrush GetBrush(Windows.UI.Color color)
        {
            return new SolidColorBrush(Color.FromArgb(color.A, color.R, color.G, color.B));
        }

        #region Event Handlers

        private static void OnClolorValuesChanged(UISettings sender, object args)
        {
            Application.Current.Dispatcher.Invoke(() =>
            {
                Initialize();
            });
        }

        private static void OnStaticPropertyChanged([CallerMemberName] string propertyName = null)
        {
            StaticPropertyChanged?.Invoke(null, new PropertyChangedEventArgs(propertyName));
        }

        #endregion

        #region Brushes

        public static SolidColorBrush SystemAccent
        {
            get => systemAccent;
            set
            {
                systemAccent = value;
                OnStaticPropertyChanged();
            }
        }

        public static SolidColorBrush SystemAccentDark1
        {
            get => systemAccentDark1;
            set
            {
                systemAccentDark1 = value;
                OnStaticPropertyChanged();
            }
        }

        public static SolidColorBrush SystemAccentDark2
        {
            get => systemAccentDark2;
            set
            {
                systemAccentDark2 = value;
                OnStaticPropertyChanged();
            }
        }

        public static SolidColorBrush SystemAccentDark3
        {
            get => systemAccentDark3;
            set
            {
                systemAccentDark3 = value;
                OnStaticPropertyChanged();
            }
        }

        public static SolidColorBrush SystemAccentLight1
        {
            get => systemAccentLight1;
            set
            {
                systemAccentLight1 = value;
                OnStaticPropertyChanged();
            }
        }

        public static SolidColorBrush SystemAccentLight2
        {
            get => systemAccentLight2;
            set
            {
                systemAccentLight2 = value;
                OnStaticPropertyChanged();
            }
        }

        public static SolidColorBrush SystemAccentLight3
        {
            get => systemAccentLight3;
            set
            {
                systemAccentLight3 = value;
                OnStaticPropertyChanged();
            }
        }

        #endregion
    }

@krlvm
Copy link
Author

krlvm commented Oct 12, 2021

@Extrimis thank you for this important suggestion, it is even more important because my proposed method did not work at all due to the fact that I did not notice that OnStaticPropertyChanged takes a property name as an argument.

If someone also ran into an issue where the accent color is updated repeatedly in a short amount of time, add a propertyName check to the EventArgs, it should be equal to ImmersiveSystemAccentLight3Brush (the last property to change).

@pa-0
Copy link

pa-0 commented Oct 7, 2024

@krlvm Does this pull request still apply then?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants