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

 

前言

我们做图片编辑工具、视频编辑工具、或者画板有时需要实现控件缩放功能,比如图片或图形可以拉伸放大或缩小,实现这种功能通常需要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控件拖动调整大小内容请搜索编程宝库以前的文章,希望以后支持编程宝库

 前言在《C# wpf Canvas中实现控件动态调整大小》中我们实现了Canvas中的控件动态调整大小,由于Grid也是可层叠布局,在Grid中也是可以实现动态调整大小的。&n ...