翼度科技»论坛 编程开发 .net 查看内容

浅谈WPF之装饰器实现控件锚点

5

主题

5

帖子

15

积分

新手上路

Rank: 1

积分
15
使用过visio的都知道,在绘制流程图时,当选择或鼠标移动到控件时,都会在控件的四周出现锚点,以便于修改大小,移动位置,或连接线等,那此功能是如何实现的呢?在WPF开发中,想要在控件四周实现锚点,可以通过装饰器来实现,今天通过一个简单的小例子,简述如何在WPF开发中,应用装饰器,仅供学习分享使用,如有不足之处,还请指正。

 
什么是装饰器?

 
装饰器(Adorner)是一种特殊类型的 FrameworkElement,用于向用户提供视觉提示。 装饰器有很多用途,可用来向元素添加功能句柄,或者提供有关某个控件的状态信息。Adorner 是绑定到 UIElement 的自定义 FrameworkElement。 装饰器在 AdornerLayer 中呈现,它是始终位于装饰元素或装饰元素集合之上的呈现表面。 装饰器的呈现独立于装饰器绑定到的 UIElement 的呈现。 装饰器通常使用位于装饰元素左上部的标准 2D 坐标原点,相对于其绑定到的元素进行定位。
 
装饰器的应用场景

 
装饰器的常见应用包括:

  • 向 控件添加功能句柄,使用户能够以某种方式操作元素(调整大小、旋转、重新定位等)。
  • 提供视觉反馈以指示各种状态,或者响应各种事件。
  • 在控件上叠加视觉装饰。
WPF为装饰视觉元素提供了一个基本框架。 下表列出了装饰对象时使用的主要类型及其用途。 下面是几个用法示例:

 
实现装饰器

 
在WPF中,提供了一个装饰器的抽象基类Adorner,自定义的装饰器只要继承此基类,并在OnRender方法中实现装饰器的重绘,具体如下如下所示:
装饰器1,在控件的四周实现连线锚点,用于提示用户,可以在此位置进行连线:
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6. using System.Windows;
  7. using System.Windows.Documents;
  8. using System.Windows.Media;
  9. namespace DemoDragAndDrop.Adorners
  10. {
  11.     /// <summary>
  12.     /// 锚点装饰器
  13.     /// </summary>
  14.     public class AnchorAdorner : Adorner
  15.     {
  16.         public AnchorAdorner(UIElement adornedElement) : base(adornedElement)
  17.         {
  18.         }
  19.         protected override void OnRender(DrawingContext drawingContext)
  20.         {
  21.             base.OnRender(drawingContext);
  22.             var size = this.AdornedElement.DesiredSize;//获取需要装饰的UI元素的真实Size
  23.             Rect rect = new Rect(size);//定义一个矩形,从0,0开始,大小为size
  24.             var pen = new Pen(Brushes.Black, 2);
  25.             pen.DashStyle = DashStyles.Solid;
  26.             //drawingContext.DrawRectangle(Brushes.Transparent, pen, rect);//绘制矩形,第1个参数是填充色,第2个参数是边框,第3个参数是矩形大小,位置
  27.             drawingContext.DrawEllipse(Brushes.WhiteSmoke, pen, new Point(0, size.Height / 2), 3, 3);//绘制锚点,左中
  28.             drawingContext.DrawEllipse(Brushes.WhiteSmoke, pen, new Point(size.Width, size.Height / 2), 3, 3);//绘制锚点,右中
  29.             drawingContext.DrawEllipse(Brushes.WhiteSmoke, pen, new Point(size.Width / 2, 0), 3, 3);//绘制锚点,上中
  30.             drawingContext.DrawEllipse(Brushes.WhiteSmoke, pen, new Point(size.Width / 2, size.Height), 3, 3);//绘制锚点,下中
  31.         }
  32.     }
  33. }
