AY 一个wpf画图项目复习下【1/10】

栏目: 编程工具 · 发布时间: 5年前

内容简介:新建一个wpf项目,4.5.2吧

AY 一个wpf画图项目复习下【1/10】

新建一个wpf项目,4.5.2吧

AY 一个wpf画图项目复习下【1/10】

画个圆

AY 一个wpf画图项目复习下【1/10】

用ContentControl包裹一层

AY 一个wpf画图项目复习下【1/10】

给ContentControl加一个默认模板

 <Canvas>
            <Canvas.Resources>
                <ControlTemplate x:Key="DesignerItemTemplate" TargetType="ContentControl">
                    <ContentPresenter Content="{TemplateBinding ContentControl.Content}"/>
                </ControlTemplate>
            </Canvas.Resources>
            <ContentControl Canvas.Top="100" Canvas.Left="100" 
                            Width="100" Height="100" Template="{StaticResource DesignerItemTemplate}">
                <Ellipse   Fill="#FF42C742"   />
            </ContentControl>
        </Canvas>

AY 一个wpf画图项目复习下【1/10】

让它可以移动,暂不考虑美观,先实现特性

public class MoveThumb : Thumb
    {
        public MoveThumb()
        {
            DragDelta += new DragDeltaEventHandler(this.MoveThumb_DragDelta);
        }

        private void MoveThumb_DragDelta(object sender, DragDeltaEventArgs e)
        {
            Control item = this.DataContext as Control;

            if (item != null)
            {
                double left = Canvas.GetLeft(item);
                double top = Canvas.GetTop(item);

                Canvas.SetLeft(item, left + e.HorizontalChange);
                Canvas.SetTop(item, top + e.VerticalChange);
            }
        }
    }

继承一个thumb,拖动时候,设置自己在canvas中的位置。

然后把thumb包裹要显示的内容,并且把内容设置不可命中测试

  <Canvas>
            <Canvas.Resources>
                <ControlTemplate x:Key="DesignerItemTemplate" TargetType="ContentControl">
                    <Grid>
                        <local:MoveThumb DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}}" 
                 Cursor="SizeAll"/>
                        <ContentPresenter Content="{TemplateBinding ContentControl.Content}" IsHitTestVisible="False"/>
                    </Grid>
                </ControlTemplate>
            </Canvas.Resources>
            <ContentControl Canvas.Top="100" Canvas.Left="100" 
                            Width="100" Height="100" Template="{StaticResource DesignerItemTemplate}">
                <Ellipse   Fill="#FF42C742"   />
            </ContentControl>
        </Canvas>

AY 一个wpf画图项目复习下【1/10】

thumb就像一个可以接受drag的矩形,更改透明外观

AY 一个wpf画图项目复习下【1/10】

 <Canvas.Resources>
                <ControlTemplate x:Key="MoveThumbTemplate" TargetType="{x:Type local:MoveThumb}">
                    <Rectangle Fill="Transparent"/>
                </ControlTemplate>
                <ControlTemplate x:Key="DesignerItemTemplate" TargetType="ContentControl">
                    <Grid>
                        <local:MoveThumb DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}}" Template="{StaticResource MoveThumbTemplate}"
                 Cursor="SizeAll"/>
                        <ContentPresenter Content="{TemplateBinding ContentControl.Content}" IsHitTestVisible="False"/>
                    </Grid>
                </ControlTemplate>
            </Canvas.Resources>

调整大小

8个thumb,4个角落矩形同时调整宽高,四个边矩形调整宽高

  public class ResizeThumb : Thumb
    {
        public ResizeThumb()
        {
            DragDelta += new DragDeltaEventHandler(this.ResizeThumb_DragDelta);
        }

        private void ResizeThumb_DragDelta(object sender, DragDeltaEventArgs e)
        {
            Control item = this.DataContext as Control;

            if (item != null)
            {
                double deltaVertical, deltaHorizontal;

                switch (VerticalAlignment)
                {
                    case System.Windows.VerticalAlignment.Bottom:
                        deltaVertical = Math.Min(-e.VerticalChange,
                            item.ActualHeight - item.MinHeight);
                        item.Height -= deltaVertical;
                        break;
                    case System.Windows.VerticalAlignment.Top:
                        deltaVertical = Math.Min(e.VerticalChange,
                            item.ActualHeight - item.MinHeight);
                        Canvas.SetTop(item, Canvas.GetTop(item) + deltaVertical);
                        item.Height -= deltaVertical;
                        break;
                    default:
                        break;
                }

                switch (HorizontalAlignment)
                {
                    case System.Windows.HorizontalAlignment.Left:
                        deltaHorizontal = Math.Min(e.HorizontalChange,
                            item.ActualWidth - item.MinWidth);
                        Canvas.SetLeft(item, Canvas.GetLeft(item) + deltaHorizontal);
                        item.Width -= deltaHorizontal;
                        break;
                    case System.Windows.HorizontalAlignment.Right:
                        deltaHorizontal = Math.Min(-e.HorizontalChange,
                            item.ActualWidth - item.MinWidth);
                        item.Width -= deltaHorizontal;
                        break;
                    default:
                        break;
                }
            }

            e.Handled = true;
        }
    }

