none
wpf and vb.net example of attaching a line to two shapes

    Question

  • Hello everyone,

    I have a simple user control that is added to a canvas when the user pushes a button.  They can then reposition the control by dragging it around the canvas.  When they press the button again, another control is added to the form.  What I'd like to do is connect the two shapes together with a line and the line stay attached to both control when either are dragged around the canvas.

    I've found a few examples online, but they're all in C# and that's not really my strong point. I've tried converting the code using various online converters but haven't had much luck in being able to port the solution in to my project. 

    Does someone have, or would they be willing to code a simple example using vb.net?  Hopefully with a simple example, I can learn a bit and port it in to my project.

    Thanks in advance!

    Tuesday, December 20, 2011 2:22 PM

Answers

  • Following link is a great article for shape connector

    http://denisvuyka.wordpress.com/2007/10/13/wpf-draggable-objects-and-simple-shape-connectors/

    The code is in C# so I have converted MyThumb class to VB.NET.

    Public Class MyThumb
        Inherits Thumb
    #Region "Properties"
        Public Shared ReadOnly TitleProperty As DependencyProperty = DependencyProperty.Register("Title"GetType(String), GetType(MyThumb), New UIPropertyMetadata(""))
        Public Shared ReadOnly ImageSourceProperty As DependencyProperty = DependencyProperty.Register("ImageSource"GetType(String), GetType(MyThumb), New UIPropertyMetadata(""))
     
        ' This property will hanlde the content of the textblock element taken from control template
        Public Property Title() As String
            Get
                Return DirectCast(GetValue(TitleProperty), String)
            End Get
            Set(value As String)
                SetValue(TitleProperty, value)
            End Set
        End Property
     
        ' This property will handle the content of the image element taken from control template
        Public Property ImageSource() As String
            Get
                Return DirectCast(GetValue(ImageSourceProperty), String)
            End Get
            Set(value As String)
                SetValue(ImageSourceProperty, value)
            End Set
        End Property
     
        Public Property EndLines() As List(Of LineGeometry)
            Get
                Return m_EndLines
            End Get
            Private Set(value As List(Of LineGeometry))
                m_EndLines = value
            End Set
        End Property
        Private m_EndLines As List(Of LineGeometry)
        Public Property StartLines() As List(Of LineGeometry)
            Get
                Return m_StartLines
            End Get
            Private Set(value As List(Of LineGeometry))
                m_StartLines = value
            End Set
        End Property
        Private m_StartLines As List(Of LineGeometry)
    #End Region
     
    #Region "Constructors"
        Public Sub New()
            MyBase.New()
            StartLines = New List(Of LineGeometry)()
            EndLines = New List(Of LineGeometry)()
        End Sub
     
        Public Sub New(template As ControlTemplate, title As String, imageSource As String, position As Point)
            Me.New()
            Me.Template = template
            Me.Title = If((title IsNot Nothing), title, String.Empty)
            Me.ImageSource = If((imageSource IsNot Nothing), imageSource, String.Empty)
            Me.SetPosition(position)
        End Sub
     
        Public Sub New(template As ControlTemplate, title As String, imageSource As String, position As Point, dragDelta As DragDeltaEventHandler)
            Me.New(template, title, imageSource, position)
            AddHandler Me.DragDelta, dragDelta
        End Sub
    #End Region
     
        ' Helper method for setting the position of our thumb
        Public Sub SetPosition(value As Point)
            Canvas.SetLeft(Me, value.X)
            Canvas.SetTop(Me, value.Y)
        End Sub
     
    #Region "Linking logic"
        ' This method establishes a link between current thumb and specified thumb.
        ' Returns a line geometry with updated positions to be processed outside.
        Public Function LinkTo(target As MyThumbAs LineGeometry
            ' Create new line geometry
            Dim line As New LineGeometry()
            ' Save as starting line for current thumb
            Me.StartLines.Add(line)
            ' Save as ending line for target thumb
            target.EndLines.Add(line)
            ' Ensure both tumbs the latest layout
            Me.UpdateLayout()
            target.UpdateLayout()
            ' Update line position
            line.StartPoint = New Point(Canvas.GetLeft(Me) + Me.ActualWidth / 2, Canvas.GetTop(Me) + Me.ActualHeight / 2)
            line.EndPoint = New Point(Canvas.GetLeft(target) + target.ActualWidth / 2, Canvas.GetTop(target) + target.ActualHeight / 2)
            ' return line for further processing
            Return line
        End Function
     
        ' This method establishes a link between current thumb and target thumb using a predefined line geometry
        ' Note: this is commonly to be used for drawing links with mouse when the line object is predefined outside this class
        Public Function LinkTo(target As MyThumb, line As LineGeometryAs Boolean
            ' Save as starting line for current thumb
            Me.StartLines.Add(line)
            ' Save as ending line for target thumb
            target.EndLines.Add(line)
            ' Ensure both tumbs the latest layout
            Me.UpdateLayout()
            target.UpdateLayout()
            ' Update line position
            line.StartPoint = New Point(Canvas.GetLeft(Me) + Me.ActualWidth / 2, Canvas.GetTop(Me) + Me.ActualHeight / 2)
            line.EndPoint = New Point(Canvas.GetLeft(target) + target.ActualWidth / 2, Canvas.GetTop(target) + target.ActualHeight / 2)
            Return True
        End Function
    #End Region
     
        ' This method updates all the starting and ending lines assigned for the given thumb 
        ' according to the latest known thumb position on the canvas
        Public Sub UpdateLinks()
            Dim left As Double = Canvas.GetLeft(Me)
            Dim top As Double = Canvas.GetTop(Me)
     
            For i As Integer = 0 To Me.StartLines.Count - 1
                Me.StartLines(i).StartPoint = New Point(left + Me.ActualWidth / 2, top + Me.ActualHeight / 2)
            Next
     
            For i As Integer = 0 To Me.EndLines.Count - 1
                Me.EndLines(i).EndPoint = New Point(left + Me.ActualWidth / 2, top + Me.ActualHeight / 2)
            Next
        End Sub
     
        ' Upon applying template we apply the "Title" and "ImageSource" properties to the template elements.
        Public Overrides Sub OnApplyTemplate()
            MyBase.OnApplyTemplate()
     
            ' Access the textblock element of template and assign it if Title property defined
            If Me.Title <> String.Empty Then
                Dim txt As TextBlock = TryCast(Me.Template.FindName("tplTextBlock"Me), TextBlock)
                If txt IsNot Nothing Then
                    txt.Text = Title
                End If
            End If
     
            ' Access the image element of our custom template and assign it if ImageSource property defined
            If Me.ImageSource <> String.Empty Then
                Dim img As Image = TryCast(Me.Template.FindName("tplImage"Me), Image)
                If img IsNot Nothing Then
                    img.Source = New BitmapImage(New Uri(Me.ImageSource, UriKind.Relative))
                End If
            End If
        End Sub
    End Class


    Gaurav Khanna | Microsoft VB.NET MVP
    • Marked as answer by sous2817_1 Tuesday, December 20, 2011 8:59 PM
    Tuesday, December 20, 2011 6:20 PM

All replies

  • Following link is a great article for shape connector

    http://denisvuyka.wordpress.com/2007/10/13/wpf-draggable-objects-and-simple-shape-connectors/

    The code is in C# so I have converted MyThumb class to VB.NET.

    Public Class MyThumb
        Inherits Thumb
    #Region "Properties"
        Public Shared ReadOnly TitleProperty As DependencyProperty = DependencyProperty.Register("Title"GetType(String), GetType(MyThumb), New UIPropertyMetadata(""))
        Public Shared ReadOnly ImageSourceProperty As DependencyProperty = DependencyProperty.Register("ImageSource"GetType(String), GetType(MyThumb), New UIPropertyMetadata(""))
     
        ' This property will hanlde the content of the textblock element taken from control template
        Public Property Title() As String
            Get
                Return DirectCast(GetValue(TitleProperty), String)
            End Get
            Set(value As String)
                SetValue(TitleProperty, value)
            End Set
        End Property
     
        ' This property will handle the content of the image element taken from control template
        Public Property ImageSource() As String
            Get
                Return DirectCast(GetValue(ImageSourceProperty), String)
            End Get
            Set(value As String)
                SetValue(ImageSourceProperty, value)
            End Set
        End Property
     
        Public Property EndLines() As List(Of LineGeometry)
            Get
                Return m_EndLines
            End Get
            Private Set(value As List(Of LineGeometry))
                m_EndLines = value
            End Set
        End Property
        Private m_EndLines As List(Of LineGeometry)
        Public Property StartLines() As List(Of LineGeometry)
            Get
                Return m_StartLines
            End Get
            Private Set(value As List(Of LineGeometry))
                m_StartLines = value
            End Set
        End Property
        Private m_StartLines As List(Of LineGeometry)
    #End Region
     
    #Region "Constructors"
        Public Sub New()
            MyBase.New()
            StartLines = New List(Of LineGeometry)()
            EndLines = New List(Of LineGeometry)()
        End Sub
     
        Public Sub New(template As ControlTemplate, title As String, imageSource As String, position As Point)
            Me.New()
            Me.Template = template
            Me.Title = If((title IsNot Nothing), title, String.Empty)
            Me.ImageSource = If((imageSource IsNot Nothing), imageSource, String.Empty)
            Me.SetPosition(position)
        End Sub
     
        Public Sub New(template As ControlTemplate, title As String, imageSource As String, position As Point, dragDelta As DragDeltaEventHandler)
            Me.New(template, title, imageSource, position)
            AddHandler Me.DragDelta, dragDelta
        End Sub
    #End Region
     
        ' Helper method for setting the position of our thumb
        Public Sub SetPosition(value As Point)
            Canvas.SetLeft(Me, value.X)
            Canvas.SetTop(Me, value.Y)
        End Sub
     
    #Region "Linking logic"
        ' This method establishes a link between current thumb and specified thumb.
        ' Returns a line geometry with updated positions to be processed outside.
        Public Function LinkTo(target As MyThumbAs LineGeometry
            ' Create new line geometry
            Dim line As New LineGeometry()
            ' Save as starting line for current thumb
            Me.StartLines.Add(line)
            ' Save as ending line for target thumb
            target.EndLines.Add(line)
            ' Ensure both tumbs the latest layout
            Me.UpdateLayout()
            target.UpdateLayout()
            ' Update line position
            line.StartPoint = New Point(Canvas.GetLeft(Me) + Me.ActualWidth / 2, Canvas.GetTop(Me) + Me.ActualHeight / 2)
            line.EndPoint = New Point(Canvas.GetLeft(target) + target.ActualWidth / 2, Canvas.GetTop(target) + target.ActualHeight / 2)
            ' return line for further processing
            Return line
        End Function
     
        ' This method establishes a link between current thumb and target thumb using a predefined line geometry
        ' Note: this is commonly to be used for drawing links with mouse when the line object is predefined outside this class
        Public Function LinkTo(target As MyThumb, line As LineGeometryAs Boolean
            ' Save as starting line for current thumb
            Me.StartLines.Add(line)
            ' Save as ending line for target thumb
            target.EndLines.Add(line)
            ' Ensure both tumbs the latest layout
            Me.UpdateLayout()
            target.UpdateLayout()
            ' Update line position
            line.StartPoint = New Point(Canvas.GetLeft(Me) + Me.ActualWidth / 2, Canvas.GetTop(Me) + Me.ActualHeight / 2)
            line.EndPoint = New Point(Canvas.GetLeft(target) + target.ActualWidth / 2, Canvas.GetTop(target) + target.ActualHeight / 2)
            Return True
        End Function
    #End Region
     
        ' This method updates all the starting and ending lines assigned for the given thumb 
        ' according to the latest known thumb position on the canvas
        Public Sub UpdateLinks()
            Dim left As Double = Canvas.GetLeft(Me)
            Dim top As Double = Canvas.GetTop(Me)
     
            For i As Integer = 0 To Me.StartLines.Count - 1
                Me.StartLines(i).StartPoint = New Point(left + Me.ActualWidth / 2, top + Me.ActualHeight / 2)
            Next
     
            For i As Integer = 0 To Me.EndLines.Count - 1
                Me.EndLines(i).EndPoint = New Point(left + Me.ActualWidth / 2, top + Me.ActualHeight / 2)
            Next
        End Sub
     
        ' Upon applying template we apply the "Title" and "ImageSource" properties to the template elements.
        Public Overrides Sub OnApplyTemplate()
            MyBase.OnApplyTemplate()
     
            ' Access the textblock element of template and assign it if Title property defined
            If Me.Title <> String.Empty Then
                Dim txt As TextBlock = TryCast(Me.Template.FindName("tplTextBlock"Me), TextBlock)
                If txt IsNot Nothing Then
                    txt.Text = Title
                End If
            End If
     
            ' Access the image element of our custom template and assign it if ImageSource property defined
            If Me.ImageSource <> String.Empty Then
                Dim img As Image = TryCast(Me.Template.FindName("tplImage"Me), Image)
                If img IsNot Nothing Then
                    img.Source = New BitmapImage(New Uri(Me.ImageSource, UriKind.Relative))
                End If
            End If
        End Sub
    End Class


    Gaurav Khanna | Microsoft VB.NET MVP
    • Marked as answer by sous2817_1 Tuesday, December 20, 2011 8:59 PM
    Tuesday, December 20, 2011 6:20 PM
  • Thank you for the translation and the link Gaurav, it's definitely moving me in the right direction!  Is there a way to have the thumb bound to a user control rather than a control template? 
    Tuesday, December 20, 2011 6:59 PM
  • think I've got it sorted.  Either way, couldn't have done it without your help Gaurav!

    • Edited by sous2817_1 Tuesday, December 20, 2011 8:59 PM
    Tuesday, December 20, 2011 8:47 PM