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

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

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

 

什么是装饰器?

 

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

 

装饰器的应用场景

 

装饰器的常见应用包括:

  • 向 控件添加功能句柄,使用户能够以某种方式操作元素(调整大小、旋转、重新定位等)。
  • 提供视觉反馈以指示各种状态,或者响应各种事件。
  • 在控件上叠加视觉装饰。

WPF为装饰视觉元素提供了一个基本框架。 下表列出了装饰对象时使用的主要类型及其用途。 下面是几个用法示例:

 

实现装饰器

 

在WPF中,提供了一个装饰器的抽象基类Adorner,自定义的装饰器只要继承此基类,并在OnRender方法中实现装饰器的重绘,具体如下如下所示:

装饰器1,在控件的四周实现连线锚点,用于提示用户,可以在此位置进行连线:

usingSystem;
usingSystem.Collections.Generic;
usingSystem.Linq;
usingSystem.Text;
usingSystem.Threading.Tasks;
usingSystem.Windows;
usingSystem.Windows.Documents;
usingSystem.Windows.Media;
namespaceDemoDragAndDrop.Adorners{
/// <summary>/// 锚点装饰器/// </summary>publicclassAnchorAdorner : Adorner    {
publicAnchorAdorner(UIElementadornedElement) : base(adornedElement)
        {
        }
protectedoverridevoidOnRender(DrawingContextdrawingContext)
        {
base.OnRender(drawingContext);
varsize=this.AdornedElement.DesiredSize;//获取需要装饰的UI元素的真实SizeRectrect=newRect(size);//定义一个矩形,从0,0开始,大小为sizevarpen=newPen(Brushes.Black, 2);
pen.DashStyle=DashStyles.Solid;
//drawingContext.DrawRectangle(Brushes.Transparent, pen, rect);//绘制矩形,第1个参数是填充色,第2个参数是边框,第3个参数是矩形大小,位置drawingContext.DrawEllipse(Brushes.WhiteSmoke, pen, newPoint(0, size.Height/2), 3, 3);//绘制锚点,左中drawingContext.DrawEllipse(Brushes.WhiteSmoke, pen, newPoint(size.Width, size.Height/2), 3, 3);//绘制锚点,右中drawingContext.DrawEllipse(Brushes.WhiteSmoke, pen, newPoint(size.Width/2, 0), 3, 3);//绘制锚点,上中drawingContext.DrawEllipse(Brushes.WhiteSmoke, pen, newPoint(size.Width/2, size.Height), 3, 3);//绘制锚点,下中        }
    }
}

装饰器2,修改大小装饰器,用于提示用户,可以在此位置进行拖动调整控件大小,如下所示:

usingSystem;
usingSystem.Collections.Generic;
usingSystem.Linq;
usingSystem.Text;
usingSystem.Threading.Tasks;
usingSystem.Windows;
usingSystem.Windows.Documents;
usingSystem.Windows.Media;
namespaceDemoDragAndDrop.Adorners{
/// <summary>/// 顶点装饰器/// </summary>publicclassRubberAdorner : Adorner    {
publicRubberAdorner(UIElementadornedElement) : base(adornedElement)
        {
        }
protectedoverridevoidOnRender(DrawingContextdrawingContext)
        {
base.OnRender(drawingContext);
varsize=this.AdornedElement.DesiredSize;//获取需要装饰的UI元素的真实SizeRectrect=newRect(size);//定义一个矩形,从0,0开始,大小为sizevarpen=newPen(Brushes.Black, 2);
pen.DashStyle=DashStyles.Solid;
//drawingContext.DrawRectangle(Brushes.Transparent, pen, rect);//绘制矩形,第1个参数是填充色,第2个参数是边框,第3个参数是矩形大小,位置drawingContext.DrawEllipse(Brushes.WhiteSmoke, pen, rect.TopLeft, 3, 3);//绘制锚点,左上drawingContext.DrawEllipse(Brushes.WhiteSmoke, pen, rect.TopRight, 3, 3);//绘制锚点,右上drawingContext.DrawEllipse(Brushes.WhiteSmoke, pen, rect.BottomLeft, 3, 3);//绘制锚点,坐下drawingContext.DrawEllipse(Brushes.WhiteSmoke, pen, rect.BottomRight, 3, 3);//绘制锚点,右下        }
    }
}

 

将装饰器绑定到元素

 

若要将装饰器绑定到特定的控件元素,请按照以下步骤操作:

通过AdornerLayer提供的静态方法GetAdornerLayer获得装饰层实例,再获取装饰层的装饰列表,然后添加装饰器,即可实现绑定,具体如下所示:

当鼠标进入时,绑定装饰器到控件元素

privatevoidMouseEnter(objectobj)
{
varelement= (UIElement)obj;
varadornerLayer=AdornerLayer.GetAdornerLayer(element);
Adorner[] adorners=adornerLayer.GetAdorners(element);
if (adornerLayer!=null&&adorners==null)
    {
adornerLayer.Add(newAnchorAdorner(element));
adornerLayer.Add(newRubberAdorner(element));
    }
}

 

