none
How to draw a line a streight line at run time, with seeing the track of the line? RRS feed

  • Question

  • Is there any way to draw a straight line with mouse actions, and see the line while moving the mouse?

    Here's my scenario:

    I click on a point and this will be my starting point(X,Y1), then I move the mouse, then I click on the second point, which will be my ending point (X,Y).

    Here's the way I do it, in the MouseLeftButtonDown event:

    Line line = new Line();
    line.Stroke = Brushes.GreenYellow;
    line.StrokeThickness = 3;
    line.X1 = _startingMeasurementPoint.X;
    line.Y1 = _startingMeasurementPoint.Y;
    line.X2 = e.MouseDevice.GetPosition(ImageCanvas).X;
    line.Y2 = e.MouseDevice.GetPosition(ImageCanvas).Y;
    MeasurementLinesCanvas.Children.Add(line);

    _startingMeasurementPoint, is the starting point from the first click.

    The problem is that, I won't see the line while drawing, and I just see it at the end.
    Is there a way to see the line while moving the mouse? 

    I tried this on the MouseMove event:

    line.X1 = LastReconnectingPoint.X;
    line.Y1 = LastReconnectingPoint.Y;
    line.X2 = e.GetPosition(ImageCanvas).X;
    line.Y2 = e.GetPosition(ImageCanvas).Y;
    LastReconnectingPoint = e.GetPosition(ImageCanvas);
    MeasurementLinesCanvas.Children.Add(line);
    But it doesn't draw a straight line, it acts like the "Pencil" tool in Paint. I want to do it like "Line" tool in Paint.


    Wednesday, February 20, 2019 5:16 PM

Answers

  • I do something sounds pretty similar to what you want in my map editor.

    Only it's part of a huge complicated application.

    Mostly I use ink for drawing lines to define (say) a road or the outline of woods.

    I have a process allows the user to do a series of straight "SnapLines".

    Code:

            private void SnapLineCanvas_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
            {
                Point pt = e.GetPosition(SnapLineCanvas);
                App.mvm.SnapLinePoints.Add(pt);
                snapLinePoints.Add(pt);
                SnapLine.Points = new PointCollection(snapLinePoints);
                SnapLine.InvalidateVisual();
                LineIndicator.X1 = pt.X;
                LineIndicator.Y1 = pt.Y;
            }
    
            private void SnapLineCanvas_PreviewMouseMove(object sender, MouseEventArgs e)
            {
                if (snapLinePoints.Count > 0 && doTraceLine)
                {
                    Point pt = e.GetPosition(SnapLineCanvas);
                    LineIndicator.X2 = pt.X;
                    LineIndicator.Y2 = pt.Y;
                }
            }
    
            private void SnapLineCanvas_PreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
            {
                doTraceLine = !doTraceLine;
                LineIndicator.Visibility = doTraceLine ? Visibility.Visible : Visibility.Collapsed;
            }
            public void SnapLineClear()
            {
                snapLinePoints = new List<Point>();
                doTraceLine = true;
                LineIndicator.X1 = 0;
                LineIndicator.X2 = 0;
                LineIndicator.Y1 = 0;
                LineIndicator.Y2 = 0;
                LineIndicator.Visibility = Visibility.Visible;
                App.mvm.SnapLinePoints.Clear();
                SnapLine.Points = new PointCollection();
                SnapLine.InvalidateVisual();
            }

    When you click that sets one end of a line object. The X1 and Y1.

    As you then move the mouse around, it sets the other end of that line - X2 and Y2.

    The result being the line (x2,y2) end follows the cursor round.

    Right clicking toggles line visibility so you can easily avoid a line following your cursor forever.

    The collection of points is used to define a geometry used in a different layer once you have defined the complete terrain outline. That aspect is quite complicated because there's a separate viewmodel per type of terrain. A roadVM, WoodsVM etc. So let's gloss over that bit.

    The Canvas you're "drawing" on:

    <Canvas Name="SnapLineCanvas" 
                                    Background="Transparent"
                                    PreviewMouseLeftButtonDown="SnapLineCanvas_PreviewMouseLeftButtonDown"
                                    PreviewMouseMove="SnapLineCanvas_PreviewMouseMove"
                                    PreviewMouseRightButtonDown="SnapLineCanvas_PreviewMouseRightButtonDown"
                                    >
                                <Polyline 
                                          Name="SnapLine"
                                          Stroke="Red" 
                                          StrokeThickness="2"
                                          FillRule="Nonzero"
                                          IsHitTestVisible="False"
                                    />
                                <Line Name="LineIndicator"
                                      StrokeDashArray="2 2" 
                                      StrokeThickness="2" 
                                      Stroke="Black"
                                      />

    The PolyLine is used to show previous uncommitted lines.

    LineIndicator shows the current line you will draw when you click.

    It follows the cursor position as you move the mouse round.

    And this is what it looks like running.

    The red lines are 3 lines already drawn and the dashed line is following the cursor - but this screen dump hasn't captured the cursor.

    More of the screen with a number of terrains drawn using this process.

    Reset clears un committed points.

    Width only applies to "line" types like a road or wall.

    Translate takes the uncommitted points and turns them into the terrain type which is selected in the combo.


    Hope that helps.

    Technet articles: WPF: Layout Lab; All my Technet Articles

    Wednesday, February 20, 2019 7:07 PM
    Moderator

