博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
WPF:从WPF Diagram Designer Part 3学习如何给设计器增加连接线功能
阅读量:6670 次
发布时间:2019-06-25

本文共 6585 字,大约阅读时间需要 21 分钟。

通过前面介绍的,我们学会了如何建立图形设计器的基本移动、选择、大小、旋转、缩略图、框选等基本功能。对于建模支持来说,流程图是必不可少的一种图形,那么我们如何让图形设计器支持在设计对象之间画上箭头呢?本篇将介绍图形设计器中的连接。

  画连接线存在多种实现方式,一种是在工具箱中提供一个连接元素,然后由设计人员选择后在两个组件中拖拽;还有一种就是由组件自身提供连接点,用户点击这个连接点后拖拽到另一个组件的连接点之上,这篇文章采用的是第二种方案。由于在建模中可能会存在多种不同的关系,所以在MetaModelEngine中的图形设计器将采用第一种方式,但是会提供第二种方式的快捷方式。

如何连接

  通过以下连接说明,我们可以知道存在连接Connection和连接点Connector两个概念,这两个概念分别由两个装饰对象来支持显示和操作。

将鼠标移到一个元素上面,元素四周会出现四个Connector,这个是在ConnectorDecoratorTemplate中进行定义的,其中在DesignerItem的模板也定义了一部分内容。

当鼠标移动到其中一个 Connector上,鼠标指针会变成会十字形状

 

当在connector上点击鼠标左键进行拖动时,connector将生成一个ConnectorAdorner,显示当前鼠标位置与源连接点的连线,当鼠标移动时,DesignerCanvas将在不断检查是否鼠标在潜在的目标连接点上

 

 

 
 

连接点 Connector

连接点是显示在设计元素之上的可供连接线关联的位置,它的Position属性代表连接点中心相对于DesignCanvas位置,其实现代码如下:

代码
 
public
class
Connector : Control, INotifyPropertyChanged
{
private
Point position;
public
Point Position
{
get
{
return
position; }
set
{
if
(position
!=
value)
{
position
=
value;
OnPropertyChanged(
"
Position
"
);
}
}
}
public
Connector()
{
//
fired when layout changes
base
.LayoutUpdated
+=
new
EventHandler(Connector_LayoutUpdated);
}
void
Connector_LayoutUpdated(
object
sender, EventArgs e)
{
DesignerCanvas designer
=
GetDesignerCanvas(
this
);
if
(designer
!=
null
)
{
//
get center position of this Connector relative to the DesignerCanvas
this
.Position
=
this
.TransformToAncestor(designer).Transform
(
new
Point(
this
.Width
/
2
,
this
.Height
/
2
));
}
}
...
}

连接点装饰模板 ConnectorDecoratorTemplate

DesignerItem的样式文件中包含了连接点控件如下:

 
<
Style TargetType
=
"
{x:Type s:DesignerItem}
"
>
<
Setter Property
=
"
Template
"
>
<
Setter.Value
>
<
ControlTemplate TargetType
=
"
{x:Type s:DesignerItem}
"
>
<
Grid DataContext
=
"
{Binding RelativeSource={RelativeSource TemplatedParent}}
"
>
 
<
ContentPresenter
 
/>
<
Control x:Name
=
"
PART_ConnectorDecorator
"
Visibility
=
"
Hidden
"
Template
=
"
{StaticResource ConnectorDecoratorTemplate}
"
/>
</
Grid
>
<
ControlTemplate.Triggers
>
<
Trigger Property
=
"
IsMouseOver
"
Value
=
"
true
"
>
<
Setter TargetName
=
"
PART_ConnectorDecorator
"
Property
=
"
Visibility
"
Value
=
"
Visible
"
/>
</
Trigger
>
</
ControlTemplate.Triggers
>
</
ControlTemplate
>
</
Setter.Value
>
</
Setter
>
</
Style
>

连接点控件样式如下:

 

 
<
ControlTemplate x:Key
=
"
ConnectorDecoratorTemplate
"
TargetType
=
"
{x:Type Control}
"
>
<
Grid Margin
=
"
-5
"
>
<
s:Connector Orientation
=
"
Left
"
VerticalAlignment
=
"
Center
"
HorizontalAlignment
=
"
Left
"
/>
<
s:Connector Orientation
=
"
Top
"
VerticalAlignment
=
"
Top
"
HorizontalAlignment
=
"
Center
"
/>
<
s:Connector Orientation
=
"
Right
"
VerticalAlignment
=
"
Center
"
HorizontalAlignment
=
"
Right
"
/>
<
s:Connector Orientation
=
"
Bottom
"
VerticalAlignment
=
"
Bottom
"
HorizontalAlignment
=
"
Center
"
/>
</
Grid
>
</
ControlTemplate
>

连接Connection

两个连接点之间连线后生成连接对象Connection,Connection有两个属性SourceSink,分别代码源Connector和目的Connector,当这两个Connector的Position改变时会通知Connection调用UpdatePathGeometry算法来更新连接线路径。

Connection的代码如下:

 

代码
 
public
class
Connection : Control, ISelectable, INotifyPropertyChanged
{
private
Connector source;
public
Connector Source
{
get
{
return
source;
}
set
{
if
(source
!=
value)
{
if
(source
!=
null
)
{
source.PropertyChanged
-=
new
PropertyChangedEventHandler(OnConnectorPositionChanged);
source.Connections.Remove(
this
);
}
source
=
value;
if
(source
!=
null
)
{
source.Connections.Add(
this
);
source.PropertyChanged
+=
new
PropertyChangedEventHandler(OnConnectorPositionChanged);
}
UpdatePathGeometry();
}
}
}
void
OnConnectorPositionChanged(
object
sender, PropertyChangedEventArgs e)
{
if
(e.PropertyName.Equals(
"
Position
"
))
{
UpdatePathGeometry();
}
}
....
}

定制化连接点布局

  • ConnectorDecoratorTemplate

有时缺省的四个连接点可能并不是我们所需要的,如一个三角形DesignerItem的定义如下:

 

 
<
Path IsHitTestVisible
=
"
False
"
Fill
=
"
Orange
"
Stretch
=
"
Fill
"
Data
=
"
M 0,10 5,0 10,10 Z
"
>
<
s:DesignerItem.DragThumbTemplate
>
<
ControlTemplate
>
<
Path Fill
=
"
Transparent
"
Stretch
=
"
Fill
"
Data
=
"
M 0,10 5,0 10,10 Z
"
/>
</
ControlTemplate
>
</
s:DesignerItem.DragThumbTemplate
>
</
Path
>

这个三角形显示的默认连接点如下图左边所示,但是我们需要的是下面所示的连接点,那么我们是如何定制化连接点布局的呢?

设计器通过DesignerItem的附加属性DesignerItem.ConnectorDecoratorTemplate来让我们自定义连接点装饰模板,为了定义出上图右边所示的连接点,我们可以修改三角形的定义如下:

 

 
<
Path IsHitTestVisible
=
"
False
"
Fill
=
"
Orange
"
Stretch
=
"
Fill
"
Data
=
"
M 0,10 5,0 10,10 Z
"
>
<!--
Custom DragThumb Template
-->
<
s:DesignerItem.DragThumbTemplate
>
<
ControlTemplate
>
<
Path Fill
=
"
Transparent
"
Stretch
=
"
Fill
"
Data
=
"
M 0,10 5,0 10,10 Z
"
/>
</
ControlTemplate
>
<
s:DesignerItem.DragThumbTemplate
>
<!--
Custom ConnectorDecorator Template
-->
<
s:DesignerItem.ConnectorDecoratorTemplate
>
<
ControlTemplate
>
<
Grid Margin
=
"
0
"
>
<
s:Connector Orientation
=
"
Top
"
HorizontalAlignment
=
"
Center
"
VerticalAlignment
=
"
Top
"
/>
<
s:Connector Orientation
=
"
Bottom
"
HorizontalAlignment
=
"
Center
"
VerticalAlignment
=
"
Bottom
"
/>
<
UniformGrid Columns
=
"
2
"
>
<
s:Connector Grid.Column
=
"
0
"
Orientation
=
"
Left
"
/>
<
s:Connector Grid.Column
=
"
1
"
Orientation
=
"
Right
"
/>
</
UniformGrid
>
</
Grid
>
</
ControlTemplate
>
</
s:DesignerItem.ConnectorDecoratorTemplate
>
</
Path
>

 

  • RelativePositionPanel和RelativePositionPanel.RelativePosition

