WPF实现控件旋转和动态修改长宽

WPF开发者QQ群: 340500857 

前言 

      有小伙伴提出要做一个带旋转的控件并且可以实现修改控件宽高。

修改控件宽高可以使用装饰器Adorner,旋转控件则使用的Thumb修改RenderTransform  Angle进行实现。

欢迎转发、分享、点赞,谢谢大家~。  

效果预览(更多效果请下载源码体验):

一、MainWindow.xaml代码如下:

<Window x:Class="WpfCanvasAdorner.MainWindow"
        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:WpfCanvasAdorner"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800"
        WindowStartupLocation="CenterScreen">
    <Canvas x:Name="_CanvasMain" Background="ForestGreen">
        <Image Source="wxgzh.png" Canvas.Left="205"
                      Canvas.Top="70"/>
        <TextBlock Text="QQ群:340500857" Foreground="White" FontSize="20"
                        Canvas.Left="505"
                      Canvas.Top="165" />
        <Border BorderThickness="2" BorderBrush="White"
                        x:Name="_border" Width="280"
                      Height="100"
                      Canvas.Left="305"
                      Canvas.Top="205" 
                            RenderTransformOrigin="0.5,0.5">
            <Grid>
                <local:ThumbAngle DataContext="{Binding ElementName=_border}"/>
                <TextBlock Text="WPF开发者" Foreground="White" FontSize="40" 
                           HorizontalAlignment="Center" VerticalAlignment="Center"/>
            </Grid>

        </Border>
        <!--<TextBlock Text="微信公众号:WPF开发者" Foreground="White" FontSize="24" 
                           HorizontalAlignment="Center" VerticalAlignment="Center"
                   Canvas.Left="205"
                      Canvas.Top="105" />-->
       
    </Canvas>
</Window>

WPF开发者WPF技术前沿、技术干货分享、ArcGIS、OpenCVSharp,欢迎关注。19篇原创内容公众号

二、MainWindow.xaml.cs代码如下:

public MainWindow()
        {
            InitializeComponent();
            this.Loaded += (s, e) =>
            {
                var al = AdornerLayer.GetAdornerLayer(_border);
                al.Add(new ElementAdorner(_border));
            };
        }

三、ElementAdorner.cs代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;

