-
框架使用 .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">
<Border
x: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}"/>