以上三角形的连接点属于比较规格的图形,有时候遇到不规则图形时可能就比较难按照上面这种布局方式去设计了,于是我们设计了一个处理相对位置布局的一个RelativePositionPanel ,并给Connector 加了一个附加属性RelativePositionPanel.RelativePosition来处理使用相对位置来设置连接点的情况。

以下为定义五角星的示例:

上图五角星的定义如下:

 

 

 
<
Path IsHitTestVisible
=
"
False
"
Fill
=
"
Orange
"
Stretch
=
"
Fill
"
Data
=
"
M 9,2 11,7 17,7 12,10 14,15 9,12 4,15 6,10 1,7 7,7 Z
"
>
<!--
Custom DragThumb Template
-->
<
s:DesignerItem.DragThumbTemplate
>
<
ControlTemplate
>
<
Path Fill
=
"
Transparent
"
Stretch
=
"
Fill
"
Data
=
"
M 9,2 11,7 17,7 12,10 14,15 9,12 4,15 6,10 1,7 7,7 Z
"
/>
</
ControlTemplate
>
</
s:DesignerItem.DragThumbTemplate
>
<!--
Custom ConnectorDecorator Template
-->
<
s:DesignerItem.ConnectorDecoratorTemplate
>
<
ControlTemplate
>
<
c:RelativePositionPanel Margin
=
"
-4
"
>
<
s:Connector Orientation
=
"
Top
"
c:RelativePositionPanel.RelativePosition
=
"
0.5,0
"
/>
<
s:Connector Orientation
=
"
Left
"
c:RelativePositionPanel.RelativePosition
=
"
0,0.385
"
/>
<
s:Connector Orientation
=
"
Right
"
c:RelativePositionPanel.RelativePosition
=
"
1,0.385
"
/>
<
s:Connector Orientation
=
"
Bottom
"
c:RelativePositionPanel.RelativePosition
=
"
0.185,1
"
/>
<
s:Connector Orientation
=
"
Bottom
"
c:RelativePositionPanel.RelativePosition
=
"
0.815,1
"
/>
</
c:RelativePositionPanel
>
</
ControlTemplate
>
</
s:DesignerItem.ConnectorDecoratorTemplate
>
</
Path
>

MetaModelEngine将增加一种布局方式:按绝对位置布局连接点

 本文转自 jingen_zhou 51CTO博客,原文链接:http://blog.51cto.com/zhoujg/517450,如需转载请自行联系原作者

你可能感兴趣的文章
JavaWeb学习笔记——XML和SAX解析区别
查看>>
hdu1716排列2(stl:next_permutation+优先队列)
查看>>
Java 8 时间日期库的20个使用示例
查看>>
Android系统开发(4)——Autotools
查看>>
Nginx教程(一) Nginx入门教程
查看>>
【cocos2d-x 3.7 飞机大战】 决战南海I (十) 游戏主场景
查看>>
ORM进阶:Hibernate框架搭建及开发
查看>>
scala Wordcount
查看>>
单细胞文献分析 Quantitative single-cell rna-seq with unique molecular identifers
查看>>
面试2
查看>>
国庆第三天如何避免无聊
查看>>
Java多线程之细说线程池
查看>>
【274】Python 相关问题
查看>>
Linux-进程间的通信-信号集函数【转】
查看>>
js2word/html2word的简单实现
查看>>
jQuery.extend和jQuery.fn.extend的区别?
查看>>
职业发展
查看>>
Linux下环境变量设置
查看>>
phonegap 安装和使用eclipse
查看>>
ASP.NET MVC使用动态产生meta
查看>>