diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Application.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Application.cs index d28872bdda3..ba2acda59f1 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Application.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Application.cs @@ -932,14 +932,15 @@ public ResourceDictionary Resources oldValue.RemoveOwner(this); } - if(ThemeManager.DeferredAppThemeLoading && !_resourcesInitialized) + if(_reloadFluentDictionary && !_resourcesInitialized) { if(value != null) { var uri = ThemeManager.GetThemeResource(ThemeMode); value.MergedDictionaries.Insert(0, new ResourceDictionary() { Source = uri }); + ThemeManager.SkipAppThemeModeSyncing = true; } - ThemeManager.DeferredAppThemeLoading = false; + _reloadFluentDictionary = false; } if (value != null) @@ -960,6 +961,11 @@ public ResourceDictionary Resources { InvalidateResourceReferences(new ResourcesChangeInfo(oldValue, value)); } + + if(ThemeManager.SkipAppThemeModeSyncing) + { + ThemeManager.SkipAppThemeModeSyncing = false; + } } } @@ -993,7 +999,9 @@ public ThemeMode ThemeMode // If the resources are not initializd, // fluent dictionary included will be reset. // Hence, deferring the step. - ThemeManager.DeferredAppThemeLoading = true; + ThemeManager.OnApplicationThemeChanged(oldValue, value); + _reloadFluentDictionary = true; + _resourcesInitialized = false; return; } @@ -1732,20 +1740,19 @@ internal int RunInternal(Window window) internal void InvalidateResourceReferences(ResourcesChangeInfo info) { - _resourcesInitialized = true; // Sync needs to be performed only under the following conditions: // - the resource change event raised is due to a collection change // i.e. it is not a IsIndividualResourceAddOperation // - the event is not raised due to the change in Application.ThemeMode // i.e. SkipAppThemeModeSyncing is set to true - // - if application's ThemeMode and Resources sync is enabled. - // i.e. IsAppThemeModeSyncEnabled is set to true - if (!ThemeManager.SkipAppThemeModeSyncing - && ThemeManager.IsAppThemeModeSyncEnabled) + if (!info.IsIndividualResourceAddOperation + && !ThemeManager.SkipAppThemeModeSyncing) { - ThemeManager.SyncThemeMode(); + ThemeManager.SyncThemeMode(info); } + + _resourcesInitialized = true; // Invalidate ResourceReference properties on all the windows. // we Clone() the collection b/c if we don't then some other thread can be @@ -2490,6 +2497,7 @@ private object RunDispatcher(object ignore) private ThemeMode _themeMode = ThemeMode.None; private bool _resourcesInitialized = false; + private bool _reloadFluentDictionary = false; private SecurityCriticalDataForSet _appMimeType; private IServiceProvider _serviceProvider; diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/ResourcesChangeInfo.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/ResourcesChangeInfo.cs index f8da008998b..ba09970dc8c 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/ResourcesChangeInfo.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/ResourcesChangeInfo.cs @@ -85,6 +85,20 @@ internal ResourcesChangeInfo( #endregion Constructors + #region Internal Properties + + internal IEnumerable OldDictionaries + { + get { return _oldDictionaries; } + } + + internal IEnumerable NewDictionaries + { + get { return _newDictionaries; } + } + + #endregion + #region Operations /// @@ -199,6 +213,11 @@ internal bool IsResourceAddOperation get { return _key != null || (_newDictionaries != null && _newDictionaries.Count > 0); } } + internal bool IsIndividualResourceAddOperation + { + get { return _key != null; } + } + // This member is used to identify the container when a style change happens internal DependencyObject Container { diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/ThemeManager.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/ThemeManager.cs index d60eb222068..6f105676fc6 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/ThemeManager.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/ThemeManager.cs @@ -125,8 +125,14 @@ internal static void OnWindowThemeChanged(Window window, ThemeMode oldThemeMode, ApplyFluentOnWindow(window); } - internal static bool SyncThemeMode() + internal static bool SyncThemeMode(ResourcesChangeInfo info) { + if (!ContainsFluentThemeDictionary(info.OldDictionaries) + && !ContainsFluentThemeDictionary(info.NewDictionaries)) + { + return false; + } + ThemeMode themeMode = GetThemeModeFromResourceDictionary(Application.Current.Resources); if (Application.Current.ThemeMode != themeMode) @@ -137,46 +143,6 @@ internal static bool SyncThemeMode() return false; } - internal static void SyncThemeModeAndResources() - { - // Since, this is called from window there is a possiblity that the application - // instance is null. Hence, we need to check for null. - if(Application.Current == null) - return; - - ThemeMode themeMode = Application.Current.ThemeMode; - var rd = Application.Current.Resources; - - bool resyncThemeMode = false; - int index = LastIndexOfFluentThemeDictionary(rd); - - if (index == -1) - { - // This means that ThemeMode was set but Resources were not set during initialization. - // Hence we need to resync. - if (themeMode != ThemeMode.None) - { - resyncThemeMode = true; - } - } - else - { - // If index > 0, then Fluent theme dictionary was added manually. - // If ThemeMode is None, and yet there is a Fluent theme dictionary, hence that was manually set. - // Hence we need to resync. - if (index > 0 || themeMode == ThemeMode.None) - { - themeMode = GetThemeModeFromSourceUri(rd.MergedDictionaries[index].Source); - resyncThemeMode = true; - } - } - - if (resyncThemeMode) - { - Application.Current.ThemeMode = themeMode; - } - } - internal static void ApplyStyleOnWindow(Window window) { if (!IsFluentThemeEnabled && window.ThemeMode == ThemeMode.None) @@ -316,8 +282,6 @@ private static void ApplyStyleOnWindow(Window window, bool useLightColors) #region Internal Properties - internal static bool IsAppThemeModeSyncEnabled { get; set; } = false; - internal static bool IsFluentThemeEnabled { get @@ -328,8 +292,6 @@ internal static bool IsFluentThemeEnabled } } - internal static bool DeferredAppThemeLoading { get; set; } = false; - internal static bool SkipAppThemeModeSyncing { get; set; } = false; internal static double DefaultFluentThemeFontSize => 14; @@ -446,6 +408,26 @@ private static int LastIndexOfFluentThemeDictionary(ResourceDictionary rd) return -1; } + private static bool ContainsFluentThemeDictionary(IEnumerable dictionaries) + { + if(dictionaries == null) + return false; + + foreach (var dictionary in dictionaries) + { + if (dictionary.Source != null) + { + if (dictionary.Source.ToString().StartsWith(FluentThemeResourceDictionaryUri, + StringComparison.OrdinalIgnoreCase)) + { + return true; + } + } + } + + return false; + } + private static IEnumerable FindAllFluentThemeResourceDictionaryIndices(ResourceDictionary rd) { ArgumentNullException.ThrowIfNull(rd, nameof(rd)); diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Window.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Window.cs index 9f467d192d2..ded2795107a 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Window.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Window.cs @@ -2558,24 +2558,9 @@ internal void CreateSourceWindow(bool duringShow) if (Standard.Utility.IsOSWindows10OrNewer) { - if(!ThemeManager.IsAppThemeModeSyncEnabled) - { - ThemeManager.SyncThemeModeAndResources(); - ThemeManager.IsAppThemeModeSyncEnabled = true; - } - if(ThemeManager.IsFluentThemeEnabled) { - - if(ThemeManager.DeferredAppThemeLoading) - { - ThemeManager.OnApplicationThemeChanged(ThemeMode.None, Application.Current.ThemeMode); - ThemeManager.DeferredAppThemeLoading = false; - } - else - { - ThemeManager.ApplyStyleOnWindow(this); - } + ThemeManager.ApplyStyleOnWindow(this); } if(_deferThemeLoading)