设置外观

   <ControlTemplate x:Key="ResizeDecoratorTemplate" TargetType="Control">
                    <Grid>
                        <local:ResizeThumb Height="3" Cursor="SizeNS" Margin="0 -4 0 0"
          VerticalAlignment="Top" HorizontalAlignment="Stretch"/>
                        <local:ResizeThumb Width="3" Cursor="SizeWE" Margin="-4 0 0 0"
          VerticalAlignment="Stretch" HorizontalAlignment="Left"/>
                        <local:ResizeThumb Width="3" Cursor="SizeWE" Margin="0 0 -4 0"
          VerticalAlignment="Stretch" HorizontalAlignment="Right"/>
                        <local:ResizeThumb Height="3" Cursor="SizeNS" Margin="0 0 0 -4"
          VerticalAlignment="Bottom"  HorizontalAlignment="Stretch"/>
                        <local:ResizeThumb Width="7" Height="7" Cursor="SizeNWSE" Margin="-6 -6 0 0"
          VerticalAlignment="Top" HorizontalAlignment="Left"/>
                        <local:ResizeThumb Width="7" Height="7" Cursor="SizeNESW" Margin="0 -6 -6 0"
          VerticalAlignment="Top" HorizontalAlignment="Right"/>
                        <local:ResizeThumb Width="7" Height="7" Cursor="SizeNESW" Margin="-6 0 0 -6"
          VerticalAlignment="Bottom" HorizontalAlignment="Left"/>
                        <local:ResizeThumb Width="7" Height="7" Cursor="SizeNWSE" Margin="0 0 -6 -6"
          VerticalAlignment="Bottom" HorizontalAlignment="Right"/>
                    </Grid>
                </ControlTemplate>
                <ControlTemplate x:Key="MoveThumbTemplate" TargetType="{x:Type local:MoveThumb}">
                    <Rectangle Fill="Transparent"/>
                </ControlTemplate>
                <ControlTemplate x:Key="DesignerItemTemplate" TargetType="ContentControl">
                    <Grid DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}}">
                        <local:MoveThumb DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}}" Template="{StaticResource MoveThumbTemplate}"
                 Cursor="SizeAll"/>
                        <Control Template="{StaticResource ResizeDecoratorTemplate}"/>
                        <ContentPresenter Content="{TemplateBinding ContentControl.Content}" IsHitTestVisible="False"/>
                    </Grid>
                </ControlTemplate>
            </Canvas.Resources>

注意

AY 一个wpf画图项目复习下【1/10】

AY 一个wpf画图项目复习下【1/10】

增加旋转,目前放在4个拐角,按下,移动,实现旋转

4个四分之三的 圆,放在拐角,行为如下,下面代码还具有学习价值,用到的向量知识,求解的旋转了多少度

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

namespace DiagramTool
{
    public class RotateThumb : Thumb
    {
        private Point centerPoint;
        private Vector startVector;
        private double initialAngle;
        private Canvas designerCanvas;
        private ContentControl designerItem;
        private RotateTransform rotateTransform;


        public RotateThumb()
        {
            DragDelta += new DragDeltaEventHandler(this.RotateThumb_DragDelta);
            DragStarted += new DragStartedEventHandler(this.RotateThumb_DragStarted);
        }

        private void RotateThumb_DragStarted(object sender, DragStartedEventArgs e)
        {
            this.designerItem = DataContext as ContentControl;

            if (this.designerItem != null)
            {
                this.designerCanvas = VisualTreeHelper.GetParent(this.designerItem) as Canvas;

                if (this.designerCanvas != null)
                {
                    this.centerPoint = this.designerItem.TranslatePoint(
                        new Point(this.designerItem.Width * this.designerItem.RenderTransformOrigin.X,
                                  this.designerItem.Height * this.designerItem.RenderTransformOrigin.Y),
                                  this.designerCanvas);

                    Point startPoint = Mouse.GetPosition(this.designerCanvas);
                    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;
                    }
                }
            }
        }

        private void RotateThumb_DragDelta(object sender, DragDeltaEventArgs e)
        {
            if (this.designerItem != null && this.designerCanvas != null)
            {
                Point currentPoint = Mouse.GetPosition(this.designerCanvas);
                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);
                this.designerItem.InvalidateMeasure();
            }
        }
    }
}

提供外观,上面给RotateThumb的,四分之三的圆,下面是一个整合4个拐角的一个control的样式

 <Style TargetType="{x:Type s:RotateThumb}">
            <Setter Property="RenderTransformOrigin" Value="0.5,0.5"/>
            <Setter Property="Cursor" Value="Hand"/>
            <Setter Property="Control.Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type s:RotateThumb}">
                        <Grid Width="30" Height="30">
                            <Path Fill="red"
                  Stretch="Fill"
                  Data="M 50,100 A 50,50 0 1 1 100,50 H 50 V 100"/>
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

        <ControlTemplate x:Key="RotateDecoratorTemplate" TargetType="{x:Type Control}">
            <Grid>
                <s:RotateThumb Margin="-18,-18,0,0" VerticalAlignment="Top" HorizontalAlignment="Left"/>
                <s:RotateThumb Margin="0,-18,-18,0" VerticalAlignment="Top" HorizontalAlignment="Right">
                    <s:RotateThumb.RenderTransform>
                        <RotateTransform Angle="90" />
                    </s:RotateThumb.RenderTransform>
                </s:RotateThumb>
                <s:RotateThumb Margin="0,0,-18,-18" VerticalAlignment="Bottom" HorizontalAlignment="Right">
                    <s:RotateThumb.RenderTransform>
                        <RotateTransform Angle="180" />
                    </s:RotateThumb.RenderTransform>
                </s:RotateThumb>
                <s:RotateThumb Margin="-18,0,0,-18" VerticalAlignment="Bottom" HorizontalAlignment="Left">
                    <s:RotateThumb.RenderTransform>
                        <RotateTransform Angle="270" />
                    </s:RotateThumb.RenderTransform>
                </s:RotateThumb>
            </Grid>
        </ControlTemplate>

没啥好解释的。

然后修改ContentControl的模板,加上旋转层,然后设置RenderTransformOrigin

AY 一个wpf画图项目复习下【1/10】

   <ControlTemplate x:Key="DesignerItemTemplate" TargetType="ContentControl">
                    <Grid DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}}">
                    <Control Name="RotateDecorator"
                     Template="{StaticResource RotateDecoratorTemplate}"
                    />
                    <local:MoveThumb DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}}" Template="{StaticResource MoveThumbTemplate}"
                 Cursor="SizeAll"/>
                        <Control Template="{StaticResource ResizeDecoratorTemplate}"/>
                        <ContentPresenter Content="{TemplateBinding ContentControl.Content}" IsHitTestVisible="False"/>
                    </Grid>
                </ControlTemplate>
            </Canvas.Resources>
        <ContentControl Canvas.Top="100" Canvas.Left="100" RenderTransformOrigin="0.5,0.5"
                            Width="100" Height="100" Template="{StaticResource DesignerItemTemplate}">
                <Ellipse   Fill="#FF42C742"   />