复制代码
装饰器2,修改大小装饰器,用于提示用户,可以在此位置进行拖动调整控件大小,如下所示:
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6. using System.Windows;
  7. using System.Windows.Documents;
  8. using System.Windows.Media;
  9. namespace DemoDragAndDrop.Adorners
  10. {
  11.     /// <summary>
  12.     /// 顶点装饰器
  13.     /// </summary>
  14.     public class RubberAdorner : Adorner
  15.     {
  16.         public RubberAdorner(UIElement adornedElement) : base(adornedElement)
  17.         {
  18.         }
  19.         protected override void OnRender(DrawingContext drawingContext)
  20.         {
  21.             base.OnRender(drawingContext);
  22.             var size = this.AdornedElement.DesiredSize;//获取需要装饰的UI元素的真实Size
  23.             Rect rect = new Rect(size);//定义一个矩形,从0,0开始,大小为size
  24.             var pen = new Pen(Brushes.Black, 2);
  25.             pen.DashStyle = DashStyles.Solid;
  26.             //drawingContext.DrawRectangle(Brushes.Transparent, pen, rect);//绘制矩形,第1个参数是填充色,第2个参数是边框,第3个参数是矩形大小,位置
  27.             drawingContext.DrawEllipse(Brushes.WhiteSmoke, pen, rect.TopLeft, 3, 3);//绘制锚点,左上
  28.             drawingContext.DrawEllipse(Brushes.WhiteSmoke, pen, rect.TopRight, 3, 3);//绘制锚点,右上
  29.             drawingContext.DrawEllipse(Brushes.WhiteSmoke, pen, rect.BottomLeft, 3, 3);//绘制锚点,坐下
  30.             drawingContext.DrawEllipse(Brushes.WhiteSmoke, pen, rect.BottomRight, 3, 3);//绘制锚点,右下
  31.         }
  32.     }
  33. }
复制代码
 
将装饰器绑定到元素

 
若要将装饰器绑定到特定的控件元素,请按照以下步骤操作:
通过AdornerLayer提供的静态方法GetAdornerLayer获得装饰层实例,再获取装饰层的装饰列表,然后添加装饰器,即可实现绑定,具体如下所示:
当鼠标进入时,绑定装饰器到控件元素
  1. private void MouseEnter(object obj)
  2. {
  3.     var element = (UIElement)obj;
  4.     var adornerLayer = AdornerLayer.GetAdornerLayer(element);
  5.     Adorner[] adorners = adornerLayer.GetAdorners(element);
  6.     if (adornerLayer != null && adorners == null)
  7.     {
  8.         adornerLayer.Add(new AnchorAdorner(element));
  9.         adornerLayer.Add(new RubberAdorner(element));
  10.     }
  11. }
复制代码
 
从控件移除装饰器

 
移除装饰器和绑定装饰器相似,都是操作装饰列表来实现。如下所示:
当鼠标移出时,移除装饰器:
  1. private void MouseLeave(object obj)
  2. {
  3.     var element = (UIElement)obj;
  4.     var adornerLayer = AdornerLayer.GetAdornerLayer(element);
  5.     Adorner[] adorners = adornerLayer.GetAdorners(element);
  6.     if (adorners != null)
  7.     {
  8.         foreach (var adorner in adorners)
  9.         {
  10.             adornerLayer.Remove(adorner);
  11.         }
  12.     }
  13. }
复制代码
 
UI页面

 
在本示例中,UI页面代码较少,主要是实现了控件事件命令绑定,如下所示:
  1. <Window x:
  2.         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3.         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4.         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  5.         xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
  6.         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  7.         xmlns:local="clr-namespace:DemoDragAndDrop"
  8.         mc:Ignorable="d"
  9.         Title="TestWindow" Height="450" Width="800">
  10.     <Grid>
  11.         <Rectangle Height="100" Stroke="Black" Fill="LightCyan" Width="100">
  12.             <i:Interaction.Triggers>
  13.                 <i:EventTrigger EventName="MouseEnter">
  14.                     <i:InvokeCommandAction Command="{Binding MouseEnterCommand}" CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Rectangle}}"/>
  15.                 </i:EventTrigger>
  16.                 <i:EventTrigger EventName="MouseLeave">
  17.                     <i:InvokeCommandAction Command="{Binding MouseLeaveCommand}" CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Rectangle}}"/>
  18.                 </i:EventTrigger>
  19.             </i:Interaction.Triggers>
  20.         </Rectangle>
  21.     </Grid>
  22. </Window>
复制代码
 
示例效果

 
通过以上实现,就可以将装饰器绑定要控件元素,示例如下所示:

 
文献参考

 
1. 微软官方文档:https://learn.microsoft.com/zh-cn/dotnet/desktop/wpf/controls/adorners-overview?view=netframeworkdesktop-4.8
 
以上就是浅谈WPF之装饰器锚点的实现的全部内容,希望可以抛砖引玉,一起学习,共同进步。

来源:https://www.cnblogs.com/hsiang/archive/2023/12/17/17905031.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

举报 回复 使用道具