C# wpf Canvas控件拖动调整大小
CodeOfCC 人气:0前言
我们做图片编辑工具、视频编辑工具、或者画板有时需要实现控件缩放功能,比如图片或图形可以拉伸放大或缩小,实现这种功能通常需要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控件,拖动的逻辑也是较为简化,最终呈现的效果还是比较不错的。
加载全部内容