效果如下:

AY 一个wpf画图项目复习下【1/10】

以上版本叫做草稿版本,因为代码都冗余在一起,此时拓展第二个元素不方便,接下来重构一下。

基于Adorner的方式实现该效果,新建DiagramTool2的wpf项目

我们每个可以拖动调整的元素,叫DesignerItem

我们添加装饰叫 DesignerItemDecorator

Decorator 英文就是叫装饰器的意思

我们可以通过AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(某个控件);拿到 某个控件的 装饰层,从而在顶部加东西,也就是装饰。

我们迁移上一个MoveThumb控件,然后新增Control类型的DesignerItemDecorator控件

这一步,我们可以可以获得ContentControl和外层的Canvas传递给 Adorner进行控制

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

namespace DiagramTool2
{
    public class DesignerItemDecorator : Control
    {
        private Adorner adorner;

        public bool ShowDecorator
        {
            get { return (bool)GetValue(ShowDecoratorProperty); }
            set { SetValue(ShowDecoratorProperty, value); }
        }

        public static readonly DependencyProperty ShowDecoratorProperty =
            DependencyProperty.Register("ShowDecorator", typeof(bool), typeof(DesignerItemDecorator),
            new FrameworkPropertyMetadata(false, new PropertyChangedCallback(ShowDecoratorProperty_Changed)));

        public DesignerItemDecorator()
        {
            Unloaded += new RoutedEventHandler(this.DesignerItemDecorator_Unloaded);
        }

        private void HideAdorner()
        {
            if (this.adorner != null)
            {
                this.adorner.Visibility = Visibility.Hidden;
            }
        }

        private void ShowAdorner()
        {
            if (this.adorner == null)
            {
                AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(this);

                if (adornerLayer != null)
                {
                    ContentControl designerItem = this.DataContext as ContentControl;
                    //添加装饰器

                    adornerLayer.Add(this.adorner);

                    if (this.ShowDecorator)
                    {
                        this.adorner.Visibility = Visibility.Visible;
                    }
                    else
                    {
                        this.adorner.Visibility = Visibility.Hidden;
                    }
                }
            }
            else
            {
                this.adorner.Visibility = Visibility.Visible;
            }
        }

        private void DesignerItemDecorator_Unloaded(object sender, RoutedEventArgs e)
        {
            if (this.adorner != null)
            {
                AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(this);
                if (adornerLayer != null)
                {
                    adornerLayer.Remove(this.adorner);
                }

                this.adorner = null;
            }
        }

        private static void ShowDecoratorProperty_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            DesignerItemDecorator decorator = (DesignerItemDecorator)d;
            bool showDecorator = (bool)e.NewValue;

            if (showDecorator)
            {
                decorator.ShowAdorner();
            }
            else
            {
                decorator.HideAdorner();
            }
        }
    }
}

这里加了一个ShowDecorator属性,用来控制显示和隐藏 装饰的东西,也就是最外层的

AY 一个wpf画图项目复习下【1/10】

在unloaded从 顶部移除装饰层。

接下来我们在App.xaml 全局增加样式

    <Application.Resources>

        <ControlTemplate x:Key="MoveThumbTemplate"  TargetType="{x:Type s:MoveThumb}">
            <Rectangle Fill="Transparent"/>
        </ControlTemplate>
        
        <Style x:Key="DesignerItemStyle" TargetType="ContentControl">
            <Setter Property="MinHeight" Value="50"/>
            <Setter Property="MinWidth" Value="50"/>
            <Setter Property="RenderTransformOrigin" Value="0.5,0.5"/>
            <Setter Property="SnapsToDevicePixels" Value="true"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="ContentControl">
                        <Grid DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}}">
                            <s:MoveThumb Cursor="SizeAll" Template="{StaticResource MoveThumbTemplate}" />
                            <ContentPresenter Content="{TemplateBinding ContentControl.Content}"
                              Margin="{TemplateBinding Padding}"/>
                            <s:DesignerItemDecorator x:Name="ItemDecorator"/>
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

    </Application.Resources>

我们的行为作用在 ContentControl的,在MainWindow增加一个控件

<Window x:Class="DiagramTool2.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:DiagramTool2"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Canvas>
        <ContentControl Width="100"
                      Height="100"
                      Padding="1"
                      Canvas.Left="110"
                      Canvas.Top="100"
                      Style="{StaticResource DesignerItemStyle}">
            <Ellipse IsHitTestVisible="False" >
                <Ellipse.Fill>
                    <RadialGradientBrush Center="0.2, 0.2" GradientOrigin="0.2, 0.2" RadiusX="0.8" RadiusY="0.8">
                        <GradientStop Color="LightBlue" Offset="0"/>
                        <GradientStop Color="#FF33CF57" Offset="0.9"/>
                        <GradientStop Color="#FF31A067" Offset="0.437"/>
                    </RadialGradientBrush>
                </Ellipse.Fill>
            </Ellipse>
        </ContentControl>
    </Canvas>
</Window>

运行项目,此时可以拖动的, AY 一个wpf画图项目复习下【1/10】

我们加的装饰层,其实也在上面,只不过没内容而已

AY 一个wpf画图项目复习下【1/10】

接下来写Adorner,因为顶部有个AdornerLayer专门放这种类型控件的

