在WPF中的Canvas上实现控件的拖动、缩放

本文介绍了如何在WPF环境中实现Canvas上自定义控件的拖动和缩放功能。通过分析Windows画图工具的行为,创建10个CustomThumb控件以区分不同的操作,并利用WPF的Thumb控件及其DragDelta和DragCompleted事件。通过自定义枚举标识操作意图,以及在构造函数和OnApplyTemplate中设置路由事件订阅,最终实现了一个可拖动和缩放的矩形框控件。
摘要由CSDN通过智能技术生成

   如题,项目中需要实现使用鼠标拖动、缩放一个矩形框,WPF中没有现成的,那就自己造一个轮子:)

   造轮子前先看看Windows自带的画图工具中是怎样做的,如下图:

 

   在被拖动的矩形框四周有9个小框,可以从不同方向拖动来放大缩小矩形框,另外需要注意的是,还有一个框,就是图中虚线的矩形框,这个框,是用来拖动目标控件的;我们要做的,就是模仿画图中的做法,在自定义控件中显示10个框,然后根据鼠标所在的框来处理鼠标输入,实现拖动与放大。

    参考这篇博文继续聊WPF——Thumb控件得知,WPF中有现成的拖动控件,可以提供对应的事件(DragDelta & DragCompleted), 就用它了。

还有一个需要考虑的是,我们的这个自定义控件中有10个不同作用的Thumb控件,如何区分事件从哪个Thumb发出来的呢?这样我们才能知道用户希望的操作是拖动,还是缩放,而且缩放也要知道朝哪个方向缩放。可以使用Tag属性,但是它是Object类型的,会涉及到拆箱,所以还是自定义一个CustomThumb。

    首先,定义说明拖动方向的枚举:

    public enum DragDirection
    {
        TopLeft = 1,
        TopCenter = 2,
        TopRight = 4,
        MiddleLeft = 16,
        MiddleCenter = 32,
        MiddleRight = 64,
        BottomLeft = 256,
        BottomCenter = 512,
        BottomRight = 1024,
    }

好了,有了这个枚举,就可以知道用户操作的意图了,现在自定义一个CustomThumb。

    public class CustomThumb : Thumb
    {
        public DragDirection DragDirection { get; set; }
    }
这些都弄好了,现在来写自定义控件的模板:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
                    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
                    xmlns:local="clr-namespace:UICommon.Controls"
                    xmlns:Core="clr-namespace:System;assembly=mscorlib"
                    mc:Ignorable="d">


    
    <ControlTemplate TargetType="{x:Type local:DragHelperBase}" x:Key="DrapControlHelperTemplate">
        <ControlTemplate.Resources>
            <Style TargetType="{x:Type Thumb}" x:Key="CornerThumbStyle">
                <Setter Property="Width" Value="{Binding CornerWidth, RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay}"/>
                <Setter Property="Height" Value="{Binding CornerWidth, RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay}"/>
                <Setter Property="BorderBrush" Value="{Binding BorderBrush, RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay}"/>
                <Setter Property="BorderThickness" Value="3"/>
                <Setter Property="Background" Value="Transparent"/>
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type Thumb}">
                            <Border SnapsToDevicePixels="True"
                                    Width="{TemplateBinding Width}" 
						            Height="{TemplateBinding Height}"
						            Background="{TemplateBinding Background}" 
						            BorderBrush="{TemplateBinding BorderBrush}"
						            BorderThickness="{TemplateBinding BorderThickness}"/>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
            
            <Style TargetType="{x:Type Thumb}" x:Key="AreaThumbStyle">
                <Setter Property="BorderBrush" Value="{Binding BorderBrush, RelativeSource={RelativeSource TemplatedParent}}"/>
                <Setter Property="Background" Value="Transparent"/>
                <Setter Property="Padding" Value="0"/>
                <Setter Property="Margin" Value="0"/>
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate T
WPF ,可以使用 `Canvas` 控件的 `MouseMove` 事件和 `MouseLeftButtonDown`、`MouseLeftButtonUp` 事件结合起来实现鼠标在 `Canvas` 控件按住移动时不能超过 `Canvas` 边界的效果。 具体实现可以参考以下代码: ```xaml <Canvas x:Name="canvas" Width="300" Height="200" Background="White" MouseLeftButtonDown="Canvas_MouseLeftButtonDown" MouseMove="Canvas_MouseMove" MouseLeftButtonUp="Canvas_MouseLeftButtonUp" /> ``` ```csharp private bool isDrawing = false; private Point startPoint; private Point endPoint; private void Canvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { isDrawing = true; startPoint = e.GetPosition(canvas); } private void Canvas_MouseMove(object sender, MouseEventArgs e) { if (isDrawing) { endPoint = e.GetPosition(canvas); // 计算鼠标在 Canvas 的坐标,并限制移动范围 double x = Math.Min(Math.Max(endPoint.X, 0), canvas.ActualWidth); double y = Math.Min(Math.Max(endPoint.Y, 0), canvas.ActualHeight); // 绘制路径 Line line = new Line { Stroke = Brushes.Black, X1 = startPoint.X, Y1 = startPoint.Y, X2 = x, Y2 = y }; canvas.Children.Add(line); // 更新起点坐标 startPoint = new Point(x, y); } } private void Canvas_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) { isDrawing = false; } ``` 在上述代码,我们在 XAML 定义了一个 `Canvas` 控件,并添加了 `MouseLeftButtonDown`、`MouseMove`、`MouseLeftButtonUp` 事件的处理函数。当鼠标左键按下时,设置 `isDrawing` 为 `true`,并记录下起点坐标。当鼠标移动时,如果 `isDrawing` 为 `true`,则计算出鼠标在 `Canvas` 的坐标,并限制移动范围。然后绘制路径,并更新起点坐标。当鼠标左键抬起时,设置 `isDrawing` 为 `false`,结束绘制。 注意,WPF 的 `Canvas` 控件大小可以通过 `Width` 和 `Height` 属性来设置,但实际大小可能会受到父控件的布局影响。因此,在计算鼠标在 `Canvas` 的坐标时,需要使用 `ActualWidth` 和 `ActualHeight` 属性来获取 `Canvas` 控件的实际大小
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值