namespace WpfCanvasAdorner
{
    public class ElementAdorner : Adorner
    {
        private const double ThumbSize = 16, ElementMiniSize = 20;
        private Thumb tLeft, tRight, bLeftBottom, bRightBottom, tMove;
        private VisualCollection visualCollection;
        public ElementAdorner(UIElement adornedElement) : base(adornedElement)
        {
            visualCollection = new VisualCollection(this);
            visualCollection.Add(tMove = CreateMoveThumb());
            visualCollection.Add(tLeft = CreateThumb(Cursors.SizeNWSE, HorizontalAlignment.Left, VerticalAlignment.Top));
            visualCollection.Add(tRight = CreateThumb(Cursors.SizeNESW, HorizontalAlignment.Right, VerticalAlignment.Top));
            visualCollection.Add(bLeftBottom = CreateThumb(Cursors.SizeNESW, HorizontalAlignment.Left, VerticalAlignment.Bottom));
            visualCollection.Add(bRightBottom = CreateThumb(Cursors.SizeNWSE, HorizontalAlignment.Right, VerticalAlignment.Bottom));
        }
        protected override void OnRender(DrawingContext drawingContext)
        {
            var offset = ThumbSize / 2;
            var sz = new Size(ThumbSize, ThumbSize);
            var renderPen = new Pen(new SolidColorBrush(Colors.White), 2.0);
            var startPoint = new Point(AdornedElement.RenderSize.Width / 2, AdornedElement.RenderSize.Height - AdornedElement.RenderSize.Height);
            var endPoint = new Point(AdornedElement.RenderSize.Width / 2, AdornedElement.RenderSize.Height - AdornedElement.RenderSize.Height - 16);
            drawingContext.DrawLine(renderPen, startPoint, endPoint);
            tMove.Arrange(new Rect(new Point(0, 0), new Size(this.RenderSize.Width, this.RenderSize.Height)));
            tLeft.Arrange(new Rect(new Point(-offset, -offset), sz));
            tRight.Arrange(new Rect(new Point(AdornedElement.RenderSize.Width - offset, -offset), sz));
            bLeftBottom.Arrange(new Rect(new Point(-offset, AdornedElement.RenderSize.Height - offset), sz));
            bRightBottom.Arrange(new Rect(new Point(AdornedElement.RenderSize.Width - offset, AdornedElement.RenderSize.Height - offset), sz));

        }
        private Thumb CreateMoveThumb()
        {
            var thumb = new Thumb()
            {
                Cursor = Cursors.SizeAll,
                Template = new ControlTemplate(typeof(Thumb))
                {
                    VisualTree = GetFactory(GetMoveEllipse())
                }
            };
            thumb.DragDelta += (s, e) =>
            {
                var element = AdornedElement as FrameworkElement;
                if (element == null)
                    return;
                Canvas.SetLeft(element, Canvas.GetLeft(element) + e.HorizontalChange);
                Canvas.SetTop(element, Canvas.GetTop(element) + e.VerticalChange);
            };
            return thumb;
        }
        Brush GetMoveEllipse()
        {
            return new DrawingBrush(new GeometryDrawing(Brushes.Transparent, null, null));
        }
        /// <summary>
        /// 创建Thumb
        /// </summary>
        /// <param name="cursor">鼠标</param>
        /// <param name="horizontal">水平</param>
        /// <param name="vertical">垂直</param>
        /// <returns></returns>
        private Thumb CreateThumb(Cursor cursor, HorizontalAlignment horizontal, VerticalAlignment vertical)
        {
            var thumb = new Thumb()
            {
                Cursor = cursor,
                Width = ThumbSize,
                Height = ThumbSize,
                HorizontalAlignment = horizontal,
                VerticalAlignment = vertical,
                Template = new ControlTemplate(typeof(Thumb))
                {
                    VisualTree = GetFactory(new SolidColorBrush(Colors.White))
                }
            };

            thumb.DragDelta += (s, e) =>
            {
                var element = AdornedElement as FrameworkElement;
                if (element == null) return;
                Resize(element);
                switch (thumb.VerticalAlignment)
                {
                    case VerticalAlignment.Bottom:
                        if (element.Height + e.VerticalChange > ElementMiniSize)
                        {
                            element.Height += e.VerticalChange;

                        }
                        break;
                    case VerticalAlignment.Top:
                        if (element.Height - e.VerticalChange > ElementMiniSize)
                        {
                            element.Height -= e.VerticalChange;
                            Canvas.SetTop(element, Canvas.GetTop(element) + e.VerticalChange);
                        }
                        break;

                }
                switch (thumb.HorizontalAlignment)
                {
                    case HorizontalAlignment.Left:
                        if (element.Width - e.HorizontalChange > ElementMiniSize)
                        {
                            element.Width -= e.HorizontalChange;
                            Canvas.SetLeft(element, Canvas.GetLeft(element) + e.HorizontalChange);
                        }
                        break;
                    case HorizontalAlignment.Right:
                        if (element.Width + e.HorizontalChange > ElementMiniSize)
                        {
                            element.Width += e.HorizontalChange;
                        }
                        break;
                }
                e.Handled = true;

            };
            return thumb;
        }
        private void Resize(FrameworkElement fElement)
        {
            if (Double.IsNaN(fElement.Width))
                fElement.Width = fElement.RenderSize.Width;
            if (Double.IsNaN(fElement.Height))
                fElement.Height = fElement.RenderSize.Height;
        }
        private FrameworkElementFactory GetFactory(Brush back)
        {
            var elementFactory = new FrameworkElementFactory(typeof(Ellipse));
            elementFactory.SetValue(Ellipse.FillProperty, back);
            return elementFactory;
        }


        protected override Visual GetVisualChild(int index)
        {
            return visualCollection[index];
        }
        protected override int VisualChildrenCount
        {
            get
            {
                return visualCollection.Count;
            }
        }
    }
}

WPF开发者WPF技术前沿、技术干货分享、ArcGIS、OpenCVSharp,欢迎关注。19篇原创内容公众号

四、ThumbAngle.cs代码如下:

using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;