添加一个上篇文章的测试adorner

 public class HasUpdateNotify : Adorner
    {
        private string notifyNumber = "5";

        public string NotifyNumber
        {
            get { return notifyNumber; }
            set { notifyNumber = value; }
        }

        public HasUpdateNotify(UIElement adornedElement, string nb)
            : base(adornedElement)
        {
            this.NotifyNumber = nb;
        }

        protected override void OnRender(DrawingContext drawingContext)
        {
            Rect adornedElementRect = new Rect(this.AdornedElement.DesiredSize);
            SolidColorBrush renderBrush = new SolidColorBrush(Colors.Red);
            renderBrush.Opacity = 1.0;
            Pen renderPen = new Pen(new SolidColorBrush(Colors.Red), 1);
            double renderRadius = 10.0;
            Point tr = adornedElementRect.TopRight;
            tr.Offset(-5, 9);
            drawingContext.DrawEllipse(renderBrush, renderPen, tr, renderRadius, renderRadius);

            if (!string.IsNullOrEmpty(notifyNumber))
            {
                tr.Offset(-3, -7);
                FormattedText numberTxt = new FormattedText(notifyNumber,
                                                      System.Globalization.CultureInfo.CurrentCulture,
                                                      System.Windows.FlowDirection.LeftToRight,
                                                      new Typeface(System.Windows.SystemFonts.MessageFontFamily, FontStyles.Normal, FontWeights.Normal, FontStretches.Normal),
                                                      12,
                                                      System.Windows.Media.Brushes.White);

                drawingContext.DrawText(numberTxt, tr);
            }
        }

然后在这里加上装饰

AY 一个wpf画图项目复习下【1/10】

当然这不会显示,因为上方的ShowDecorator是false

我们修改DesignerItem的模板

AY 一个wpf画图项目复习下【1/10】

然后运行效果如下

AY 一个wpf画图项目复习下【1/10】

此时我们只要实现 resize和rotate的adorner,加在这里就行了。

当然,上面只是渲染效果,

真正是添加元素,并且具有响应事件,很明显当前需求是这样的一个adorner

一个基本的Adorner代码模板

   public class ResizeAdorner : Adorner
    {
        VisualCollection visuals;
        public ResizeAdorner(UIElement adorned) : base(adorned)
        {
            visuals = new VisualCollection(this);
        }

        protected override Size ArrangeOverride(Size finalSize)
        {
            return finalSize;
        }

        protected override Visual GetVisualChild(int index)
        {
            return visuals[index];
        }

        protected override int VisualChildrenCount
        {
            get
            {
                return visuals.Count;
            }
        }
    }

经过修改:我们先实现Size的,size是4个角落+4条方向的thumb线

索性封装一个控件叫 SizeChrome,然后每个thumb执行的特殊性,原生thumb满足不了,继承写个ResizeThumb

SizeChrome代码如下,只是提供一个容器用的,可以理解容器

using System.Windows;
using System.Windows.Controls;

namespace DiagramTool2
{
    public class SizeChrome : Control
    {
        static SizeChrome()
        {
            FrameworkElement.DefaultStyleKeyProperty.OverrideMetadata(typeof(SizeChrome), new FrameworkPropertyMetadata(typeof(SizeChrome)));
        }
    }
}

SizeAdorner也很简单

using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Media;

namespace DiagramTool2
{
    public class SizeAdorner : Adorner
    {
        private SizeChrome chrome;
        private VisualCollection visuals;
        private ContentControl designerItem;

        protected override int VisualChildrenCount
        {
            get
            {
                return this.visuals.Count;
            }
        }

        public SizeAdorner(ContentControl designerItem)
            : base(designerItem)
        {
            this.SnapsToDevicePixels = true;
            this.designerItem = designerItem;
            this.chrome = new SizeChrome();
            this.chrome.DataContext = designerItem;
            this.visuals = new VisualCollection(this);
            this.visuals.Add(this.chrome);
        }

        protected override Visual GetVisualChild(int index)
        {
            return this.visuals[index];
        }

        protected override Size ArrangeOverride(Size arrangeBounds)
        {
            this.chrome.Arrange(new Rect(new Point(0.0, 0.0), arrangeBounds));
            return arrangeBounds;
        }
    }
}

我们完全可以把SizeChrome内部的东西,在Adorner里面add进去,每个拐角的thumb增加事件,然后只需要给contentcontrol的DesignerItemDecorator中加入这个adorner就可以完成,但是这样不易维护。

所以提取出一个XXChrome来容纳 一些东西,这里也指定了Chrome的DataContext为ContentControl了,调用这个adorner时候会传递进来的。

第三步骤,实现ResizeThumb

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Documents;
using System.Windows.Media;
using System.Collections.Generic;

namespace DiagramTool2
{
    public class ResizeThumb : Thumb
    {
        private RotateTransform rotateTransform;
        private double angle;
        private Adorner adorner;
        private Point transformOrigin;
        private ContentControl designerItem;
        private Canvas canvas;

        public ResizeThumb()
        {
            DragStarted += new DragStartedEventHandler(this.ResizeThumb_DragStarted);
            DragDelta += new DragDeltaEventHandler(this.ResizeThumb_DragDelta);
    
        }


        private void ResizeThumb_DragStarted(object sender, DragStartedEventArgs e)
        {
            this.designerItem = this.DataContext as ContentControl;

            if (this.designerItem != null)
            {
                this.canvas = VisualTreeHelper.GetParent(this.designerItem) as Canvas;

                if (this.canvas != null)
                {
                    this.transformOrigin = this.designerItem.RenderTransformOrigin;

                    this.rotateTransform = this.designerItem.RenderTransform as RotateTransform;
                    if (this.rotateTransform != null)
                    {
                        this.angle = this.rotateTransform.Angle * Math.PI / 180.0;
                    }
                    else
                    {
                        this.angle = 0.0d;
                    }

          
                }
            }
        }

        private void ResizeThumb_DragDelta(object sender, DragDeltaEventArgs e)
        {
            if (this.designerItem != null)
            {
                double deltaVertical, deltaHorizontal;

                switch (VerticalAlignment)
                {
                    case System.Windows.VerticalAlignment.Bottom:
                        deltaVertical = Math.Min(-e.VerticalChange, this.designerItem.ActualHeight - this.designerItem.MinHeight);
                        Canvas.SetTop(this.designerItem, Canvas.GetTop(this.designerItem) + (this.transformOrigin.Y * deltaVertical * (1 - Math.Cos(-this.angle))));
                        Canvas.SetLeft(this.designerItem, Canvas.GetLeft(this.designerItem) - deltaVertical * this.transformOrigin.Y * Math.Sin(-this.angle));
                        this.designerItem.Height -= deltaVertical;
                        break;
                    case System.Windows.VerticalAlignment.Top:
                        deltaVertical = Math.Min(e.VerticalChange, this.designerItem.ActualHeight - this.designerItem.MinHeight);
                        Canvas.SetTop(this.designerItem, Canvas.GetTop(this.designerItem) + deltaVertical * Math.Cos(-this.angle) + (this.transformOrigin.Y * deltaVertical * (1 - Math.Cos(-this.angle))));
                        Canvas.SetLeft(this.designerItem, Canvas.GetLeft(this.designerItem) + deltaVertical * Math.Sin(-this.angle) - (this.transformOrigin.Y * deltaVertical * Math.Sin(-this.angle)));
                        this.designerItem.Height -= deltaVertical;
                        break;
                    default:
                        break;
                }

                switch (HorizontalAlignment)
                {
                    case System.Windows.HorizontalAlignment.Left:
                        deltaHorizontal = Math.Min(e.HorizontalChange, this.designerItem.ActualWidth - this.designerItem.MinWidth);
                        Canvas.SetTop(this.designerItem, Canvas.GetTop(this.designerItem) + deltaHorizontal * Math.Sin(this.angle) - this.transformOrigin.X * deltaHorizontal * Math.Sin(this.angle));
                        Canvas.SetLeft(this.designerItem, Canvas.GetLeft(this.designerItem) + deltaHorizontal * Math.Cos(this.angle) + (this.transformOrigin.X * deltaHorizontal * (1 - Math.Cos(this.angle))));
                        this.designerItem.Width -= deltaHorizontal;
                        break;
                    case System.Windows.HorizontalAlignment.Right:
                        deltaHorizontal = Math.Min(-e.HorizontalChange, this.designerItem.ActualWidth - this.designerItem.MinWidth);
                        Canvas.SetTop(this.designerItem, Canvas.GetTop(this.designerItem) - this.transformOrigin.X * deltaHorizontal * Math.Sin(this.angle));
                        Canvas.SetLeft(this.designerItem, Canvas.GetLeft(this.designerItem) + (deltaHorizontal * this.transformOrigin.X * (1 - Math.Cos(this.angle))));
                        this.designerItem.Width -= deltaHorizontal;
                        break;
                    default:
                        break;
                }
            }

            e.Handled = true;
        }


    }
}

这里有个弧度

1弧度约为57.3°,而一π弧度等于180°。在数学和物理中,弧度是角的度量单位。它是由国际单位制导出的单位,单位缩写是rad。弧度也就是弧长等于半径的圆弧,其所对的圆心角

弧度 = 角度*PI/180

角度 = 弧度*180/PI

所以,这里把角度 转换弧度,方便下面的计算

AY 一个wpf画图项目复习下【1/10】

定义好后,用上去,那么当前ContentControl顶层就会多个SizeChrome出来

这里我们调整宽高,还显示当前宽高,我们加个转换器,显示整数的宽高

    public class DoubleFormatConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            double d = (double)value;
            return Math.Round(d);
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return null;
        }
    }
  <s:DoubleFormatConverter x:Key="doubleFormatConverter"/>

        <Style TargetType="{x:Type s:SizeChrome}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type s:SizeChrome}">
                        <Grid SnapsToDevicePixels="True">
                  
                            <Path Stroke="Red"
                  StrokeThickness="1"
                  Height="10"
                  VerticalAlignment="Bottom"
                  Margin="-2,0,-2,-15"
                  Stretch="Fill"
                  Data="M0,0 0,10 M 0,5 100,5 M 100,0 100,10"/>
                            <TextBlock Text="{Binding Path=Width, Converter={StaticResource doubleFormatConverter}}"
                       Background="White"
                       Padding="3,0,3,0"
                       Foreground="Red"
                       Margin="0,0,0,-18"
                       HorizontalAlignment="Center"
                       VerticalAlignment="Bottom"/>
                            <Path Stroke="Red"
                  StrokeThickness="1"
                  Width="10"
                  HorizontalAlignment="Right"
                  Margin="0,-2,-15,-2"
                  Stretch="Fill"
                  Data="M5,0 5,100 M 0,0 10,0 M 0,100 10,100"/>
                            <TextBlock Text="{Binding Path=Height, Converter={StaticResource doubleFormatConverter}}"
                       Background="White"
                       Foreground="Red"
                       Padding="3,0,3,0"
                       Margin="0,0,-18,0"
                       HorizontalAlignment="Right"
                       VerticalAlignment="Center">
                                <TextBlock.LayoutTransform>
                                    <RotateTransform Angle="90" CenterX="1" CenterY="0.5"/>
                                </TextBlock.LayoutTransform>
                            </TextBlock>
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

