Click here to Skip to main content
15,898,134 members
Articles / Programming Languages / Visual Basic

WPF-Drawing Canvas Control

Rate me:
Please Sign up or sign in to vote.
4.93/5 (13 votes)
5 Oct 2012CPOL13 min read 124.8K   8.1K   47  
A drawing tool program that can create simplified XAML code
Imports System.Globalization

Public Class CustomLine
    Inherits FrameworkElement
    Implements System.ComponentModel.INotifyPropertyChanged

    ' Create a collection of child visual objects.
    Private _children As VisualCollection

    Public Selection As SelectionType = SelectionType.NotSelected
    Public Enum SelectionType As Integer
        LineSelected
        PointSelection
        NotSelected
    End Enum

#Region "Constructor"
    Public Sub New(p_position As PointCollection)

        Points = p_position

        _children = New VisualCollection(Me)

        For i As Integer = 0 To Points.Count - 1
            If i < Points.Count - 1 Then
                _children.Add(CreateDrawingVisualLine(Points(i), Points(i + 1)))
                _children.Add(CreateInvisibleDrawingVisualLine(Points(i), Points(i + 1)))
            End If
            Dim temp As New CanvasPoint(Points(i))
            temp.Opacity = 0
            _children.Add(temp)
        Next

        ' Add the event handler for MouseLeftButtonDown.
        AddHandler PreviewMouseLeftButtonDown, AddressOf CustomLineMouseDown
    End Sub
#End Region

#Region "Properties"

    Private _HitFromPoint As Boolean = False
    Public Property HitFromPoint() As Boolean
        Get
            Return _HitFromPoint
        End Get
        Set(ByVal value As Boolean)
            _HitFromPoint = value
        End Set
    End Property

    Private _Multiselect As Boolean = False
    Public Property Multiselect() As Boolean
        Get
            Return _Multiselect
        End Get
        Set(ByVal value As Boolean)
            _Multiselect = value
        End Set
    End Property

    Private p_LinePoints As New PointCollection
    Public Property Points() As PointCollection
        Get
            Return p_LinePoints
        End Get
        Set(ByVal value As PointCollection)
            p_LinePoints = value
            INotifyChange("PositionOnCanvas")
        End Set
    End Property

    Private _SelectedPointID As Integer
    Public Property SelectedPointID() As Integer
        Get
            Return _SelectedPointID
        End Get
        Set(ByVal value As Integer)
            _SelectedPointID = value
        End Set
    End Property

    Public Sub INotifyChange(ByVal info As String)
        RaiseEvent PropertyChanged(Me, New System.ComponentModel.PropertyChangedEventArgs(info))
    End Sub

    Public Event PropertyChanged(sender As Object, e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged


#End Region

#Region "Overided properties"

    ' Provide a required override for the VisualChildrenCount property.
    Protected Overrides ReadOnly Property VisualChildrenCount() As Integer
        Get
            Return _children.Count
        End Get
    End Property

    ' Provide a required override for the GetVisualChild method.
    Protected Overrides Function GetVisualChild(ByVal index As Integer) As Visual
        If index < 0 OrElse index >= _children.Count Then
            Throw New ArgumentOutOfRangeException()
        End If

        Return _children(index)
    End Function
#End Region

#Region "Drawing"
    Private Function CreateDrawingVisualLine(ByVal p1 As Point, ByVal p2 As Point) As DrawingVisual
        Dim drawingVisual As New DrawingVisual()

        ' Retrieve the DrawingContext in order to create new drawing content.
        Dim drawingContext As DrawingContext = drawingVisual.RenderOpen()
        Dim pen As Pen '(Brush, 70)

        If Selection = SelectionType.LineSelected Then
            pen = New Pen(Brushes.Black, 1)
        Else
            pen = New Pen(Brushes.Gray, 1)
        End If
        pen.EndLineCap = PenLineCap.Round
        pen.DashCap = PenLineCap.Round
        pen.LineJoin = PenLineJoin.Round
        pen.StartLineCap = PenLineCap.Round
        pen.MiterLimit = 10.0
        drawingContext.DrawLine(pen, p1, p2)
        ' Persist the drawing content.
        drawingContext.Close()

        Return drawingVisual
    End Function

    Private Function CreateInvisibleDrawingVisualLine(ByVal p1 As Point, ByVal p2 As Point) As DrawingVisual
        Dim drawingVisual As New DrawingVisual()

        ' Retrieve the DrawingContext in order to create new drawing content.
        Dim drawingContext As DrawingContext = drawingVisual.RenderOpen()

        drawingContext.DrawLine(New Pen(Brushes.Transparent, 3), p1, p2)

        ' Persist the drawing content.
        drawingContext.Close()

        Return drawingVisual
    End Function

    Public Sub ReDraw()
        _children.Clear()
        _children = New VisualCollection(Me)

        For i As Integer = 0 To Points.Count - 1
            If i < Points.Count - 1 Then
                _children.Add(CreateDrawingVisualLine(Points(i), Points(i + 1)))
                _children.Add(CreateInvisibleDrawingVisualLine(Points(i), Points(i + 1)))
            End If
            If Selection = SelectionType.PointSelection Then
                _children.Add(New CanvasPoint(Points(i)))
            End If

        Next
    End Sub
#End Region

    Public Sub CustomLineMouseDown(ByVal sender As Object, ByVal e As MouseEventArgs)
        If Not TypeOf (e.OriginalSource) Is CanvasPoint Then
            HitFromPoint = False
            If Selection = SelectionType.NotSelected Then
                Selection = SelectionType.LineSelected
                For i As Integer = 0 To _children.Count - 1
                    If TypeOf (_children(i)) Is DrawingVisual Then
                        DirectCast(_children(i), DrawingVisual).Opacity = 0.5
                    ElseIf TypeOf (_children(i)) Is CanvasPoint Then
                        DirectCast(_children(i), CanvasPoint).Opacity = 0.5
                    End If
                Next
                ReDraw()
            ElseIf Selection = SelectionType.LineSelected Then
                Selection = SelectionType.PointSelection
                ReDraw()
            Else
                Selection = SelectionType.NotSelected
                ReDraw()
            End If
        ElseIf TypeOf (e.OriginalSource) Is CanvasPoint Then
            HitFromPoint = True
            Dim CurrentSelectedPoint As CanvasPoint
            CurrentSelectedPoint = DirectCast(e.OriginalSource, CanvasPoint)
            CurrentSelectedPoint.Opacity = 0.5
            For i As Integer = 0 To Me._children.Count - 1
                If TypeOf (Me._children(i)) Is CanvasPoint Then
                    If Not Multiselect Then
                        Dim po As CanvasPoint = DirectCast(Me._children(i), CanvasPoint)
                        If po Is CurrentSelectedPoint Then
                            po.Opacity = 1
                        Else
                            po.Opacity = 0.5
                        End If
                    End If
                End If
            Next
            For i As Integer = 0 To Points.Count - 1
                If CurrentSelectedPoint.PositionOnCanvas = (Points(i)) Then
                    SelectedPointID = i
                End If
            Next
        End If
    End Sub

End Class

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Chief Technology Officer
Norway Norway
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions