WPF 之 自定义Shape
AMindMap需要一个Line,用以连接父ANode和子ANode,
简单说,就是一头大一头小的线,Wpf自带的Line是没这个功能。
Path可以画,不过,我的想法仍旧是绑定。那只能自己做咯。
图例 |
正文 |
既然Line,Rectangle等都是继承自Shape的,直接新建一个类继承自Sharp.
1 Public Class ALine 2 Inherits Shape 3 4 Protected Overrides ReadOnly Property DefiningGeometry As System.Windows.Media.Geometry 5 Get 6 7 End Get 8 End Property 9 End Class 10
继承完Shape,ALine中自动添加了一个需要重写的只读属性,从字面上就可以理解
为自定义shape的内容了。返回一个Geometry,那岂不是嗯嗯嗯?
ALine的属性 |
一头大一头小的Line也是Line,那就要有两个端点,并且,端点的数值是需要被
绑定的,大声一起说,“DependencyProperty”
1 2 #Region " X1 DependencyProperty " 3 ''' <summary> 4 ''' PropertyComment 5 ''' </summary> 6 ''' <remarks></remarks> 7 Public Shared ReadOnly X1Property As DependencyProperty = _ 8 DependencyProperty.Register( 9 "X1", GetType(Double), GetType(ALine), New FrameworkPropertyMetadata( _ 10 0.0, FrameworkPropertyMetadataOptions.AffectsMeasure)) 11 12 Public Property X1() As Double 13 Get 14 Return GetValue(X1Property) 15 End Get 16 Set(ByVal Value As Double) 17 SetValue(X1Property, Value) 18 End Set 19 End Property 20 #End Region 21 22 #Region " Y1 DependencyProperty " 23 ''' <summary> 24 ''' PropertyComment 25 ''' </summary> 26 ''' <remarks></remarks> 27 Public Shared ReadOnly Y1Property As DependencyProperty = _ 28 DependencyProperty.Register( 29 "Y1", GetType(Double), GetType(ALine), New FrameworkPropertyMetadata( _ 30 0.0, FrameworkPropertyMetadataOptions.AffectsMeasure)) 31 32 Public Property Y1() As Double 33 Get 34 Return GetValue(Y1Property) 35 End Get 36 Set(ByVal Value As Double) 37 SetValue(Y1Property, Value) 38 End Set 39 End Property 40 41 #End Region 42 43 #Region " X2 DependencyProperty " 44 ''' <summary> 45 ''' PropertyComment 46 ''' </summary> 47 ''' <remarks></remarks> 48 Public Shared ReadOnly X2Property As DependencyProperty = _ 49 DependencyProperty.Register( 50 "X2", GetType(Double), GetType(ALine), New FrameworkPropertyMetadata( _ 51 0.0, FrameworkPropertyMetadataOptions.AffectsMeasure)) 52 53 Public Property X2() As Double 54 Get 55 Return GetValue(X2Property) 56 End Get 57 Set(ByVal Value As Double) 58 SetValue(X2Property, Value) 59 End Set 60 End Property 61 62 #End Region 63 64 #Region " Y2 DependencyProperty " 65 ''' <summary> 66 ''' PropertyComment 67 ''' </summary> 68 ''' <remarks></remarks> 69 Public Shared ReadOnly Y2Property As DependencyProperty = _ 70 DependencyProperty.Register( 71 "Y2", GetType(Double), GetType(ALine), New FrameworkPropertyMetadata( _ 72 0.0, FrameworkPropertyMetadataOptions.AffectsMeasure)) 73 74 Public Property Y2() As Double 75 Get 76 Return GetValue(Y2Property) 77 End Get 78 Set(ByVal Value As Double) 79 SetValue(Y2Property, Value) 80 End Set 81 End Property 82 83 #End Region 84 85 #Region " TailWidth DependencyProperty " 86 ''' <summary> 87 ''' PropertyComment 88 ''' </summary> 89 ''' <remarks></remarks> 90 Public Shared ReadOnly TailWidthProperty As DependencyProperty = _ 91 DependencyProperty.Register( 92 "TailWidth", GetType(Double), GetType(ALine), New FrameworkPropertyMetadata( _ 93 3.0, FrameworkPropertyMetadataOptions.AffectsMeasure)) 94 Public Property TailWidth() As Double 95 Get 96 Return GetValue(TailWidthProperty) 97 End Get 98 Set(ByVal Value As Double) 99 SetValue(TailWidthProperty, Value) 100 End Set 101 End Property 102 103 #End Region
这里定义了X1,Y1,X2,Y2,TailWidth,这些属性足够说明,线的位置和尾部粗细。
ALine的内容 |
一个楔形是怎么画的呢?这只是一个几何问题,还是画一张图说明吧。
Sorry哈,反正就是Atan,sin,cos一通算,画图太费劲了,我就歇了哈。
代码 强制重载的DefiningGeometry |
1 2 Protected Overrides ReadOnly Property DefiningGeometry As System.Windows.Media.Geometry 3 Get 4 Dim mGeometry As New StreamGeometry 5 mGeometry.FillRule = FillRule.EvenOdd 6 7 Using context As StreamGeometryContext = mGeometry.Open 8 DrawLineGeometry(context) 9 End Using 10 mGeometry.Freeze() 11 Return mGeometry 12 End Get 13 End Property 14 15 Private Sub DrawLineGeometry(ByVal context As StreamGeometryContext) 16 Dim theta As Double = Math.Atan2(Y1 - Y2, X1 - X2) 17 Dim sint As Double = Math.Sin(theta) 18 Dim cost As Double = Math.Cos(theta) 19 Dim pt1 As Point = New Point(X2, Y2) 20 Dim pt2 As Point = New Point(X1 - TailWidth * sint, Y1 + TailWidth * cost) 21 Dim pt3 As Point = New Point(X1 + TailWidth * sint, Y1 - TailWidth * cost) 22 context.BeginFigure(pt1, True, True) 23 context.LineTo(pt2, True, True) 24 context.LineTo(pt3, True, True) 25 End Sub
实例 |
在一个空白窗口中,像使用Line一样。
1 <local:ALine X1="10" Y1="10" X2="100" Y2="100" TailWidth="10" 2 Fill="LightBlue" 3 Canvas.Left="93" Canvas.Top="76" 4 > 5 </local:ALine>
就这个效果
我不得不说,这个思路是在网上找到的,既然找到了,给大家分享一下,是一件好事儿。