此时运行项目

AY 一个wpf画图项目复习下【1/10】

接下来添加 调整大小的,修改sizechrome外观

        <Style TargetType="{x:Type s:SizeChrome}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type s:SizeChrome}">
                        <Grid SnapsToDevicePixels="True">
                            <Grid>
                                <s:ResizeThumb Height="3" Cursor="SizeNS" Margin="0 -4 0 0"
          VerticalAlignment="Top" HorizontalAlignment="Stretch"/>
                                <s:ResizeThumb Width="3" Cursor="SizeWE" Margin="-4 0 0 0"
          VerticalAlignment="Stretch" HorizontalAlignment="Left"/>
                                <s:ResizeThumb Width="3" Cursor="SizeWE" Margin="0 0 -4 0"
          VerticalAlignment="Stretch" HorizontalAlignment="Right"/>
                                <s:ResizeThumb Height="3" Cursor="SizeNS" Margin="0 0 0 -4"
          VerticalAlignment="Bottom"  HorizontalAlignment="Stretch"/>
                                <s:ResizeThumb Width="7" Height="7" Cursor="SizeNWSE" Margin="-6 -6 0 0"
          VerticalAlignment="Top" HorizontalAlignment="Left"/>
                                <s:ResizeThumb Width="7" Height="7" Cursor="SizeNESW" Margin="0 -6 -6 0"
          VerticalAlignment="Top" HorizontalAlignment="Right"/>
                                <s:ResizeThumb Width="7" Height="7" Cursor="SizeNESW" Margin="-6 0 0 -6"
          VerticalAlignment="Bottom" HorizontalAlignment="Left"/>
                                <s:ResizeThumb Width="7" Height="7" Cursor="SizeNWSE" Margin="0 0 -6 -6"
          VerticalAlignment="Bottom" HorizontalAlignment="Right"/>
                            </Grid>
                            <Path Stroke="Red"
                  StrokeThickness="1"
                  Height="10"
                  VerticalAlignment="Bottom"
                  Margin="-2,0,-2,-15"
                  Stretch="Fill"
                  Data="M0,0 0,10 M 0,5 100,5 M 100,0 100,10"/>
                            <TextBlock Text="{Binding Path=Width, Converter={StaticResource doubleFormatConverter}}"
                       Background="White"
                       Padding="3,0,3,0"
                       Foreground="Red"
                       Margin="0,0,0,-18"
                       HorizontalAlignment="Center"
                       VerticalAlignment="Bottom"/>
                            <Path Stroke="Red"
                  StrokeThickness="1"
                  Width="10"
                  HorizontalAlignment="Right"
                  Margin="0,-2,-15,-2"
                  Stretch="Fill"
                  Data="M5,0 5,100 M 0,0 10,0 M 0,100 10,100"/>
                            <TextBlock Text="{Binding Path=Height, Converter={StaticResource doubleFormatConverter}}"
                       Background="White"
                       Foreground="Red"
                       Padding="3,0,3,0"
                       Margin="0,0,-18,0"
                       HorizontalAlignment="Right"
                       VerticalAlignment="Center">
                                <TextBlock.LayoutTransform>
                                    <RotateTransform Angle="90" CenterX="1" CenterY="0.5"/>
                                </TextBlock.LayoutTransform>
                            </TextBlock>
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

