From d0dc957c8112e88ec67a965a651d821d97c01d3f Mon Sep 17 00:00:00 2001 From: NaBian <836904362@qq.com> Date: Tue, 19 Nov 2019 23:16:24 +0800 Subject: [PATCH] refactor Poptip & Magnifier --- .../Controls/Base/AdornerElement.cs | 87 +++++++++++++++++++ .../Controls/Other/Magnifier.cs | 86 ++++++++---------- .../Controls/Other/Poptip.cs | 64 +++----------- .../HandyControl_Shared.projitems | 1 + 4 files changed, 134 insertions(+), 104 deletions(-) create mode 100644 src/Shared/HandyControl_Shared/Controls/Base/AdornerElement.cs diff --git a/src/Shared/HandyControl_Shared/Controls/Base/AdornerElement.cs b/src/Shared/HandyControl_Shared/Controls/Base/AdornerElement.cs new file mode 100644 index 00000000..c3fa3241 --- /dev/null +++ b/src/Shared/HandyControl_Shared/Controls/Base/AdornerElement.cs @@ -0,0 +1,87 @@ +using System; +using System.ComponentModel; +using System.Windows; +using System.Windows.Controls; +using HandyControl.Data; + +namespace HandyControl.Controls +{ + public abstract class AdornerElement : Control, IDisposable + { + protected FrameworkElement ElementTarget { get; set; } + + public static readonly DependencyProperty TargetProperty = DependencyProperty.Register( + "Target", typeof(FrameworkElement), typeof(AdornerElement), new PropertyMetadata(default(FrameworkElement), OnTargetChanged)); + + private static void OnTargetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var ctl = (AdornerElement)d; + ctl.OnTargetChanged(ctl.ElementTarget, false); + ctl.OnTargetChanged((FrameworkElement)e.NewValue, true); + } + + [Bindable(true), Category("Layout")] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public FrameworkElement Target + { + get => (FrameworkElement) GetValue(TargetProperty); + set => SetValue(TargetProperty, value); + } + + public static readonly DependencyProperty InstanceProperty = DependencyProperty.RegisterAttached( + "Instance", typeof(AdornerElement), typeof(AdornerElement), new PropertyMetadata(default(AdornerElement), OnInstanceChanged)); + + private static void OnInstanceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + if (!(d is FrameworkElement target)) return; + var element = (AdornerElement)e.NewValue; + element.OnInstanceChanged(target); + } + + protected virtual void OnInstanceChanged(FrameworkElement target) => Target = target; + + public static void SetInstance(DependencyObject element, AdornerElement value) + => element.SetValue(InstanceProperty, value); + + public static AdornerElement GetInstance(DependencyObject element) + => (AdornerElement) element.GetValue(InstanceProperty); + + public static readonly DependencyProperty IsInstanceProperty = DependencyProperty.RegisterAttached( + "IsInstance", typeof(bool), typeof(AdornerElement), new PropertyMetadata(ValueBoxes.TrueBox)); + + public static void SetIsInstance(DependencyObject element, bool value) + => element.SetValue(IsInstanceProperty, value); + + public static bool GetIsInstance(DependencyObject element) + => (bool) element.GetValue(IsInstanceProperty); + + protected virtual void OnTargetChanged(FrameworkElement element, bool isNew) + { + if (element == null) return; + + if (!isNew) + { + element.Unloaded -= TargetElement_Unloaded; + ElementTarget = null; + } + else + { + element.Unloaded += TargetElement_Unloaded; + ElementTarget = element; + } + } + + private void TargetElement_Unloaded(object sender, RoutedEventArgs e) + { + if (sender is FrameworkElement element) + { + element.Unloaded -= TargetElement_Unloaded; + Dispose(); + } + } + + protected abstract void Dispose(); + + void IDisposable.Dispose() => Dispose(); + } +} diff --git a/src/Shared/HandyControl_Shared/Controls/Other/Magnifier.cs b/src/Shared/HandyControl_Shared/Controls/Other/Magnifier.cs index 407adeb1..d80c0e26 100644 --- a/src/Shared/HandyControl_Shared/Controls/Other/Magnifier.cs +++ b/src/Shared/HandyControl_Shared/Controls/Other/Magnifier.cs @@ -1,5 +1,4 @@ using System.Windows; -using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; @@ -11,14 +10,12 @@ using HandyControl.Tools.Extension; namespace HandyControl.Controls { [TemplatePart(Name = ElementVisualBrush, Type = typeof(VisualBrush))] - public class Magnifier : Control + public class Magnifier : AdornerElement { + private AdornerContainer _adornerContainer; + private Size _viewboxSize; - private AdornerContainer _adorner; - - private UIElement _elementTarget; - private const string ElementVisualBrush = "PART_VisualBrush"; private VisualBrush _visualBrush = new VisualBrush(); @@ -43,40 +40,8 @@ namespace HandyControl.Controls set => SetValue(VerticalOffsetProperty, value); } - public static readonly DependencyProperty InstanceProperty = DependencyProperty.RegisterAttached( - "Instance", typeof(Magnifier), typeof(Magnifier), new PropertyMetadata(default(Magnifier), OnMagnifierChanged)); - - private static void OnMagnifierChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - if (!(d is UIElement target)) return; - var magnifier = (Magnifier)e.NewValue; - magnifier.Target = target; - } - - public static void SetInstance(DependencyObject element, Magnifier value) - => element.SetValue(InstanceProperty, value); - - public static Magnifier GetInstance(DependencyObject element) - => (Magnifier) element.GetValue(InstanceProperty); - public static Magnifier Default => new Magnifier(); - internal static readonly DependencyProperty TargetProperty = DependencyProperty.Register( - "Target", typeof(UIElement), typeof(Magnifier), new PropertyMetadata(default(UIElement), OnTargetChanged)); - - private static void OnTargetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - var ctl = (Magnifier) d; - ctl.UpdateTarget(ctl._elementTarget, false); - ctl.UpdateTarget((UIElement)e.NewValue, true); - } - - internal UIElement Target - { - get => (UIElement)GetValue(TargetProperty); - set => SetValue(TargetProperty, value); - } - public static readonly DependencyProperty ScaleProperty = DependencyProperty.Register( "Scale", typeof(double), typeof(Magnifier), new PropertyMetadata(5.0, OnScaleChanged), ValidateHelper.IsInRangeOfPosDouble); @@ -111,8 +76,10 @@ namespace HandyControl.Controls private void UpdateViewboxSize() => _viewboxSize = new Size(ActualWidth / Scale, ActualHeight / Scale); - private void UpdateTarget(UIElement element , bool isNew) + protected sealed override void OnTargetChanged(FrameworkElement element , bool isNew) { + base.OnTargetChanged(element, isNew); + if (element == null) return; if (!isNew) @@ -120,17 +87,19 @@ namespace HandyControl.Controls element.MouseEnter -= Element_MouseEnter; element.MouseLeave -= Element_MouseLeave; element.MouseMove -= Element_MouseMove; - _elementTarget = null; + ElementTarget = null; } else { element.MouseEnter += Element_MouseEnter; element.MouseLeave += Element_MouseLeave; element.MouseMove += Element_MouseMove; - _elementTarget = element; + ElementTarget = element; } } + protected override void Dispose() => HideAdornerElement(); + private void UpdateLocation() { var targetPoint = Mouse.GetPosition(Target); @@ -140,33 +109,48 @@ namespace HandyControl.Controls var targetVector = VisualTreeHelper.GetOffset(Target); _visualBrush.Viewbox = new Rect(new Point(subX + targetVector.X, subY + targetVector.Y), _viewboxSize); - var adornerPoint = Mouse.GetPosition(_adorner); + var adornerPoint = Mouse.GetPosition(_adornerContainer); _translateTransform.X = adornerPoint.X + HorizontalOffset; _translateTransform.Y = adornerPoint.Y + VerticalOffset; } private void Element_MouseMove(object sender, MouseEventArgs e) => UpdateLocation(); - private void Element_MouseLeave(object sender, MouseEventArgs e) + private void Element_MouseLeave(object sender, MouseEventArgs e) => HideAdornerElement(); + + private void Element_MouseEnter(object sender, MouseEventArgs e) => ShowAdornerElement(); + + private void HideAdornerElement() { var layer = AdornerLayer.GetAdornerLayer(Target); - if (layer == null) return; - layer.Remove(_adorner); - _adorner.Child = null; - _adorner = null; + if (layer != null) + { + layer.Remove(_adornerContainer); + } + else if(_adornerContainer != null && _adornerContainer.Parent is AdornerLayer parent) + { + parent.Remove(_adornerContainer); + } + + if (_adornerContainer != null) + { + _adornerContainer.Child = null; + _adornerContainer = null; + } } - private void Element_MouseEnter(object sender, MouseEventArgs e) + private void ShowAdornerElement() { - if (_adorner == null) + if (_adornerContainer == null) { var layer = AdornerLayer.GetAdornerLayer(Target); if (layer == null) return; - _adorner = new AdornerContainer(layer) + + _adornerContainer = new AdornerContainer(layer) { Child = this }; - layer.Add(_adorner); + layer.Add(_adornerContainer); } this.Show(); } diff --git a/src/Shared/HandyControl_Shared/Controls/Other/Poptip.cs b/src/Shared/HandyControl_Shared/Controls/Other/Poptip.cs index 65ec968c..4da52653 100644 --- a/src/Shared/HandyControl_Shared/Controls/Other/Poptip.cs +++ b/src/Shared/HandyControl_Shared/Controls/Other/Poptip.cs @@ -1,5 +1,4 @@ using System; -using System.ComponentModel; using System.Windows; using System.Windows.Controls; using System.Windows.Controls.Primitives; @@ -10,12 +9,10 @@ using HandyControl.Data.Enum; namespace HandyControl.Controls { - public class Poptip : Control + public class Poptip : AdornerElement { private readonly Popup _popup; - private UIElement _elementTarget; - public Poptip() { _popup = new Popup @@ -42,15 +39,6 @@ namespace HandyControl.Controls set => SetValue(HitModeProperty, value); } - private static readonly DependencyProperty IsInstanceProperty = DependencyProperty.RegisterAttached( - "IsInstance", typeof(bool), typeof(Poptip), new PropertyMetadata(ValueBoxes.TrueBox)); - - private static void SetIsInstance(DependencyObject element, bool value) - => element.SetValue(IsInstanceProperty, value); - - private static bool GetIsInstance(DependencyObject element) - => (bool) element.GetValue(IsInstanceProperty); - public static readonly DependencyProperty ContentProperty = DependencyProperty.RegisterAttached( "Content", typeof(object), typeof(Poptip), new PropertyMetadata(default, OnContentChanged)); @@ -144,7 +132,7 @@ namespace HandyControl.Controls } else { - GetInstance(d)?.SwitchPoptip((bool)e.NewValue); + ((Poptip)GetInstance(d))?.SwitchPoptip((bool)e.NewValue); } } @@ -160,44 +148,12 @@ namespace HandyControl.Controls set => SetValue(IsOpenProperty, value); } - public static readonly DependencyProperty TargetProperty = DependencyProperty.Register( - "Target", typeof(UIElement), typeof(Poptip), new PropertyMetadata(default(UIElement), OnTargetChanged)); - - private static void OnTargetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - var ctl = (Poptip)d; - ctl.UpdateTarget(ctl._elementTarget, false); - ctl.UpdateTarget((UIElement)e.NewValue, true); - } - - [Bindable(true), Category("Layout")] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public UIElement Target - { - get => (UIElement) GetValue(TargetProperty); - set => SetValue(TargetProperty, value); - } - - public static readonly DependencyProperty InstanceProperty = DependencyProperty.RegisterAttached( - "Instance", typeof(Poptip), typeof(Poptip), new PropertyMetadata(default(Poptip), OnPoptipChanged)); - - private static void OnPoptipChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - if (!(d is UIElement target)) return; - var poptip = (Poptip)e.NewValue; - poptip.Target = target; - } - - public static void SetInstance(DependencyObject element, Poptip value) - => element.SetValue(InstanceProperty, value); - - public static Poptip GetInstance(DependencyObject element) - => (Poptip)element.GetValue(InstanceProperty); - public static Poptip Default => new Poptip(); - private void UpdateTarget(UIElement element, bool isNew) + protected sealed override void OnTargetChanged(FrameworkElement element, bool isNew) { + base.OnTargetChanged(element, isNew); + if (element == null) return; if (!isNew) @@ -206,7 +162,7 @@ namespace HandyControl.Controls element.MouseLeave -= Element_MouseLeave; element.GotFocus -= Element_GotFocus; element.LostFocus -= Element_LostFocus; - _elementTarget = null; + ElementTarget = null; } else { @@ -214,11 +170,13 @@ namespace HandyControl.Controls element.MouseLeave += Element_MouseLeave; element.GotFocus += Element_GotFocus; element.LostFocus += Element_LostFocus; - _elementTarget = element; - _popup.PlacementTarget = _elementTarget; + ElementTarget = element; + _popup.PlacementTarget = ElementTarget; } } + protected override void Dispose() => SwitchPoptip(false); + private void UpdateLocation() { var targetWidth = Target.RenderSize.Width; @@ -233,7 +191,7 @@ namespace HandyControl.Controls var offsetX = .0; var offsetY = .0; - var poptip = GetInstance(Target); + var poptip = (Poptip)GetInstance(Target); var popupPlacement = poptip.Placement; var popupOffset = poptip.Offset; diff --git a/src/Shared/HandyControl_Shared/HandyControl_Shared.projitems b/src/Shared/HandyControl_Shared/HandyControl_Shared.projitems index 9c8cb1eb..6c2ea7c9 100644 --- a/src/Shared/HandyControl_Shared/HandyControl_Shared.projitems +++ b/src/Shared/HandyControl_Shared/HandyControl_Shared.projitems @@ -20,6 +20,7 @@ +