C# wpf Canvas中实现控件拖动调整大小的示例

目录
  • 前言
  • 一、功能说明
  • 二、如何实现?
    • 1.继承Adorner
    • 2.使用Thumb
    • 3.实现拖动逻辑
  • 三、完整代码
  • 四、使用示例
  • 总结

前言

我们做图片编辑工具、视频编辑工具、或者画板有时需要实现控件缩放功能,比如图片或图形可以拉伸放大或缩小,实现这种功能通常需要8个点,对应4条边和4个角,在wpf中通常可以使用装饰器实现。

一、功能说明

8个点方放置在控件的8个方位上,通过拖动这些点对控件进行拉伸或缩小,示意图如下:

二、如何实现?

1.继承Adorner

通过装饰器的方式添加8个点在控件上,这样既可以不影响控件布局,又可以自由摆放8点控件。通过重写方法,给装饰添加控件。必要的重写的方法如下面示例所示:

public class CanvasAdorner : Adorner
{
  //获取装饰器的元素个数
  protected override Visual GetVisualChild(int index);
  //指定装饰器子元素个数
  protected override int VisualChildrenCount{get;}
  //布局,添加的子元素需要手动布局。
  protected override Size ArrangeOverride(Size finalSize);
}

2.使用Thumb

因为Thumb实现拖动比较容易,有相关事件获取拖动距离。在装饰器中定义8个Thumb,对应8个方位点。
示例代码如下:

//4条边
Thumb _leftThumb, _topThumb, _rightThumb, _bottomThumb;
//4个角
Thumb _lefTopThumb, _rightTopThumb, _rightBottomThumb, _leftbottomThumb;

初始化

 public CanvasAdorner(UIElement adornedElement) : base(adornedElement)
 {
     //初始化thumb
     _leftThumb = new Thumb();
     _leftThumb.HorizontalAlignment = HorizontalAlignment.Left;
     _leftThumb.VerticalAlignment = VerticalAlignment.Center;
     _leftThumb.Cursor = Cursors.SizeWE;
     //其他略...
}

3.实现拖动逻辑

在Thumb的DragDelta事件可以获取拖动距离,根据八个方位的不同计算并修改控件的大小。

private void Thumb_DragDelta(object sender, DragDeltaEventArgs e)
{
//1.右侧点HorizontalChange加宽
//2.左侧点HorizontalChange减宽,加左移
//3.下侧点VerticalChange加高
//4.上侧点VerticalChange减高,加上移
}

三、完整代码