然后运行

AY 一个wpf画图项目复习下【1/10】

同样的方式,我们可以把旋转按钮也加在SizeChrome里面,但是想到一个更好的方案,把旋转和缩放放在一个adorner,然后尺寸显示放在第二个adorner,在resizethumb的dragcompleted时候,移除具体的尺寸数值,本来这里也应该有2个adorner。或者可以再sizechrome内部加一个依赖属性,用来控制边缘数值线的显示。

同样的方式,新增一个ResizeRotateChrome

using System.Windows;
using System.Windows.Controls;

namespace DiagramTool2
{
    public class ResizeRotateChrome : Control
    {
        static ResizeRotateChrome()
        {
            FrameworkElement.DefaultStyleKeyProperty.OverrideMetadata(typeof(ResizeRotateChrome), new FrameworkPropertyMetadata(typeof(ResizeRotateChrome)));
        }
    }
}

ResizeRotateAdorner

using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Media;

namespace DiagramTool2
{
    public class ResizeRotateAdorner : Adorner
    {
        private VisualCollection visuals;
        private ResizeRotateChrome chrome;

        protected override int VisualChildrenCount
        {
            get
            {
                return this.visuals.Count;
            }
        }

        public ResizeRotateAdorner(ContentControl designerItem)
            : base(designerItem)
        {
            SnapsToDevicePixels = true;
            this.chrome = new ResizeRotateChrome();
            this.chrome.DataContext = designerItem;
            this.visuals = new VisualCollection(this);
            this.visuals.Add(this.chrome);
        }

        protected override Size ArrangeOverride(Size arrangeBounds)
        {
            this.chrome.Arrange(new Rect(arrangeBounds));
            return arrangeBounds;
        }

        protected override Visual GetVisualChild(int index)
        {
            return this.visuals[index];
        }
    }
}

接下来实现关键的旋转

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

namespace DiagramTool2
{
    public class RotateThumb : Thumb
    {
        private double initialAngle;
        private RotateTransform rotateTransform;
        private Vector startVector;
        private Point centerPoint;
        private ContentControl designerItem;
        private Canvas canvas;

        public RotateThumb()
        {
            DragDelta += new DragDeltaEventHandler(this.RotateThumb_DragDelta);
            DragStarted += new DragStartedEventHandler(this.RotateThumb_DragStarted);
        }

        private void RotateThumb_DragStarted(object sender, DragStartedEventArgs e)
        {
            this.designerItem = DataContext as ContentControl;

            if (this.designerItem != null)
            {
                this.canvas = VisualTreeHelper.GetParent(this.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;
                    }
                }
            }
        }

        private void RotateThumb_DragDelta(object sender, 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);
                this.designerItem.InvalidateMeasure();
            }
        }
    }
}

修改ResizeThumb

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Documents;
using System.Windows.Media;
using System.Collections.Generic;

namespace DiagramTool2
{
    public class ResizeThumb : Thumb
    {
        private RotateTransform rotateTransform;
        private double angle;
        private Adorner adorner;
        private Point transformOrigin;
        private ContentControl designerItem;
        private Canvas canvas;

        public ResizeThumb()
        {
            DragStarted += new DragStartedEventHandler(this.ResizeThumb_DragStarted);
            DragDelta += new DragDeltaEventHandler(this.ResizeThumb_DragDelta);
            DragCompleted += new DragCompletedEventHandler(this.ResizeThumb_DragCompleted);
        }

