一、 引子
因为最近很忙(lan),很久没发博了。不少朋友对那个右键弹出菜单和连线的功能很感兴趣,因为VS本身是不包含这种功能的。
大家想这是什么鬼,怎么我的设计器没有,其实这是一个微软黑科技,如果用好,VS可以打造为你专用的神兵利器。
二、 什么是WPF设计器扩展
WPF 设计器基于一个具有可扩展的体系结构的框架,用户可以扩展这种框架以创建自己的自定义设计体验。
通过扩展 WPF 设计器对象模型,可以在很大程度上自定义 WPF 内容的设计时外观和行为。例如,可以通过下列方式扩展 WPF 设计器:
-
利用增强的图形自定义移动并调整标志符 的大小。
-
向设计图面添加一个标志符 ,在鼠标移动时该标志符 可以使所选控件倾斜。
-
在不同工具之间修改控件的设计时外观和行为。
-
WPF 设计器 体系结构支持 WPF 的所有表现力。这样便可以创建很多以前不可能拥有的可视化设计体验。
三、 如何实现设计器扩展
-
API总体架构
VS的状态分为设计时和运行时。设计时就是你打开VS,拖拽控件,界面布局,属性设置,代码编写,打交道的对象是Visual Studio;运行时就是你编译运行自己的exe文件。
-
如何实现
要实现一个完整的设计器扩展,要经历以下过程:
定义元数据,设计器需要知道哪些控件具有哪些扩展。这是通过Metadata 类来实现的:Metadata 类有一个AttributeTable方法,在其中构建了控件和功能(即相应的Provider)的映射关系。
using Microsoft.Windows.Design.Features;
using Microsoft.Windows.Design.Metadata;
[assembly: ProvideMetadata(typeof(HMIControl.VisualStudio.Design.Metadata))]
namespace HMIControl.VisualStudio.Design
{
internal class Metadata : IProvideAttributeTable
{
// Accessed by the designer to register any design-time metadata.
public AttributeTable AttributeTable
{
get
{
AttributeTableBuilder builder = new AttributeTableBuilder();
//InitializeAttributes(builder);
// Add the adorner provider to the design-time metadata.
builder.AddCustomAttributes(
typeof(LinkableControl),
new FeatureAttribute(typeof(ControlAdornerProvider))
//new FeatureAttribute(typeof(TagComplexContextMenuProvider))
);
builder.AddCustomAttributes(
typeof(HMIControlBase),
//new FeatureAttribute(typeof(LinkLineAdornerProvider)),
new FeatureAttribute(typeof(TagComplexContextMenuProvider)));
builder.AddCustomAttributes(
typeof(LinkLine),
new FeatureAttribute(typeof(LinkLineAdornerProvider)),
new FeatureAttribute(typeof(TagComplexContextMenuProvider)));
builder.AddCustomAttributes(
typeof(ButtonBase),
new FeatureAttribute(typeof(TagWriterContextMenuProvider)));
builder.AddCustomAttributes(
typeof(HMIButton),
new FeatureAttribute(typeof(TagWindowContextMenuProvider)),
new FeatureAttribute(typeof(TagComplexContextMenuProvider)),
new FeatureAttribute(typeof(TagWriterContextMenuProvider)));
builder.AddCustomAttributes(
typeof(FromTo),
new FeatureAttribute(typeof(TagWindowContextMenuProvider)));
return builder.CreateTable();
}
}
}
}
定义具体的Provider,所有的Provider都执行如下次序:根据用户选择,找到相关控件,并进行操作,将操作结果反馈给设计器。
根据设计器扩展的默认规则,在正确的位置使用正确的命名方式,否则你的扩展不会出现在设计器。这些默认规则包括:
命名空间规则:将设计器扩展项目的命名空间设置为HMIControl.VisualStudio.Design(HMIControl即控件库的命名空间),以便设计器能够发现元数据。
项目路径规则:将项目的输出路径设置为“..HMIControlbin”(HMIControl即控件库的项目路径)。 使控件的程序集与元数据程序集位于同一文件夹中,从而可为设计器启用元数据发现。
-
如何调试
一段不能加断点调试的代码会给编写者带来很大困扰。但设计器扩展有一个特殊性:没法在运行时加断点。好在微软早就为我们安排好了一切。具体可参考https://msdn.microsoft.com/zh-cn/sqlserver/bb514636
即调试时需要更改项目的属性,设置启动程序为VS的可执行文件: devenv.exe.相当于再打开一个新的VS作为运行时。调试时打开你的设计器操作,会发现第一个打开的VS中已经命中断点了。
四、 组态定制需求的实现
-
界面连线的实现
设计目标:实现两个HMI控件的连线。每个控件最多有上下左右四个位置(即锚点,也可以少于四个甚至没有),连线从A控件任一位置引出,自动寻找路径,连到B控件的任一位置;路径不能穿越其他控件,而应自动绕开。连线均为直线,不能为圆弧线或斜线;在控件位置改变时,连线重新计算并绘制。
设计过程:具有锚点的控件均继承LinkableControl类。锚点装饰器类为ControlAdorner,是一个控件容器,包含上下左右四个锚点,每个锚点由PinAdorner 定义,包含锚点的外形、自动生成路径等功能。路径发现由PathFinder类实现。与设计器交互通过继承AdornerProvider 类实现。
运行过程:通过AdornerProvider 类的Activate事件,获取当前点击(激活)的控件并转换为LinkableControl,并找到控件的父容器Panel、控件的装饰器ControlAdorner及其包含的每个PinAdorner、设计器包装DesignerView。在每个PinAdorner的鼠标点击和拖放事件内,可探索到其他控件的锚点、规划路径、生成连线LinkLine。
同时要考虑设计器进行缩放时路径的变化,在DesignerView的ZoomLevelChanged事件中处理。
-
右键菜单的实现
设计过程:TagComplexContextMenuProvider 继承了ContextMenuProvider,如果菜单“ComplexEditor”被激活,触发Exeute事件,则弹出窗体TagComplexEditor,以设置控件的动画关联的变量表达式;操作结果将写回控件的TagReadText 属性。
-
未来改进
相关文章:
-
.NET十年回顾
-
开源纯C#工控 关+组态软件
-
开源纯C#工控 关+组态软件(三)加入一个新驱动:西门子S7
-
开源纯C#工控 关+组态软件(四)上下位机通讯原理
-
开源纯C#工控 关+组态软件(五)从 关到人机界面
-
开源纯C#工控 关+组态软件(六)图元组件
-
开源纯C#工控 关+组态软件(七)数据采集与归档
-
开源纯C#工控 关+组态软件(八)表达式编译器
github地址:https://github.com/GavinYellow/SharpSCADA。QQ群:102486275
原文地址:http://www.cnblogs.com/evilcat/p/8859223.html
声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!