控件名:Magnifier
作 者:WPFDevelopersOrg - 驚鏵
原文链接[1]:https://github.com/WPFDevelopersOrg/WPFDevelopers
框架使用
.NET40
;Visual Studio 2019
;实现此功能需要用到
VisualBrush
,放大镜展现使用Canvas
->Ellipse
.可以使用
VisualBrush
创建放大效果。设置
Visual
获取或设置画笔的内容。设置
ViewboxUnits
Absolute
坐标系与边界框无关。设置
Viewbox
获取或设置TileBrush
图块中内容的位置和尺寸。
当鼠标移动获取当前坐标点修改
VisualBrush
的Viewbox
。鼠标移动修改
Ellipse
的Canvas.Left
与Canvas.Top
跟随鼠标。接着上一篇把放大镜做成控件方便使用。
新建
Magnifier
获取父控件,为父控件创建装饰器把Magnifier
添加到装饰器Child
。需注意当鼠标移动获取在父控件上获取
Visual
的偏移量VisualTreeHelper.GetOffset
。
1) Magnifier.xaml
代码如下:
<Style TargetType="{x:Type controls:Magnifier}" BasedOn="{StaticResource ControlBasicStyle}"><Setter Property="HorizontalAlignment" Value="Left"/><Setter Property="VerticalAlignment" Value="Top"/><Setter Property="IsHitTestVisible" Value="False" /><Setter Property="Width" Value="200"/><Setter Property="Height" Value="200"/><Setter Property="BorderThickness" Value="8"/><Setter Property="BorderBrush" Value="{DynamicResource PrimaryNormalSolidColorBrush}"/><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="{x:Type controls:Magnifier}"><Canvas Name="PART_Canvas"><Borderx:Name="PART_Border"BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}"Height="{TemplateBinding Height}" Width="{TemplateBinding Height}"CornerRadius="{TemplateBinding CornerRadius}"><Ellipse><Ellipse.Fill><VisualBrush x:Name="PART_VisualBrush"Visual="{Binding ParentTarget,RelativeSource={RelativeSource TemplatedParent}}" ViewboxUnits="Absolute" /></Ellipse.Fill></Ellipse></Border></Canvas></ControlTemplate></Setter.Value></Setter></Style>
2) Magnifier.xaml.cs
代码如下:
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using WPFDevelopers.Utilities;namespace WPFDevelopers.Controls
{[TemplatePart(Name = BorderTemplateName, Type = typeof(Border))][TemplatePart(Name = VisualBrushTemplateName, Type = typeof(VisualBrush))]public class Magnifier : Control{private const string BorderTemplateName = "PART_Border";private const string VisualBrushTemplateName = "PART_VisualBrush";public static Magnifier Default = new Magnifier();public static readonly DependencyProperty CornerRadiusProperty =DependencyProperty.Register("CornerRadius", typeof(CornerRadius), typeof(Magnifier), new PropertyMetadata(new CornerRadius(0)));public static readonly DependencyProperty ParentTargetProperty =DependencyProperty.Register("ParentTarget", typeof(FrameworkElement), typeof(Magnifier),new PropertyMetadata(default, OnParentTargetChanged));public static readonly DependencyProperty AddProperty =DependencyProperty.RegisterAttached("Add", typeof(Magnifier), typeof(Magnifier),new PropertyMetadata(default, OnAddChanged));private AdornerContainer _adornerContainer;private Border _border;private double _factor = 0.5;private VisualBrush _visualBrush = new VisualBrush();public CornerRadius CornerRadius{get => (CornerRadius)GetValue(CornerRadiusProperty);set => SetValue(CornerRadiusProperty, value);}public FrameworkElement ParentTarget{get => (FrameworkElement)GetValue(ParentTargetProperty);set => SetValue(ParentTargetProperty, value);}private static void OnParentTargetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e){var magnifier = (Magnifier)d;magnifier.OnParentTargetChanged((FrameworkElement)e.NewValue);}private void OnParentTargetChanged(FrameworkElement element){if (element == null) return;element.Unloaded -= Element_Unloaded;element.Unloaded += Element_Unloaded;element.MouseEnter -= Element_MouseEnter;element.MouseEnter += Element_MouseEnter;element.MouseLeave -= Element_MouseLeave;element.MouseLeave += Element_MouseLeave;element.MouseMove -= Element_MouseMove;element.MouseMove += Element_MouseMove;element.MouseWheel -= Element_MouseWheel;element.MouseWheel += Element_MouseWheel;}private void Element_MouseWheel(object sender, MouseWheelEventArgs e){if (e.Delta > 0)_factor -= 0.2;else_factor += 0.2;_factor = _factor < 0.2 ? 0.2 : _factor;_factor = _factor > 1 * 4 ? 4 : _factor;MoveMagnifier();}private void Element_MouseLeave(object sender, MouseEventArgs e){if (_adornerContainer == null) return;var layer = AdornerLayer.GetAdornerLayer(ParentTarget);if (layer != null) layer.Remove(_adornerContainer);if (_adornerContainer != null){_adornerContainer.Child = null;_adornerContainer = null;}}private void Element_Unloaded(object sender, RoutedEventArgs e){if (sender is FrameworkElement element)element.Unloaded -= Element_Unloaded;}private void Element_MouseMove(object sender, MouseEventArgs e){MoveMagnifier();}private void MoveMagnifier(){if (_border == null) return;var length = Width * _factor;var radius = length / 2;var parentTargetPoint = Mouse.GetPosition(ParentTarget);var parentTargetVector = VisualTreeHelper.GetOffset(ParentTarget);var size = new Size(length, length);var viewboxRect =new Rect(new Point(parentTargetPoint.X - radius + parentTargetVector.X,parentTargetPoint.Y - radius + parentTargetVector.Y), size);_visualBrush.Viewbox = viewboxRect;var adornerPoint = Mouse.GetPosition(_adornerContainer);_border.SetValue(Canvas.LeftProperty, adornerPoint.X - Width / 2);_border.SetValue(Canvas.TopProperty, adornerPoint.Y - Height / 2);}private void Element_MouseEnter(object sender, MouseEventArgs e){ParentTarget.Cursor = Cursors.Cross;if (_adornerContainer == null){var layer = AdornerLayer.GetAdornerLayer(ParentTarget);if (layer == null) return;_adornerContainer = new AdornerContainer(layer){Child = this};layer.Add(_adornerContainer);}}public static Magnifier GetAdd(DependencyObject obj){return (Magnifier)obj.GetValue(AddProperty);}public static void SetAdd(DependencyObject obj, int value){obj.SetValue(AddProperty, value);}private static void OnAddChanged(DependencyObject d, DependencyPropertyChangedEventArgs e){if (d is FrameworkElement parent){var element = (Magnifier)e.NewValue;element.OnAddChanged(parent);}}private void OnAddChanged(FrameworkElement parent){ParentTarget = parent;}public override void OnApplyTemplate(){base.OnApplyTemplate();CornerRadius = new CornerRadius(Width / 2);_border = GetTemplateChild(BorderTemplateName) as Border;_visualBrush = GetTemplateChild(VisualBrushTemplateName) as VisualBrush ?? new VisualBrush();}}
}
1) MagnifierExample.xaml
代码如下:
<Image Source="/Images/Craouse/0.jpg" Stretch="None"wpfdev:Magnifier.Add="{x:Static wpfdev:Magnifier.Default}"/>
参考资料
[1]
原文链接: https://github.com/WPFDevelopersOrg/WPFDevelopers