        private void ResizeThumb_DragStarted(object sender, DragStartedEventArgs e)
        {
            this.designerItem = this.DataContext as ContentControl;

            if (this.designerItem != null)
            {
                this.canvas = VisualTreeHelper.GetParent(this.designerItem) as Canvas;

                if (this.canvas != null)
                {
                    this.transformOrigin = this.designerItem.RenderTransformOrigin;

                    this.rotateTransform = this.designerItem.RenderTransform as RotateTransform;
                    if (this.rotateTransform != null)
                    {
                        this.angle = this.rotateTransform.Angle * Math.PI / 180.0;
                    }
                    else
                    {
                        this.angle = 0.0d;
                    }

                    AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(this.canvas);
                    if (adornerLayer != null)
                    {
                        this.adorner = new SizeAdorner(this.designerItem);
                        adornerLayer.Add(this.adorner);
                    }
                }
            }
        }

        private void ResizeThumb_DragDelta(object sender, DragDeltaEventArgs e)
        {
            if (this.designerItem != null)
            {
                double deltaVertical, deltaHorizontal;

                switch (VerticalAlignment)
                {
                    case System.Windows.VerticalAlignment.Bottom:
                        deltaVertical = Math.Min(-e.VerticalChange, this.designerItem.ActualHeight - this.designerItem.MinHeight);
                        Canvas.SetTop(this.designerItem, Canvas.GetTop(this.designerItem) + (this.transformOrigin.Y * deltaVertical * (1 - Math.Cos(-this.angle))));
                        Canvas.SetLeft(this.designerItem, Canvas.GetLeft(this.designerItem) - deltaVertical * this.transformOrigin.Y * Math.Sin(-this.angle));
                        this.designerItem.Height -= deltaVertical;
                        break;
                    case System.Windows.VerticalAlignment.Top:
                        deltaVertical = Math.Min(e.VerticalChange, this.designerItem.ActualHeight - this.designerItem.MinHeight);
                        Canvas.SetTop(this.designerItem, Canvas.GetTop(this.designerItem) + deltaVertical * Math.Cos(-this.angle) + (this.transformOrigin.Y * deltaVertical * (1 - Math.Cos(-this.angle))));
                        Canvas.SetLeft(this.designerItem, Canvas.GetLeft(this.designerItem) + deltaVertical * Math.Sin(-this.angle) - (this.transformOrigin.Y * deltaVertical * Math.Sin(-this.angle)));
                        this.designerItem.Height -= deltaVertical;
                        break;
                    default:
                        break;
                }

                switch (HorizontalAlignment)
                {
                    case System.Windows.HorizontalAlignment.Left:
                        deltaHorizontal = Math.Min(e.HorizontalChange, this.designerItem.ActualWidth - this.designerItem.MinWidth);
                        Canvas.SetTop(this.designerItem, Canvas.GetTop(this.designerItem) + deltaHorizontal * Math.Sin(this.angle) - this.transformOrigin.X * deltaHorizontal * Math.Sin(this.angle));
                        Canvas.SetLeft(this.designerItem, Canvas.GetLeft(this.designerItem) + deltaHorizontal * Math.Cos(this.angle) + (this.transformOrigin.X * deltaHorizontal * (1 - Math.Cos(this.angle))));
                        this.designerItem.Width -= deltaHorizontal;
                        break;
                    case System.Windows.HorizontalAlignment.Right:
                        deltaHorizontal = Math.Min(-e.HorizontalChange, this.designerItem.ActualWidth - this.designerItem.MinWidth);
                        Canvas.SetTop(this.designerItem, Canvas.GetTop(this.designerItem) - this.transformOrigin.X * deltaHorizontal * Math.Sin(this.angle));
                        Canvas.SetLeft(this.designerItem, Canvas.GetLeft(this.designerItem) + (deltaHorizontal * this.transformOrigin.X * (1 - Math.Cos(this.angle))));
                        this.designerItem.Width -= deltaHorizontal;
                        break;
                    default:
                        break;
                }
            }

            e.Handled = true;
        }

        private void ResizeThumb_DragCompleted(object sender, DragCompletedEventArgs e)
        {
            if (this.adorner != null)
            {
                AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(this.canvas);
                if (adornerLayer != null)
                {
                    adornerLayer.Remove(this.adorner);
                }

                this.adorner = null;
            }
        }
    }
}

拖大小完成后,从canvas顶部移除 移除adorner,这个adorner是SizeAdorner,里面放的SizeChrome这个控件,我们修改SizeChrome的外观为那个尺寸线条就好了,把那几个调整宽高的点移动到旋转的ResizeRotateChrome中去。

修改DesignerItemDecorator直接增加一个旋转和调整大小的装饰器。

AY 一个wpf画图项目复习下【1/10】

修改外观样式,

