From 62f5677d236ea0807afdc48fd4352443afecc5ed Mon Sep 17 00:00:00 2001 From: h3xds1nz Date: Sat, 20 Jul 2024 20:09:09 +0200 Subject: [PATCH 1/4] replace boxing Hashtable with generic Dictionary --- .../Component/AdornerPresentationContext.cs | 68 ++++++++----------- 1 file changed, 27 insertions(+), 41 deletions(-) diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/Annotations/Component/AdornerPresentationContext.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/Annotations/Component/AdornerPresentationContext.cs index 901bb229d1b..8d811d9fbcc 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/Annotations/Component/AdornerPresentationContext.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/Annotations/Component/AdornerPresentationContext.cs @@ -4,7 +4,7 @@ // // Description: -// AdornerPresentationContext knows that annotation comonents are wrapped +// AdornerPresentationContext knows that annotation components are wrapped // in an AnnotationAdorner and hosted in the AdornerLayer. Note, implementation-wise // a new PresentationContext is created for every annotation component. Executing // operations on a presentation context for a different annotation component @@ -24,7 +24,7 @@ namespace MS.Internal.Annotations.Component { /// - /// AdornerPresentationContext knows that annotation comonents are wrapped in an AnnotationAdorner and hosted in the AdornerLayer. + /// AdornerPresentationContext knows that annotation components are wrapped in an AnnotationAdorner and hosted in the AdornerLayer. /// Note, implementation-wise a new PresentationContext is created for every annotation component. Executing operations on a presentation context /// for a different annotation component (located in the same adorner layer) works, but is slower than using the presentation context stored in the /// annotation component. @@ -108,13 +108,13 @@ internal static void SetTypeZLevel(Type type, int level) Invariant.Assert(type != null, "type is null"); - if (_ZLevel.ContainsKey(type)) + if (s_ZLevel.ContainsKey(type)) { - _ZLevel[type] = level; + s_ZLevel[type] = level; } else { - _ZLevel.Add(type, level); + s_ZLevel.Add(type, level); } } @@ -128,9 +128,9 @@ internal static void SetTypeZLevel(Type type, int level) /// max Z-order value for this level internal static void SetZLevelRange(int level, int min, int max) { - if (_ZRanges[level] == null) + if (s_ZRanges.ContainsKey(level) == false) { - _ZRanges.Add(level, new ZRange(min, max)); + s_ZRanges.Add(level, new ZRange(min, max)); } } @@ -512,12 +512,9 @@ private AnnotationAdorner GetAnnotationAdorner(IAnnotationComponent component) /// ZLevel private static int GetComponentLevel(IAnnotationComponent component) { - int level = 0; Type type = component.GetType(); - if (_ZLevel.ContainsKey(type)) - level = (int)_ZLevel[type]; - return level; + return s_ZLevel.TryGetValue(type, out int value) ? value : 0; } /// @@ -531,18 +528,21 @@ private static int GetComponentLevel(IAnnotationComponent component) private static int ComponentToAdorner(int zOrder, int level) { int res = zOrder; - ZRange range = (ZRange)_ZRanges[level]; - if (range != null) + + if (s_ZRanges.TryGetValue(level, out ZRange range)) { //adjust the Z-order (shift it with the minimal value for this range) //that way the component does need to know the range for its type that is // set by the application. It always sets the z-order as it starts from 0 res += range.Min; + if (res < range.Min) res = range.Min; + if (res > range.Max) res = range.Max; } + return res; } @@ -559,19 +559,17 @@ private static int ComponentToAdorner(int zOrder, int level) /// /// The adornerLayer which contains the annotation component. Basically what the presentation hides. /// - private AdornerLayer _adornerLayer; + private readonly AdornerLayer _adornerLayer; /// - /// The hashtable holds the priority level for each Component type as defined by the application + /// The dictionary holds the priority level for each Component type as defined by the application /// - private static Hashtable _ZLevel = new Hashtable(); + private static readonly Dictionary s_ZLevel = new(); /// /// The ZRanges for the ZLevels. /// - private static Hashtable _ZRanges = new Hashtable(); - - + private static readonly Dictionary s_ZRanges = new(); #endregion Private Fields @@ -581,40 +579,28 @@ private static int ComponentToAdorner(int zOrder, int level) /// This is to control the relationships with TextSelection which lives in the same /// AdornerLayer. Will be removed when more flexible Z-ordering mechanism is available /// - private class ZRange + private sealed class ZRange { public ZRange(int min, int max) { - //exchange values if needed + // Swap values if needed if (min > max) { - int temp = min; + int num = min; min = max; - max = temp; + max = num; } - _min = min; - _max = max; - } - public int Min - { - get - { - return _min; - } - } - public int Max - { - get - { - return _max; - } + Min = min; + Max = max; } - private int _min, _max; + public int Min { get; } + public int Max { get; } + } - #endregion Internal classes + #endregion Private classes } } From 451653296e6c185bd3db15a94a81866cf8dad094 Mon Sep 17 00:00:00 2001 From: h3xds1nz Date: Sun, 21 Jul 2024 10:52:04 +0200 Subject: [PATCH 2/4] reduce additional allocations by making ZRange a readonly struct --- .../Annotations/Component/AdornerPresentationContext.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/Annotations/Component/AdornerPresentationContext.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/Annotations/Component/AdornerPresentationContext.cs index 8d811d9fbcc..0f293abaeeb 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/Annotations/Component/AdornerPresentationContext.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/Annotations/Component/AdornerPresentationContext.cs @@ -579,7 +579,7 @@ private static int ComponentToAdorner(int zOrder, int level) /// This is to control the relationships with TextSelection which lives in the same /// AdornerLayer. Will be removed when more flexible Z-ordering mechanism is available /// - private sealed class ZRange + private readonly struct ZRange { public ZRange(int min, int max) { From c20679331e0c66dbd86258bcbdfa8be19608e13e Mon Sep 17 00:00:00 2001 From: h3xds1nz Date: Sun, 11 Aug 2024 12:45:54 +0200 Subject: [PATCH 3/4] remove check that is not needed --- .../Component/AdornerPresentationContext.cs | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/Annotations/Component/AdornerPresentationContext.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/Annotations/Component/AdornerPresentationContext.cs index 0f293abaeeb..83b5f382c20 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/Annotations/Component/AdornerPresentationContext.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/Annotations/Component/AdornerPresentationContext.cs @@ -100,22 +100,14 @@ internal static void HostComponent(AdornerLayer adornerLayer, IAnnotationCompone /// BringToTop method. This will move the component to the top of its priority group. If there are other /// components with higher priority they will still be on top of that component. If more than /// one component type have the same ZLevel that means they all can stay on top of each other. - /// Setting IAnnotationComponent.ZOrder must be invoked only by the PrezentationContext + /// Setting IAnnotationComponent.ZOrder must be invoked only by the PresentationContext /// when the Z-order changes. It can not be set by application in v1. internal static void SetTypeZLevel(Type type, int level) { Invariant.Assert(level >= 0, "level is < 0"); - Invariant.Assert(type != null, "type is null"); - if (s_ZLevel.ContainsKey(type)) - { - s_ZLevel[type] = level; - } - else - { - s_ZLevel.Add(type, level); - } + s_ZLevel[type] = level; } /// From b5dab8be2dea832a68c9b999952757bbd372cba7 Mon Sep 17 00:00:00 2001 From: h3xds1nz Date: Sun, 11 Aug 2024 14:12:57 +0200 Subject: [PATCH 4/4] seal the class for additional perf benefit --- .../Annotations/Component/AdornerPresentationContext.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/Annotations/Component/AdornerPresentationContext.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/Annotations/Component/AdornerPresentationContext.cs index 83b5f382c20..a152d03c03b 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/Annotations/Component/AdornerPresentationContext.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/Annotations/Component/AdornerPresentationContext.cs @@ -19,7 +19,6 @@ using System.Windows.Annotations; using System.Windows.Documents; using System.Windows.Media; -using System.Collections; namespace MS.Internal.Annotations.Component { @@ -29,7 +28,7 @@ namespace MS.Internal.Annotations.Component /// for a different annotation component (located in the same adorner layer) works, but is slower than using the presentation context stored in the /// annotation component. /// - internal class AdornerPresentationContext : PresentationContext + internal sealed class AdornerPresentationContext : PresentationContext { #region Constructors @@ -120,7 +119,7 @@ internal static void SetTypeZLevel(Type type, int level) /// max Z-order value for this level internal static void SetZLevelRange(int level, int min, int max) { - if (s_ZRanges.ContainsKey(level) == false) + if (!s_ZRanges.ContainsKey(level)) { s_ZRanges.Add(level, new ZRange(min, max)); }