namespace WpfCanvasAdorner
{
    public class ThumbAngle:Thumb
    {
        private double initialAngle;
        private RotateTransform rotateTransform;
        private Vector startVector;
        private Point centerPoint;
        private Border designerItem;
        private Canvas canvas;
        public ThumbAngle()
        {
            Cursor = Cursors.Hand;
            Width = 16;
            Height = 16;
            VerticalAlignment = VerticalAlignment.Top;
            Margin = new Thickness(0,-28,0,0);
            Template = new ControlTemplate(typeof(Thumb))
            {
                VisualTree = GetFactory(GetMoveEllipseBack())
            };
            ToolTip = "旋转";
            DragDelta += new DragDeltaEventHandler(this.Thumb_DragDelta);
            DragStarted += new DragStartedEventHandler(this.Thumb_DragStarted);
        }
        Brush GetMoveEllipseBack()
        {

            string lan = "M242 842l60-60c48 36 106 60 168 68v86c-86-8-164-42-228-94zM554 850c62-8 120-32 166-68l62 60c-64 52-142 86-228 94v-86zM782 722c36-48 60-104 68-166h86c-8 86-42 162-94 226zM640 512c0 70-58 128-128 128s-128-58-128-128 58-128 128-128 128 58 128 128zM174 554c8 62 32 120 68 166l-60 62c-52-64-86-142-94-228h86zM242 302c-36 48-60 106-68 168h-86c8-86 42-164 94-228zM850 470c-8-62-32-120-68-168l60-60c52 64 86 142 94 228h-86zM782 182l-60 60c-48-36-106-60-168-68v-86c86 8 164 42 228 94zM470 174c-62 8-120 32-168 68l-60-60c64-52 142-86 228-94v86z";
            var converter = TypeDescriptor.GetConverter(typeof(Geometry));
            var geometry = (Geometry)converter.ConvertFrom(lan);
            TileBrush bsh = new DrawingBrush(new GeometryDrawing(Brushes.White, new Pen(Brushes.Transparent,2), geometry));
            bsh.Stretch = Stretch.Fill;
            return bsh;

        }
        private FrameworkElementFactory GetFactory(Brush back)
        {
            var elementFactory = new FrameworkElementFactory(typeof(Ellipse));
            elementFactory.SetValue(Ellipse.FillProperty, back);
            return elementFactory;
        }
        private void Thumb_DragDelta(object sender, System.Windows.Controls.Primitives.DragDeltaEventArgs e)
        {
            if (this.designerItem != null && this.canvas != null)
            {
                Point currentPoint = Mouse.GetPosition(this.canvas);
                Vector deltaVector = Point.Subtract(currentPoint, this.centerPoint);

                double angle = Vector.AngleBetween(this.startVector, deltaVector);

                RotateTransform rotateTransform = this.designerItem.RenderTransform as RotateTransform;
                rotateTransform.Angle = this.initialAngle + Math.Round(angle, 0);
                designerItem.InvalidateMeasure();
            }
        }
      
        private void Thumb_DragStarted(object sender, System.Windows.Controls.Primitives.DragStartedEventArgs e)
        {
            var thumb = sender as Thumb;
            designerItem = thumb.DataContext as Border;
            canvas = VisualTreeHelper.GetParent(designerItem) as Canvas;
            if (this.canvas != null)
            {
                this.centerPoint = this.designerItem.TranslatePoint(
                    new Point(this.designerItem.Width * this.designerItem.RenderTransformOrigin.X,
                              this.designerItem.Height * this.designerItem.RenderTransformOrigin.Y),
                              this.canvas);

                Point startPoint = Mouse.GetPosition(this.canvas);
                this.startVector = Point.Subtract(startPoint, this.centerPoint);

                this.rotateTransform = this.designerItem.RenderTransform as RotateTransform;
                if (this.rotateTransform == null)
                {
                    this.designerItem.RenderTransform = new RotateTransform(0);
                    this.initialAngle = 0;
                }
                else
                {
                    this.initialAngle = this.rotateTransform.Angle;
                }
            }
        }
    }
}

源码地址

github:https://github.com/yanjinhuagood/WPFDevelopers.git

gitee:https://gitee.com/yanjinhua/WPFDevelopers.git

WPF开发者QQ群: 340500857 

blogs: https://www.cnblogs.com/yanjinhua

Github:https://github.com/yanjinhuagood

出处:https://www.cnblogs.com/yanjinhua

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

转载请著名作者 出处 https://github.com/yanjinhuagood

WPF开发者WPF技术前沿、技术干货分享、ArcGIS、OpenCVSharp,欢迎关注。19篇原创内容公众号

原文出处:微信公众号【驚鏵 WPF开发者】

原文链接:https://mp.weixin.qq.com/s/rGq7VFr84svLH-8x_QglQQ

本文观点不代表Dotnet9立场,转载请联系原作者。

发表评论

登录后才能评论