All replies

  • I do something sounds pretty similar to what you want in my map editor.

    Only it's part of a huge complicated application.

    Mostly I use ink for drawing lines to define (say) a road or the outline of woods.

    I have a process allows the user to do a series of straight "SnapLines".

    Code:

            private void SnapLineCanvas_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
            {
                Point pt = e.GetPosition(SnapLineCanvas);
                App.mvm.SnapLinePoints.Add(pt);
                snapLinePoints.Add(pt);
                SnapLine.Points = new PointCollection(snapLinePoints);
                SnapLine.InvalidateVisual();
                LineIndicator.X1 = pt.X;
                LineIndicator.Y1 = pt.Y;
            }
    
            private void SnapLineCanvas_PreviewMouseMove(object sender, MouseEventArgs e)
            {
                if (snapLinePoints.Count > 0 && doTraceLine)
                {
                    Point pt = e.GetPosition(SnapLineCanvas);
                    LineIndicator.X2 = pt.X;
                    LineIndicator.Y2 = pt.Y;
                }
            }
    
            private void SnapLineCanvas_PreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
            {
                doTraceLine = !doTraceLine;
                LineIndicator.Visibility = doTraceLine ? Visibility.Visible : Visibility.Collapsed;
            }
            public void SnapLineClear()
            {
                snapLinePoints = new List<Point>();
                doTraceLine = true;
                LineIndicator.X1 = 0;
                LineIndicator.X2 = 0;
                LineIndicator.Y1 = 0;
                LineIndicator.Y2 = 0;
                LineIndicator.Visibility = Visibility.Visible;
                App.mvm.SnapLinePoints.Clear();
                SnapLine.Points = new PointCollection();
                SnapLine.InvalidateVisual();
            }

    When you click that sets one end of a line object. The X1 and Y1.

    As you then move the mouse around, it sets the other end of that line - X2 and Y2.

    The result being the line (x2,y2) end follows the cursor round.

    Right clicking toggles line visibility so you can easily avoid a line following your cursor forever.

    The collection of points is used to define a geometry used in a different layer once you have defined the complete terrain outline. That aspect is quite complicated because there's a separate viewmodel per type of terrain. A roadVM, WoodsVM etc. So let's gloss over that bit.

    The Canvas you're "drawing" on:

    <Canvas Name="SnapLineCanvas" 
                                    Background="Transparent"
                                    PreviewMouseLeftButtonDown="SnapLineCanvas_PreviewMouseLeftButtonDown"
                                    PreviewMouseMove="SnapLineCanvas_PreviewMouseMove"
                                    PreviewMouseRightButtonDown="SnapLineCanvas_PreviewMouseRightButtonDown"
                                    >
                                <Polyline 
                                          Name="SnapLine"
                                          Stroke="Red" 
                                          StrokeThickness="2"
                                          FillRule="Nonzero"
                                          IsHitTestVisible="False"
                                    />
                                <Line Name="LineIndicator"
                                      StrokeDashArray="2 2" 
                                      StrokeThickness="2" 
                                      Stroke="Black"
                                      />

    The PolyLine is used to show previous uncommitted lines.

    LineIndicator shows the current line you will draw when you click.

    It follows the cursor position as you move the mouse round.

    And this is what it looks like running.

    The red lines are 3 lines already drawn and the dashed line is following the cursor - but this screen dump hasn't captured the cursor.

    More of the screen with a number of terrains drawn using this process.

    Reset clears un committed points.

    Width only applies to "line" types like a road or wall.

    Translate takes the uncommitted points and turns them into the terrain type which is selected in the combo.


    Hope that helps.

    Technet articles: WPF: Layout Lab; All my Technet Articles

    Wednesday, February 20, 2019 7:07 PM
    Moderator
  • Hi Andy!

    It's a very nice way of doing it, I mean having the indicator.

    I applied your solution, and it's working perfectly fine.

    Thanks!


    Thursday, February 21, 2019 6:15 PM