代码如下:

   public class CanvasAdorner : Adorner
    {
        //4条边
        Thumb _leftThumb, _topThumb, _rightThumb, _bottomThumb;
        //4个角
        Thumb _lefTopThumb, _rightTopThumb, _rightBottomThumb, _leftbottomThumb;
        //布局容器,如果不使用布局容器,则需要给上述8个控件布局,实现和Grid布局定位是一样的,会比较繁琐且意义不大。
        Grid _grid;
        UIElement _adornedElement;
        public CanvasAdorner(UIElement adornedElement) : base(adornedElement)
        {
            _adornedElement = adornedElement;
            //初始化thumb
            _leftThumb = new Thumb();
            _leftThumb.HorizontalAlignment = HorizontalAlignment.Left;
            _leftThumb.VerticalAlignment = VerticalAlignment.Center;
            _leftThumb.Cursor = Cursors.SizeWE;
            _topThumb = new Thumb();
            _topThumb.HorizontalAlignment = HorizontalAlignment.Center;
            _topThumb.VerticalAlignment = VerticalAlignment.Top;
            _topThumb.Cursor = Cursors.SizeNS;
            _rightThumb = new Thumb();
            _rightThumb.HorizontalAlignment = HorizontalAlignment.Right;
            _rightThumb.VerticalAlignment = VerticalAlignment.Center;
            _rightThumb.Cursor = Cursors.SizeWE;
            _bottomThumb = new Thumb();
            _bottomThumb.HorizontalAlignment = HorizontalAlignment.Center;
            _bottomThumb.VerticalAlignment = VerticalAlignment.Bottom;
            _bottomThumb.Cursor = Cursors.SizeNS;
            _lefTopThumb = new Thumb();
            _lefTopThumb.HorizontalAlignment = HorizontalAlignment.Left;
            _lefTopThumb.VerticalAlignment = VerticalAlignment.Top;
            _lefTopThumb.Cursor = Cursors.SizeNWSE;
            _rightTopThumb = new Thumb();
            _rightTopThumb.HorizontalAlignment = HorizontalAlignment.Right;
            _rightTopThumb.VerticalAlignment = VerticalAlignment.Top;
            _rightTopThumb.Cursor = Cursors.SizeNESW;
            _rightBottomThumb = new Thumb();
            _rightBottomThumb.HorizontalAlignment = HorizontalAlignment.Right;
            _rightBottomThumb.VerticalAlignment = VerticalAlignment.Bottom;
            _rightBottomThumb.Cursor = Cursors.SizeNWSE;
            _leftbottomThumb = new Thumb();
            _leftbottomThumb.HorizontalAlignment = HorizontalAlignment.Left;
            _leftbottomThumb.VerticalAlignment = VerticalAlignment.Bottom;
            _leftbottomThumb.Cursor = Cursors.SizeNESW;
            _grid = new Grid();
            _grid.Children.Add(_leftThumb);
            _grid.Children.Add(_topThumb);
            _grid.Children.Add(_rightThumb);
            _grid.Children.Add(_bottomThumb);
            _grid.Children.Add(_lefTopThumb);
            _grid.Children.Add(_rightTopThumb);
            _grid.Children.Add(_rightBottomThumb);
            _grid.Children.Add(_leftbottomThumb);
            AddVisualChild(_grid);
            foreach (Thumb thumb in _grid.Children)
            {
                thumb.Width = 16;
                thumb.Height = 16;
                thumb.Background = Brushes.Green;
                thumb.Template = new ControlTemplate(typeof(Thumb))
                {
                    VisualTree = GetFactory(new SolidColorBrush(Colors.White))
                };
                thumb.DragDelta += Thumb_DragDelta;
            }
        }
        protected override Visual GetVisualChild(int index)
        {
            return _grid;
        }
        protected override int VisualChildrenCount
        {
            get
            {
                return 1;
            }
        }
        protected override Size ArrangeOverride(Size finalSize)
        {
            //直接给grid布局,grid内部的thumb会自动布局。
            _grid.Arrange(new Rect(new Point(-_leftThumb.Width / 2, -_leftThumb.Height / 2), new Size(finalSize.Width + _leftThumb.Width, finalSize.Height + _leftThumb.Height)));
            return finalSize;
        }
        //拖动逻辑
        private void Thumb_DragDelta(object sender, DragDeltaEventArgs e)
        {
            var c = _adornedElement as FrameworkElement;
            var thumb = sender as FrameworkElement;
            double left, top, width, height;
            if (thumb.HorizontalAlignment == HorizontalAlignment.Left)
            {

                left =double.IsNaN( Canvas.GetLeft(c))?0: Canvas.GetLeft(c) + e.HorizontalChange;
                width = c.Width - e.HorizontalChange;
            }
            else
            {
                left = Canvas.GetLeft(c);
                width = c.Width + e.HorizontalChange;
            }
            if (thumb.VerticalAlignment == VerticalAlignment.Top)
            {
                top = double.IsNaN(Canvas.GetTop(c)) ? 0 : Canvas.GetTop(c) + e.VerticalChange;
                height = c.Height - e.VerticalChange;
            }
            else
            {
                top = Canvas.GetTop(c);
                height = c.Height + e.VerticalChange;
            }
            if (thumb.HorizontalAlignment != HorizontalAlignment.Center)
            {
                if (width >= 0)
                {
                    Canvas.SetLeft(c, left);
                    c.Width = width;
                }
            }
            if (thumb.VerticalAlignment != VerticalAlignment.Center)
            {
                if (height >= 0)
                {
                    Canvas.SetTop(c, top);
                    c.Height = height;
                }
            }
        }
        //thumb的样式
        FrameworkElementFactory GetFactory(Brush back)
        {
            var fef = new FrameworkElementFactory(typeof(Ellipse));
            fef.SetValue(Ellipse.FillProperty, back);
            fef.SetValue(Ellipse.StrokeProperty, new SolidColorBrush((Color)ColorConverter.ConvertFromString("#999999")));
            fef.SetValue(Ellipse.StrokeThicknessProperty, (double)2);
            return fef;
        }
    }

四、使用示例

示例代码如下:
xaml

<Canvas Margin="20">
    <Border  x:Name="border"  Width="200" Height="200"  Background="Gray"  ></Border>
</Canvas>

在窗口或控件的Loaded事件中添加装饰器:
cs

private void window_Loaded(object sender, RoutedEventArgs e)
{
    var layer = AdornerLayer.GetAdornerLayer(border);
    layer.Add(new CanvasAdorner(border));
}

效果预览:

总结

以上就是今天要讲的内容,本文讲述了控件缩放的方法与实现,都相对较简单,尤其是实现也是特意精简了代码,比如布局直接使用Grid控件,拖动的逻辑也是较为简化,最终呈现的效果还是比较不错的。

