温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

C# wpf Canvas中如何实现控件拖动调整大小

发布时间:2022-08-05 10:55:22 来源:亿速云 阅读:732 作者:iii 栏目:开发技术

这篇“C# wpf Canvas中如何实现控件拖动调整大小”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“C# wpf Canvas中如何实现控件拖动调整大小”文章吧。

    前言

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

    一、功能说明

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

    C# wpf Canvas中如何实现控件拖动调整大小

    二、如何实现?

    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));
    }

    效果预览:

    C# wpf Canvas中如何实现控件拖动调整大小

    以上就是关于“C# wpf Canvas中如何实现控件拖动调整大小”这篇文章的内容,相信大家都有了一定的了解,希望小编分享的内容对大家有帮助,若想了解更多相关的知识内容,请关注亿速云行业资讯频道。

    向AI问一下细节

    免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

    AI