从控件移除装饰器

 

移除装饰器和绑定装饰器相似,都是操作装饰列表来实现。如下所示:

当鼠标移出时,移除装饰器:

privatevoidMouseLeave(objectobj)
{
varelement= (UIElement)obj;
varadornerLayer=AdornerLayer.GetAdornerLayer(element);
Adorner[] adorners=adornerLayer.GetAdorners(element);
if (adorners!=null)
    {
foreach (varadornerinadorners)
        {
adornerLayer.Remove(adorner);
        }
    }
}

 

UI页面

 

在本示例中,UI页面代码较少,主要是实现了控件事件命令绑定,如下所示:

<Windowx:Class="DemoDragAndDrop.TestWindow"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:i="http://schemas.microsoft.com/xaml/behaviors"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"xmlns:local="clr-namespace:DemoDragAndDrop"mc:Ignorable="d"Title="TestWindow"Height="450"Width="800"><Grid><RectangleHeight="100"Stroke="Black"Fill="LightCyan"Width="100"><i:Interaction.Triggers><i:EventTriggerEventName="MouseEnter"><i:InvokeCommandActionCommand="{Binding MouseEnterCommand}"CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Rectangle}}"/></i:EventTrigger><i:EventTriggerEventName="MouseLeave"><i:InvokeCommandActionCommand="{Binding MouseLeaveCommand}"CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Rectangle}}"/></i:EventTrigger></i:Interaction.Triggers></Rectangle></Grid></Window>

 

示例效果

 

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

 

文献参考

 

1. 微软官方文档:https://learn.microsoft.com/zh-cn/dotnet/desktop/wpf/controls/adorners-overview?view=netframeworkdesktop-4.8

 

以上就是浅谈WPF之装饰器锚点的实现的全部内容,希望可以抛砖引玉,一起学习,共同进步。

相关文章
|
20天前
|
C# 开发者 Windows
基于Material Design风格开源、易用、强大的WPF UI控件库
基于Material Design风格开源、易用、强大的WPF UI控件库
|
8月前
|
C# Windows
WPF技术之图形系列Polygon控件
WPF Polygon是Windows Presentation Foundation (WPF)框架中的一个标记元素,用于绘制多边形形状。它可以通过设置多个点的坐标来定义多边形的形状,可以绘制任意复杂度的多边形。
460 0
|
8月前
|
C# Windows
WPF技术之RichTextBox控件
WPF RichTextBox是Windows Presentation Foundation (WPF)中提供的一个强大的文本编辑控件,它可以显示富文本格式的文本,支持多种文本处理操作。
347 0
|
4月前
|
前端开发 C# 容器
浅谈WPF之控件拖拽与拖动
使用过office的visio软件画图的小伙伴都知道,画图软件分为两部分,左侧图形库,存放各种图标,右侧是一个画布,将左侧图形库的图标控件拖拽到右侧画布,就会生成一个新的控件,并且可以自由拖动。那如何在WPF程序中,实现类似的功能呢?今天就以一个简单的小例子,简述如何在WPF中实现控件的拖拽和拖动,仅供学习分享使用,如有不足之处,还请指正。
108 2
|
8月前
|
数据挖掘 数据处理 C#
WPF技术之DataGrid控件
WPF DataGrid是一种可以显示和编辑数据的界面控件。它可以作为表格形式展示数据,支持添加、删除、修改、排序和分组操作。
184 0
|
20天前
|
C# 开发者 C++
一套开源、强大且美观的WPF UI控件库
一套开源、强大且美观的WPF UI控件库
135 0
|
5月前
|
算法 C# UED
浅谈WPF之控件模板和数据模板
WPF不仅支持传统的Windows Forms编程的用户界面和用户体验设计,同时还推出了以模板为核心的新一代设计理念。在WPF中,通过引入模板,将数据和算法的“内容”和“形式”进行解耦。模板主要分为两大类:数据模板【Data Template】和控件模板【Control Template】。
96 8
|
8月前
|
定位技术 C# UED
WPF技术之ScrollViewer控件
WPF ScrollViewer是WPF中常用的一个控件,它提供了滚动视图的功能,可用于显示超出容器可视区域的内容。ScrollViewer通常用于容纳大量内容的控件,以在有限的空间内显示这些内容,并允许用户通过滚动来查看隐藏的部分。
717 0
|
8月前
|
前端开发 C#
WPF技术之ContentControl 控件
ContentControl 是 WPF 中的一个常见控件,用于显示单个内容元素。它可以包含任意类型的内容,包括文本、图像、控件等。
784 0
|
8月前
|
XML C# 数据格式
WPF技术之DocumentViewer控件
WPF 的 DocumentViewer 是一个强大的控件,用于在应用程序中显示各种类型的文档,如 XPS(XML Paper Specification)、FlowDocument 和 FixedDocument 等。
1086 1