到此这篇关于C# wpf Canvas中实现控件拖动调整大小的示例的文章就介绍到这了,更多相关C# wpf Canvas控件拖动调整大小内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 基于C# wpf 实现Grid内控件拖动详情

    目录 一.如何实现? 1.注册鼠标事件 2.记录位置 3.跟随鼠标移动 4.恢复标识 二.示例 前言: 有一些业务场景中我们需要拖动控件,在Grid中就可以实现控件拖动,通过设置Margin属性即可,根据鼠标的移动,设置相应的Margin的Left.Top,当然有时也不是直接设置的,需要根据HorizontalAlignment.VerticalAlignment值有不同的计算方法. 一.如何实现? 1.注册鼠标事件 拖动的控件需要注册3个鼠标事件分别是,鼠标按下.鼠标移动.鼠标弹起. 以But

  • C# wpf Canvas中实现控件拖动调整大小的示例

    目录 前言 一.功能说明 二.如何实现? 1.继承Adorner 2.使用Thumb 3.实现拖动逻辑 三.完整代码 四.使用示例 总结 前言 我们做图片编辑工具.视频编辑工具.或者画板有时需要实现控件缩放功能,比如图片或图形可以拉伸放大或缩小,实现这种功能通常需要8个点,对应4条边和4个角,在wpf中通常可以使用装饰器实现. 一.功能说明 8个点方放置在控件的8个方位上,通过拖动这些点对控件进行拉伸或缩小,示意图如下: 二.如何实现? 1.继承Adorner 通过装饰器的方式添加8个点在控件上

  • WPF实现slide控件拖动完成后改变变量值

    WPF中使slide控件拖动完成后改变变量值这个问题一开始觉得还是挺简单的,网上也看到不少解决方案. 首先一个最简单最直接的方案就是自定义一个名为FinalValue的依赖属性.随后重载OnThumbDragCompleted函数,在Thumb控件完成拖动时改写FinalValue.代码如下 public class SliderIgnoreDelta : Slider { public int FinalValue { get { return (int)GetValue(FinalValue

  • 在WPF中动态加载XAML中的控件实例代码

    本文实例讲述了在WPF中动态加载XAML中的控件的方法.分享给大家供大家参考,具体如下: using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using S

  • WPF实现控件拖动的示例代码

    实现控件拖动的基本原理是对鼠标位置的捕获,同时根据鼠标按键的按下.释放确定控件移动的幅度和时机. 简单示例: 在Grid中有一个Button,通过鼠标事件改编Button的Margin属性,从而改变Button在Grid中的相对位置. <Grid Name="gd"> <Button Width=90 Height=30 Name="btn">button</Button> </Grid> 为Button控件绑定三个事

  • 对WPF中Expander控件美化

    示例图: Expander控件功能很常见, 一般用于系统左侧的菜单收缩面板. 主要的组成 一个头部(header) 和 一个 内容(content) 组成. <Expander ExpandDirection="Down" SnapsToDevicePixels="True" VerticalAlignment="Top" Style="{DynamicResource ExpanderStyle1}" > <

  • 分享Android中ExpandableListView控件使用教程

    本文采用一个Demo来展示Android中ExpandableListView控件的使用,如如何在组/子ListView中绑定数据源.直接上代码如下: 程序结构图: layout目录下的 main.xml 文件源码如下: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android

  • 详解BootStrap中Affix控件的使用及保持布局的美观的方法

    Affix是BootStrap中的一个很有用的控件,他能够监视浏览器的滚动条的位置并让你的导航始终都在页面的可视区域.一开始的时候,导航在页面中是普通的流式布局,占有文档中固定的位置,当页面滚动的时候,导航就自动变成了固定布局(fixed),始终处于用户的视区,下面来说说他的用法.首先来看看他的实现原理.它是通过实时修改页面元素的class属性来实现的 开始的时候应用affix的元素的class中会自动添加affxi-top属性 当滚动条滚动以至于导航快要到页面顶部的时候这时候在元素的class

  • Android控件拖动实例详解

    Android控件拖动 Android控件的拖动,主要是通过设置控件的setOnTouchListener()方法,重写它的onTouch()方法.然后通过MotionEvent的不同事件,进行判断,主要是在MotionEvent.ACTION_MOVE中不断重绘控件在画布中的位置,而实现拖动的效果. public class DragViewActivity extends AppCompatActivity { private Button btn_drag; @Override prote

  • Android实现控件拖动效果

    本文实例为大家分享了Android实现控件拖动效果的具体代码,供大家参考,具体内容如下 1.今天突然想到做个实现个控件拖动效果,就来试试,一查原来还是很简单的 2.原理就是实现OnTouchLinstener,然后触摸屏幕时改变控件的位置,当然了会有人问OnTouch与OnClick有什么区别,百度搜一下就知道了,懒得说. 3.废话不多说直接看图 4.当然了,笔者在点击和拖动的时候更改了ImageView的图片,离开屏幕时恢复,很简单,但很实用的一点,直接上代码吧 package com.xug

随机推荐