<Style TargetType="{x:Type Shape}" x:Key="ThumbCorner">
            <Setter Property="SnapsToDevicePixels" Value="true" />
            <Setter Property="Stroke" Value="#FFC8C8C8" />
            <Setter Property="StrokeThickness" Value=".5" />
            <Setter Property="Width" Value="7" />
            <Setter Property="Height" Value="7" />
            <Setter Property="Margin" Value="-2" />
            <Setter Property="Fill">
                <Setter.Value>
                    <RadialGradientBrush Center="0.2, 0.2" GradientOrigin="0.2, 0.2" RadiusX="0.8" RadiusY="0.8">
                        <GradientStop Color="White" Offset="0.0" />
                        <GradientStop Color="Gray" Offset="0.8" />
                    </RadialGradientBrush>
                </Setter.Value>
            </Setter>
        </Style>

        <Style TargetType="{x:Type s:ResizeRotateChrome}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type s:ResizeRotateChrome}">
                        <Grid>
                            <Grid  Margin="-3">
                                <s:RotateThumb Width="7"
                             Height="7"
                             Margin="0,-20,0,0"
                             Cursor="Hand"
                             VerticalAlignment="Top"
                             HorizontalAlignment="Center"/>
                                <s:ResizeThumb Height="3"
                             Cursor="SizeNS" Background="Red"
                             VerticalAlignment="Top"
                             HorizontalAlignment="Stretch"/>
                                <s:ResizeThumb Width="3"
                             Cursor="SizeWE"  Background="Red"
                             VerticalAlignment="Stretch"
                             HorizontalAlignment="Left"/>
                                <s:ResizeThumb Width="3"
                             Cursor="SizeWE"  Background="Red"
                             VerticalAlignment="Stretch"
                             HorizontalAlignment="Right"/>
                                <s:ResizeThumb Height="3"
                             Cursor="SizeNS"  Background="Red"
                             VerticalAlignment="Bottom"
                             HorizontalAlignment="Stretch"/>
                                <s:ResizeThumb Width="7"
                             Height="7"
                             Margin="-2"
                             Cursor="SizeNWSE"
                             VerticalAlignment="Top"
                             HorizontalAlignment="Left"/>
                                <s:ResizeThumb Width="7"
                             Height="7"
                             Margin="-2"
                             Cursor="SizeNESW"
                             VerticalAlignment="Top"
                             HorizontalAlignment="Right"/>
                                <s:ResizeThumb Width="7"
                             Height="7"
                             Margin="-2"
                             Cursor="SizeNESW"
                             VerticalAlignment="Bottom"
                             HorizontalAlignment="Left"/>
                                <s:ResizeThumb Width="7"
                             Height="7"
                             Margin="-2"
                             Cursor="SizeNWSE"
                             VerticalAlignment="Bottom"
                             HorizontalAlignment="Right"/>
                            </Grid>
                            <Grid IsHitTestVisible="False" Opacity="1" Margin="-3">
                                <Rectangle SnapsToDevicePixels="True"
                         StrokeThickness="1"
                         Margin="1"
                         Stroke="White"/>
                                <Line StrokeThickness="1" X1="0" Y1="0" X2="0" Y2="20"
                    HorizontalAlignment="Center"
                    VerticalAlignment="Top"
                    Margin="0,-19,0,0"
                    Stroke="White"/>
                                <Ellipse Style="{StaticResource ThumbCorner}" HorizontalAlignment="Center" VerticalAlignment="Top" Margin="-1,-20,0,0"/>
                                <Ellipse Style="{StaticResource ThumbCorner}" HorizontalAlignment="Left" VerticalAlignment="Top"/>
                                <Ellipse Style="{StaticResource ThumbCorner}" HorizontalAlignment="Right" VerticalAlignment="Top"/>
                                <Ellipse Style="{StaticResource ThumbCorner}" HorizontalAlignment="Left" VerticalAlignment="Bottom"/>
                                <Ellipse Style="{StaticResource ThumbCorner}" HorizontalAlignment="Right" VerticalAlignment="Bottom"/>
                            </Grid>
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>


        <s:DoubleFormatConverter x:Key="doubleFormatConverter"/>

        <Style TargetType="{x:Type s:SizeChrome}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type s:SizeChrome}">
                        <Grid SnapsToDevicePixels="True">
                            <Path Stroke="Red"
                  StrokeThickness="1"
                  Height="10"
                  VerticalAlignment="Bottom"
                  Margin="-2,0,-2,-15"
                  Stretch="Fill"
                  Data="M0,0 0,10 M 0,5 100,5 M 100,0 100,10"/>
                            <TextBlock Text="{Binding Path=Width, Converter={StaticResource doubleFormatConverter}}"
                       Background="White"
                       Padding="3,0,3,0"
                       Foreground="Red"
                       Margin="0,0,0,-18"
                       HorizontalAlignment="Center"
                       VerticalAlignment="Bottom"/>
                            <Path Stroke="Red"
                  StrokeThickness="1"
                  Width="10"
                  HorizontalAlignment="Right"
                  Margin="0,-2,-15,-2"
                  Stretch="Fill"
                  Data="M5,0 5,100 M 0,0 10,0 M 0,100 10,100"/>
                            <TextBlock Text="{Binding Path=Height, Converter={StaticResource doubleFormatConverter}}"
                       Background="White"
                       Foreground="Red"
                       Padding="3,0,3,0"
                       Margin="0,0,-18,0"
                       HorizontalAlignment="Right"
                       VerticalAlignment="Center">
                                <TextBlock.LayoutTransform>
                                    <RotateTransform Angle="90" CenterX="1" CenterY="0.5"/>
                                </TextBlock.LayoutTransform>
                            </TextBlock>
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

运行项目

AY 一个wpf画图项目复习下【1/10】

一个节点的 调整,旋转 特性就出来了。

客户端,只需要是ContentControl包裹的 的内容都可以被调整。

AY这篇文章,根据 这篇文章 ,自己理解源码编写。

时间有限,对此项目的 讲解还算挺彻底的了。

最后一步修改外观即可,5个顶点,再加一些 选中特性外观,就是一个完美的调整了。

====================www.ayjs.net       杨洋    wpfui.com        ayui      ay  aaronyang=======请不要转载谢谢了。=========

命名规范:

XXAdorner定义一个辅助的顶层外观,如果外观复杂,可以考虑增加一个XXChrome的控件,来管理这个顶层外观

推荐您阅读更多有关于“”的文章


以上所述就是小编给大家介绍的《AY 一个wpf画图项目复习下【1/10】》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

人工智能产品经理——AI时代PM修炼手册

人工智能产品经理——AI时代PM修炼手册

张竞宇 / 电子工业出版社 / 2018-6 / 59

随着人工智能热潮的兴起,企业对人工智能领域产品经理的人才需求也开始井喷,人工智能产品经理成为顺应时代潮流的重要人力资源。实际上,人工智能确实给现有的产品和服务带来了全方位的升级,这也给产品经理从业人员提出了更高的要求,是关注人工智能产品的产品经理们面临的一次关键转型考验。 《人工智能产品经理——AI时代PM修炼手册》从知识体系、能力模型、沟通技巧等方面帮助大家系统地梳理了人工智能产品经理所必......一起来看看 《人工智能产品经理——AI时代PM修炼手册》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

SHA 加密
SHA 加密

SHA 加密工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具