WPF中画布Canvas控件中内容缩放(扩展控件)

本文介绍如何在WPF中实现Canvas控件内容的缩放,避免使用Border进行缩放,而是监听MouseWheel事件,遍历子控件进行缩放。通过创建CanvasEx扩展控件,实现拖拽和缩放功能,详细解析缩放的核心方法ZoomBehavior,提供了一种矩阵变换的解决方案。
摘要由CSDN通过智能技术生成

WPF中画布Canvas控件中内容缩放

1. Transform Class 简介

Transform类位于命名空间System.Windows.Media下。在WPF中Transform类被广泛应用于绘图元素的变换。作为大部分可视化控件的基类,UIElement类具有这样的静态依赖属性:


// System.Windows.UIElement

public Transform RenderTransform
{
   
	get
	{
   
		return (Transform)base.GetValue(UIElement.RenderTransformProperty);
	}
	set
	{
   
		base.SetValue(UIElement.RenderTransformProperty, value);
	}
}

[CommonDependencyProperty]
public static readonly DependencyProperty RenderTransformProperty = 
	DependencyProperty.Register("RenderTransform", typeof(Transform), typeof(UIElement), new PropertyMetadata(Transform.Identity, new PropertyChangedCallback(UIElement.RenderTransform_Changed)));

private static void RenderTransform_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
   
	UIElement uielement = (UIElement)d;
	if (!uielement.NeverMeasured && !uielement.NeverArranged && !e.IsASubPropertyChange)
	{
   
		uielement.InvalidateArrange();
		uielement.AreTransformsClean = false;
	}
}

官方文档的注解

A render transform does not regenerate layout size or render size information. Render transforms are typically intended for animating or applying a temporary effect to an element. For example, the element might zoom when focused or moused over, or might jitter on load to draw the eye to that part of the user interface (UI).

故可以通过更改UIElement的RenderTransform属性达到控件变换的目的,且开销较小。
注意到Transform类为抽象类,派生类型有:

  • System.Windows.Media.MatrixTransform
  • System.Windows.Media.TranslateTransform
  • System.Windows.Media.RotateTransform
  • System.Windows.Media.ScaleTransform
  • System.Windows.Media.SkewTransform
  • System.Windows.Media.TransformGroup

由于继承自System.Windows.Media.Transform ,上述各种变换中都具有Value的只读属性,其返回 Matrix 结构。

2. 画布Canvas控件中内容缩放方法简述

网上存在一些解决方案,是通过给Canvas外层添加Border,缩放变换Canvas本省来达到缩放的目的。该方法无法控制Canvas中某一控件不缩放,或各控件非同时缩放,故这里不使用该方法进行缩放,而是监听Canvas的MouseWheel事件并遍历Canvas.Children,对子控件单独控制。控制的基本思想在于,为子控件附加CanZoom附加属性,并附加子控件各自的缩放信息,以此为根据进行缩放变换。
为方便起见,下节直接构造一个新的布局控件 CanvasEx ,其继承于Canvas。

3. CanvasEx具体实现及解读

废话不多说,先上代码:

public class CanvasEx : Canvas
{
   
	private bool _onKeyboardCommand = false;
	private bool _onMouseButtonCommand = false;
	private Point _previousDraggingPoint;

	public static Cursor DragCursor => new Cursor(AppDomain.CurrentDomain.BaseDirectory + "DragHand.cur");
	private Cursor _previousCursor;

	[Browsable(false)]
	private bool IsDragging
	{
   
		get {
    return (bool)GetValue(IsDraggingProperty); }
		set {
    SetValue(IsDraggingProperty, value); }
	}

	// Using a DependencyProperty as the backing store for IsDragging.  This enables animation, styling, binding, etc...
	public static readonly DependencyProperty IsDraggingProperty =
		DependencyProperty.Register("IsDragging", typeof(bool), typeof(CanvasEx), new PropertyMetadata(false));

	[Browsable(false)]
	private bool IsZooming
	{
   
		get {
    return (bool)GetValue(IsZoomingProperty); }
		set {
    SetValue(IsZoomingProperty, value); }
	}

	// Using a DependencyProperty as the backing store for IsZooming.  This enables animation, styling, binding, etc...
	public static readonly DependencyProperty IsZoomingProperty =
		DependencyProperty.Register("IsZooming", typeof(bool), typeof(CanvasEx), new PropertyMetadata(false));

	public static bool GetCanDrag(DependencyObject obj)
	{
   
		return (bool)obj.GetValue(CanDragProperty);
	}

	public static void SetCanDrag(DependencyObject obj, bool value)
	{
   
		obj.SetValue(CanDragProperty, value);
	}

	// Using a DependencyProperty as the backing store for CanDrag.  This enables animation, styling, binding, etc...
	public static readonly DependencyProperty CanDragProperty =
		DependencyProperty.RegisterAttached("CanDrag", typeof(bool), typeof(CanvasEx), new PropertyMetadata(false));

	public static 
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值