From ec3c74ff27a2533ecf95954fbdd76b56a93b6bf2 Mon Sep 17 00:00:00 2001 From: Dirkster99 Date: Sun, 30 Aug 2020 21:10:38 +0200 Subject: [PATCH] Fix Issue #189 Rolling back removal of DctionaryTheme class with additional documentation for its usage. --- README.md | 1 + .../Controls/LayoutFloatingWindowControl.cs | 40 +++++++++++---- .../AvalonDock/Controls/NavigatorWindow.cs | 32 +++++++++--- .../AvalonDock/Controls/OverlayWindow.cs | 41 +++++++++++---- .../Components/AvalonDock/DockingManager.cs | 42 ++++++++++++---- .../AvalonDock/Themes/DictionaryTheme.cs | 50 +++++++++++++++++++ 6 files changed, 168 insertions(+), 38 deletions(-) create mode 100644 source/Components/AvalonDock/Themes/DictionaryTheme.cs diff --git a/README.md b/README.md index b653144e..9cf05dc7 100644 --- a/README.md +++ b/README.md @@ -134,6 +134,7 @@ to also theme standard elements, such as, button and textblock etc. - Removed the additional [ToolTip](https://github.com/Dirkster99/AvalonDock/commit/5554de5c4bfadc37f974ba29803dc792b54f00d0) and [ContextMenu](https://github.com/Dirkster99/AvalonDock/commit/103e1068bc9f5bae8fef275a0e785393b4115764) styles from the Generic.xaml in VS2013 [more details here](https://github.com/Dirkster99/AvalonDock/pull/170#issuecomment-674253874) +- [#189 Removal of DictionaryTheme breaks my application](https://github.com/Dirkster99/AvalonDock/issues/189) (thanx to [hamohn](https://github.com/hamohn)) ## Fixes & Features added in Version 4.3 diff --git a/source/Components/AvalonDock/Controls/LayoutFloatingWindowControl.cs b/source/Components/AvalonDock/Controls/LayoutFloatingWindowControl.cs index a1dffba6..0a36a813 100644 --- a/source/Components/AvalonDock/Controls/LayoutFloatingWindowControl.cs +++ b/source/Components/AvalonDock/Controls/LayoutFloatingWindowControl.cs @@ -1,4 +1,4 @@ -/************************************************************************ +/************************************************************************ AvalonDock Copyright (C) 2007-2013 Xceed Software Inc. @@ -36,7 +36,7 @@ namespace AvalonDock.Controls public abstract class LayoutFloatingWindowControl : Window, ILayoutControl { #region fields - + private ResourceDictionary currentThemeResourceDictionary; // = null private bool _isInternalChange; //false private readonly ILayoutElement _model; private bool _attachDrag = false; @@ -246,22 +246,40 @@ public double ContentMinWidth #endregion Properties #region Internal Methods - + /// Is Invoked when AvalonDock's WPF Theme changes via the method. + /// internal virtual void UpdateThemeResources(Theme oldTheme = null) { - if (oldTheme != null) + if (oldTheme != null) // Remove the old theme if present { - var resourceDictionaryToRemove = - Resources.MergedDictionaries.FirstOrDefault(r => r.Source == oldTheme.GetResourceUri()); - if (resourceDictionaryToRemove != null) - Resources.MergedDictionaries.Remove( - resourceDictionaryToRemove); + if (oldTheme is DictionaryTheme) + { + if (currentThemeResourceDictionary != null) + { + Resources.MergedDictionaries.Remove(currentThemeResourceDictionary); + currentThemeResourceDictionary = null; + } + } + else + { + var resourceDictionaryToRemove = + Resources.MergedDictionaries.FirstOrDefault(r => r.Source == oldTheme.GetResourceUri()); + if (resourceDictionaryToRemove != null) + Resources.MergedDictionaries.Remove( + resourceDictionaryToRemove); + } } + // Implicit parameter to this method is the new theme already set here var manager = _model.Root?.Manager; if (manager?.Theme == null) return; - - Resources.MergedDictionaries.Add(new ResourceDictionary { Source = manager.Theme.GetResourceUri() }); + if (manager.Theme is DictionaryTheme dictionaryTheme) + { + currentThemeResourceDictionary = dictionaryTheme.ThemeResourceDictionary; + Resources.MergedDictionaries.Add(currentThemeResourceDictionary); + } + else + Resources.MergedDictionaries.Add(new ResourceDictionary { Source = manager.Theme.GetResourceUri() }); } internal void AttachDrag(bool onActivated = true) diff --git a/source/Components/AvalonDock/Controls/NavigatorWindow.cs b/source/Components/AvalonDock/Controls/NavigatorWindow.cs index 8c808a7d..f488d12f 100644 --- a/source/Components/AvalonDock/Controls/NavigatorWindow.cs +++ b/source/Components/AvalonDock/Controls/NavigatorWindow.cs @@ -1,4 +1,4 @@ -/************************************************************************ +/************************************************************************ AvalonDock Copyright (C) 2007-2013 Xceed Software Inc. @@ -28,6 +28,7 @@ namespace AvalonDock.Controls public class NavigatorWindow : Window { #region fields + private ResourceDictionary currentThemeResourceDictionary; // = null private const string PART_AnchorableListBox = "PART_AnchorableListBox"; private const string PART_DocumentListBox = "PART_DocumentListBox"; @@ -286,17 +287,36 @@ protected override void OnPreviewKeyUp(System.Windows.Input.KeyEventArgs e) /// The new value for the property. protected void SetDocuments(LayoutDocumentItem[] value) => SetValue(DocumentsPropertyKey, value); + /// Is Invoked when AvalonDock's WPF Theme changes via the method. + /// internal void UpdateThemeResources(Theme oldTheme = null) { - if (oldTheme != null) + if (oldTheme != null) // Remove the old theme if present { - var resourceDictionaryToRemove = Resources.MergedDictionaries.FirstOrDefault(r => r.Source == oldTheme.GetResourceUri()); - if (resourceDictionaryToRemove != null) Resources.MergedDictionaries.Remove(resourceDictionaryToRemove); + if (oldTheme is DictionaryTheme) + { + if (currentThemeResourceDictionary != null) + { + Resources.MergedDictionaries.Remove(currentThemeResourceDictionary); + currentThemeResourceDictionary = null; + } + } + else + { + var resourceDictionaryToRemove = Resources.MergedDictionaries.FirstOrDefault(r => r.Source == oldTheme.GetResourceUri()); + if (resourceDictionaryToRemove != null) Resources.MergedDictionaries.Remove(resourceDictionaryToRemove); + } } + // Implicit parameter to this method is the new theme already set here if (_manager.Theme == null) return; - - Resources.MergedDictionaries.Add(new ResourceDictionary() { Source = _manager.Theme.GetResourceUri() }); + if (_manager.Theme is DictionaryTheme dictionaryTheme) + { + currentThemeResourceDictionary = dictionaryTheme.ThemeResourceDictionary; + Resources.MergedDictionaries.Add(currentThemeResourceDictionary); + } + else + Resources.MergedDictionaries.Add(new ResourceDictionary() { Source = _manager.Theme.GetResourceUri() }); } internal void SelectNextDocument() diff --git a/source/Components/AvalonDock/Controls/OverlayWindow.cs b/source/Components/AvalonDock/Controls/OverlayWindow.cs index d5e64062..4ad7d5b4 100644 --- a/source/Components/AvalonDock/Controls/OverlayWindow.cs +++ b/source/Components/AvalonDock/Controls/OverlayWindow.cs @@ -1,4 +1,4 @@ -/************************************************************************ +/************************************************************************ AvalonDock Copyright (C) 2007-2013 Xceed Software Inc. @@ -25,6 +25,7 @@ namespace AvalonDock.Controls public class OverlayWindow : Window, IOverlayWindow { #region fields + private ResourceDictionary currentThemeResourceDictionary; // = null private Canvas _mainCanvasPanel; private Grid _gridDockingManagerDropTargets; // Showing and activating 4 outer drop taget buttons over DockingManager @@ -169,21 +170,41 @@ protected override void OnClosing(System.ComponentModel.CancelEventArgs e) #endregion Overrides #region Internal Methods - + /// Is Invoked when AvalonDock's WPF Theme changes via the method. + /// internal void UpdateThemeResources(Theme oldTheme = null) { - if (oldTheme != null) + if (oldTheme != null) // Remove the old theme if present { - var resourceDictionaryToRemove = - Resources.MergedDictionaries.FirstOrDefault(r => r.Source == oldTheme.GetResourceUri()); - if (resourceDictionaryToRemove != null) - Resources.MergedDictionaries.Remove( - resourceDictionaryToRemove); + if (oldTheme is DictionaryTheme) + { + if (currentThemeResourceDictionary != null) + { + Resources.MergedDictionaries.Remove(currentThemeResourceDictionary); + currentThemeResourceDictionary = null; + } + } + else + { + var resourceDictionaryToRemove = + Resources.MergedDictionaries.FirstOrDefault(r => r.Source == oldTheme.GetResourceUri()); + if (resourceDictionaryToRemove != null) + Resources.MergedDictionaries.Remove( + resourceDictionaryToRemove); + } } - if (_host.Manager.Theme != null) + if (_host.Manager.Theme != null) // Implicit parameter to this method is the new theme already set here { - Resources.MergedDictionaries.Add(new ResourceDictionary() { Source = _host.Manager.Theme.GetResourceUri() }); + if (_host.Manager.Theme is DictionaryTheme theme) + { + currentThemeResourceDictionary = theme.ThemeResourceDictionary; + Resources.MergedDictionaries.Add(currentThemeResourceDictionary); + } + else + { + Resources.MergedDictionaries.Add(new ResourceDictionary() { Source = _host.Manager.Theme.GetResourceUri() }); + } } } diff --git a/source/Components/AvalonDock/DockingManager.cs b/source/Components/AvalonDock/DockingManager.cs index 3909e684..f42c91fd 100644 --- a/source/Components/AvalonDock/DockingManager.cs +++ b/source/Components/AvalonDock/DockingManager.cs @@ -1,4 +1,4 @@ -/************************************************************************ +/************************************************************************ AvalonDock Copyright (C) 2007-2013 Xceed Software Inc. @@ -42,6 +42,9 @@ namespace AvalonDock public class DockingManager : Control, IOverlayWindowHost//, ILogicalChildrenContainer { #region fields + // ShortCut to current AvalonDock theme if OnThemeChanged() is invoked with DictionaryTheme instance + // in e.OldValue and e.NewValue of the passed event + private ResourceDictionary currentThemeResourceDictionary; private AutoHideWindowManager _autoHideWindowManager; private FrameworkElement _autohideArea; @@ -1029,24 +1032,41 @@ protected virtual void OnThemeChanged(DependencyPropertyChangedEventArgs e) { var oldTheme = e.OldValue as Theme; var resources = Resources; - if (oldTheme != null) + if (oldTheme != null) // remove old theme from resource dictionary if present { - var resourceDictionaryToRemove = - resources.MergedDictionaries.FirstOrDefault(r => r.Source == oldTheme.GetResourceUri()); - if (resourceDictionaryToRemove != null) - resources.MergedDictionaries.Remove( - resourceDictionaryToRemove); + if (oldTheme is DictionaryTheme) // We are using AvalonDock's own DictionaryTheme class + { + if (currentThemeResourceDictionary != null) + { + resources.MergedDictionaries.Remove(currentThemeResourceDictionary); + currentThemeResourceDictionary = null; + } + } + else // We are using standard ResourceDictionaries + { // Lockup the old theme and remove it from resource dictionary + var resourceDictionaryToRemove = + resources.MergedDictionaries.FirstOrDefault(r => r.Source == oldTheme.GetResourceUri()); + if (resourceDictionaryToRemove != null) + resources.MergedDictionaries.Remove( + resourceDictionaryToRemove); + } } - if (e.NewValue as Theme != null) + if (e.NewValue as Theme != null) // Add new theme into resource dictionary if present { - resources.MergedDictionaries.Add(new ResourceDictionary { Source = (e.NewValue as Theme).GetResourceUri() }); + if (e.NewValue as Theme is DictionaryTheme theme) + { + currentThemeResourceDictionary = theme.ThemeResourceDictionary; + resources.MergedDictionaries.Add(currentThemeResourceDictionary); + } + else // We are using standard ResourceDictionaries -> Add new theme resource + resources.MergedDictionaries.Add(new ResourceDictionary { Source = (e.NewValue as Theme).GetResourceUri() }); } - foreach (var fwc in _fwList) + foreach (var fwc in _fwList) // Update theme resources in floating window controls fwc.UpdateThemeResources(oldTheme); - _navigatorWindow?.UpdateThemeResources(); + _navigatorWindow?.UpdateThemeResources(); // Update theme resources in related AvalonDock controls _overlayWindow?.UpdateThemeResources(); } diff --git a/source/Components/AvalonDock/Themes/DictionaryTheme.cs b/source/Components/AvalonDock/Themes/DictionaryTheme.cs new file mode 100644 index 00000000..fa8c5ac9 --- /dev/null +++ b/source/Components/AvalonDock/Themes/DictionaryTheme.cs @@ -0,0 +1,50 @@ +/************************************************************************ + AvalonDock + + Copyright (C) 2007-2013 Xceed Software Inc. + + This program is provided to you under the terms of the Microsoft Public + License (Ms-PL) as published at https://opensource.org/licenses/MS-PL + ************************************************************************/ + +using System; +using System.Windows; + +namespace AvalonDock.Themes +{ + /// Defines a base class to implement a method for storing the current AvalonDock theme + /// that provides a XAML Uri pointing to a . + /// + /// This class can be used to create customized themes by loading a + /// from an existing theme (by using theme.GetResourceUri()), and then replacing some key colors + /// (typically the "Accent" colors). + /// + /// See Issue https://github.com/Dirkster99/AvalonDock/issues/189 for more details. + public abstract class DictionaryTheme : Theme + { + #region Constructors + /// Class constructor + public DictionaryTheme() + { + } + + /// Class constructor from theme specific resource dictionary. + /// + public DictionaryTheme(ResourceDictionary themeResourceDictionary) + { + this.ThemeResourceDictionary = themeResourceDictionary; + } + + #endregion Constructors + + /// Gets the resource dictionary that is associated with this AvalonDock theme. + public ResourceDictionary ThemeResourceDictionary { get; private set; } + + /// Gets the of the XAML that contains the definition for this AvalonDock theme. + /// of the XAML that contains the definition for this custom AvalonDock theme + public override Uri GetResourceUri() + { + return null; + } + } +}