简体   繁体   中英

C# WPF MouseUp event not being fired

So, I am creating a paint like program in WPF. On a canvas I have the following functionalities:

  • Draw a line
  • Move a line
  • Rotate a line

To accomplish this, I have 3 events: MouseDown , MouseMove , MouseUp

When I start drawing on the canvas, the MouseDown & MouseMove event are triggered perfectly. But, the MouseUp is not triggered... This problem occurs when I'm drawing while moving. It works fine when the draw function is called after all events been triggered.

The commented section in the Redraw function is messing up the MouseUp event. When commented the event is working perfectly fine

The code:

namespace Roomplanner.Controls
{
    /// <summary>
    /// Interaction logic for DrawingControl.xaml
    /// </summary>
    public partial class DrawingControl : UserControl
    {
        //Size settings
        private double _zoomLevel = 1.1;
        private int _mapWidth = 765;
        private int _mapHeight = 430;
        private static MouseState _mouseState = MouseState.Idle;

        //Wall variables
        private List<Point> Pt1 = new List<Point>();
        private List<Point> Pt2 = new List<Point>();
        private Point _NewPt1, _NewPt2;
        private bool _isDrawing = false;


        private const int object_radius = 3;

        // We're over an object if the distance squared
        // between the mouse and the object is less than this.
        private const int over_dist_squared = object_radius * object_radius;

        public DrawingControl()
        {
            //Automated
            InitializeComponent();

            //
            drawingCanvas.Width     = _mapWidth;
            drawingCanvas.Height    = _mapHeight;

            drawingCanvas.MouseWheel += DrawingCanvas_MouseWheel;


        }


        //==================================================================================
        //MOUSE FUNCTIONS
        //==================================================================================
        private void DrawingCanvas_MouseDown(object sender, MouseButtonEventArgs e)
        {
            // See what we're over.
            Point hit_point;
            int segment_number;

            if (MouseIsOverEndpoint(Mouse.GetPosition(drawingCanvas), out segment_number, out hit_point))
            {
                // Start moving this end point.
                drawingCanvas.MouseMove -= DrawingCanvas_MouseMove_NotDown;
                drawingCanvas.MouseMove += DrawingCanvas_MouseMove_MovingEndPoint;
                drawingCanvas.MouseUp += DrawingCanvas_MouseUp_MovingEndPoint;

                // Remember the segment number.
                MovingSegment = segment_number;

                // See if we're moving the start end point.
                MovingStartEndPoint = (Pt1[segment_number].Equals(hit_point));

                // Remember the offset from the mouse to the point.
                OffsetX = hit_point.X - e.GetPosition(drawingCanvas).X;
                OffsetY = hit_point.Y - e.GetPosition(drawingCanvas).Y;
            }
            else if (MouseIsOverSegment(Mouse.GetPosition(drawingCanvas), out segment_number))
            {
                // Start moving this segment.
                drawingCanvas.MouseMove -= DrawingCanvas_MouseMove_NotDown;
                drawingCanvas.MouseMove += DrawingCanvas_MouseMove_MovingSegment;
                drawingCanvas.MouseUp += DrawingCanvas_MouseUp_MovingSegment;

                // Remember the segment number.
                MovingSegment = segment_number;

                // Remember the offset from the mouse to the segment's first point.
                OffsetX = Pt1[segment_number].X - e.GetPosition(drawingCanvas).X;
                OffsetY = Pt1[segment_number].Y - e.GetPosition(drawingCanvas).Y;
            }
            else
            {
                // Start drawing a new segment.
                drawingCanvas.MouseMove -= DrawingCanvas_MouseMove_NotDown;
                drawingCanvas.MouseMove += DrawingCanvas_MouseMove_Drawing;
                drawingCanvas.MouseUp += DrawingCanvas_MouseUp_Drawing;

                _isDrawing = true;
                _NewPt1 = new Point(e.GetPosition(drawingCanvas).X, e.GetPosition(drawingCanvas).Y);
                _NewPt2 = new Point(e.GetPosition(drawingCanvas).X, e.GetPosition(drawingCanvas).Y);
            }
        }
        // We're drawing a new segment.
        private void DrawingCanvas_MouseMove_Drawing(object sender, MouseEventArgs e)
        {
            // Save the new point.
            _NewPt2 = new Point(e.GetPosition(drawingCanvas).X, e.GetPosition(drawingCanvas).Y);

            // Redraw.
            Redraw();

        }

        // Stop drawing.
        private void DrawingCanvas_MouseUp_Drawing(object sender, MouseEventArgs e)
        {
            _isDrawing = false;
            Console.WriteLine("UP");
            // Reset the event handlers.
            drawingCanvas.MouseMove -= DrawingCanvas_MouseMove_Drawing;
            drawingCanvas.MouseMove += DrawingCanvas_MouseMove_NotDown;
            drawingCanvas.MouseUp -= DrawingCanvas_MouseUp_Drawing;

            // Create the new segment.
            Pt1.Add(_NewPt1);
            Pt2.Add(_NewPt2);

            // Redraw.
            Redraw();
        }


        private void DrawingCanvas_MouseMove_NotDown(object sender, MouseEventArgs e)
        {

            //See what we're hovering
            Point hit_point;
            int segment_number;
            Point curpos = Mouse.GetPosition(drawingCanvas);

            if (MouseIsOverEndpoint(curpos, out segment_number, out hit_point))
                Cursor = Cursors.Arrow;
            else if (MouseIsOverSegment(curpos, out segment_number))
                Cursor = Cursors.Hand;
        }

        private void DrawingCanvas_MouseWheel(object sender, MouseWheelEventArgs e)
        {
            if(e.Delta > 0)
            {
                sourceGridST.ScaleX *= _zoomLevel;
                sourceGridST.ScaleY *= _zoomLevel;
            }
            else
            {
                sourceGridST.ScaleX /= _zoomLevel;
                sourceGridST.ScaleY /= _zoomLevel;
            }
        }

        // The segment we're moving or the segment whose end point we're moving.
        private int MovingSegment = -1;

        // The end point we're moving.
        private bool MovingStartEndPoint = false;

        // The offset from the mouse to the object being moved.
        private double OffsetX, OffsetY;

        // See if the mouse is over an end point.
        private bool MouseIsOverEndpoint(Point mouse_pt, out int segment_number, out Point hit_pt)
        {
            for (int i = 0; i < Pt1.Count; i++)
            {
                // Check the starting point.
                if (FindDistanceToPointSquared(mouse_pt, Pt1[i]) < over_dist_squared)
                {
                    // We're over this point.
                    segment_number = i;
                    hit_pt = Pt1[i];
                    return true;
                }

                // Check the end point.
                if (FindDistanceToPointSquared(mouse_pt, Pt2[i]) < over_dist_squared)
                {
                    // We're over this point.
                    segment_number = i;
                    hit_pt = Pt2[i];
                    return true;
                }
            }

            segment_number = -1;
            hit_pt = new Point(-1, -1);
            return false;
        }

        // See if the mouse is over a line segment.
        private bool MouseIsOverSegment(Point mouse_pt, out int segment_number)
        {
            for (int i = 0; i < Pt1.Count; i++)
            {
                // See if we're over the segment.
                Point closest;
                if (FindDistanceToSegmentSquared(
                    mouse_pt, Pt1[i], Pt2[i], out closest)
                        < over_dist_squared)
                {
                    // We're over this segment.
                    segment_number = i;
                    return true;
                }
            }

            segment_number = -1;
            return false;
        }

        #region "Moving End Point"

        // We're moving an end point.
        private void DrawingCanvas_MouseMove_MovingEndPoint(object sender, MouseEventArgs e)
        {
            // Move the point to its new location.
            if (MovingStartEndPoint)
                Pt1[MovingSegment] =
                    new Point(e.GetPosition(drawingCanvas).X + OffsetX, e.GetPosition(drawingCanvas).Y + OffsetY);
            else
                Pt2[MovingSegment] =
                    new Point(e.GetPosition(drawingCanvas).X + OffsetX, e.GetPosition(drawingCanvas).Y + OffsetY);

            // Redraw.
            Redraw();

        }

        // Stop moving the end point.
        private void DrawingCanvas_MouseUp_MovingEndPoint(object sender, MouseEventArgs e)
        {
            // Reset the event handlers.
            drawingCanvas.MouseMove += DrawingCanvas_MouseMove_NotDown;
            drawingCanvas.MouseMove -= DrawingCanvas_MouseMove_MovingEndPoint;
            drawingCanvas.MouseUp -= DrawingCanvas_MouseUp_MovingEndPoint;

            // Redraw.
            Redraw();
        }

        #endregion // Moving End Point

        #region "Moving Segment"

        // We're moving a segment.
        private void DrawingCanvas_MouseMove_MovingSegment(object sender, MouseEventArgs e)
        {
            // See how far the first point will move.
            double new_x1 = e.GetPosition(drawingCanvas).X + OffsetX;
            double new_y1 = e.GetPosition(drawingCanvas).Y + OffsetY;

            double dx = new_x1 - Pt1[MovingSegment].X;
            double dy = new_y1 - Pt1[MovingSegment].Y;

            if (dx == 0 && dy == 0) return;

            // Move the segment to its new location.
            Pt1[MovingSegment] = new Point(new_x1, new_y1);
            Pt2[MovingSegment] = new Point(
                Pt2[MovingSegment].X + dx,
                Pt2[MovingSegment].Y + dy);

            // Redraw.
            Redraw();

        }

        // Stop moving the segment.
        private void DrawingCanvas_MouseUp_MovingSegment(object sender, MouseEventArgs e)
        {
            // Reset the event handlers.
            drawingCanvas.MouseMove += DrawingCanvas_MouseMove_NotDown;
            drawingCanvas.MouseMove -= DrawingCanvas_MouseMove_MovingSegment;
            drawingCanvas.MouseUp -= DrawingCanvas_MouseUp_MovingSegment;

            // Redraw.
            Redraw();
        }

        #endregion // Moving End Point

        //==================================================================================
        //END MOUSE FUNCTIONS
        //==================================================================================

        // Calculate the distance squared between two points.
        private int FindDistanceToPointSquared(Point pt1, Point pt2)
        {
            int dx = (int)pt1.X - (int)pt2.X;
            int dy = (int)pt1.Y - (int)pt2.Y;
            return dx * dx + dy * dy;
        }

        // Calculate the distance squared between
        // point pt and the segment p1 --> p2.
        private double FindDistanceToSegmentSquared(Point pt, Point p1, Point p2, out Point closest)
        {
            float dx = (float)p2.X - (float)p1.X;
            float dy = (float)p2.Y - (float)p1.Y;
            if ((dx == 0) && (dy == 0))
            {
                // It's a point not a line segment.
                closest = p1;
                dx = (float)pt.X - (float)p1.X;
                dy = (float)pt.Y - (float)p1.Y;
                return dx * dx + dy * dy;
            }

            // Calculate the t that minimizes the distance.
            float t = (float)((pt.X - p1.X) * dx + (pt.Y - p1.Y) * dy) / (dx * dx + dy * dy);

            // See if this represents one of the segment's
            // end points or a point in the middle.
            if (t < 0)
            {
                closest = new Point(p1.X, p1.Y);
                dx = (float)pt.X - (float)p1.X;
                dy = (float)pt.Y - (float)p1.Y;
            }
            else if (t > 1)
            {
                closest = new Point(p2.X, p2.Y);
                dx = (float)pt.X - (float)p2.X;
                dy = (float)pt.Y - (float)p2.Y;
            }
            else
            {
                closest = new Point(p1.X + t * dx, p1.Y + t * dy);
                dx = (float)pt.X - (float)closest.X;
                dy = (float)pt.Y - (float)closest.Y;
            }

            return dx * dx + dy * dy;
        }


        private void DrawWalls(Line wall)
        {
            wall.Stroke = Brushes.Black;
            drawingCanvas.Children.Add(wall);

        }
        private void ChangeSize(int x, int y)
        {
            drawingCanvas.Height = y;
            drawingCanvas.Width = x;
        }

        private void Redraw()
        {
            drawingCanvas.Children.Clear();
            // Draw the segments.
            for (int i = 0; i < Pt1.Count; i++)
            {
                // Draw the segment
                Line wall = new Line();
                wall.X1 = Pt1[i].X;
                wall.X2 = Pt2[i].X;
                wall.Y1 = Pt1[i].Y;
                wall.Y2 = Pt2[i].Y;
                wall.Stroke = Brushes.Black;
                drawingCanvas.Children.Add(wall);

            }

            // Draw the end points.
            foreach (Point pt in Pt1)
            {
                Rectangle rect = new Rectangle();
                rect.Stroke = Brushes.LightGray;
                rect.Width  = 6;
                rect.Height = 6;
                Canvas.SetTop(rect, pt.Y - object_radius);
                Canvas.SetLeft(rect, pt.X - object_radius);
                drawingCanvas.Children.Add(rect);

            }
            foreach (Point pt in Pt2)
            {
                Rectangle rect = new Rectangle();
                rect.Stroke = Brushes.LightGray;
                rect.Width = 6;
                rect.Height = 6;
                Canvas.SetTop(rect, pt.Y - object_radius);
                Canvas.SetLeft(rect, pt.X - object_radius);
                drawingCanvas.Children.Add(rect);
            }

            // If there's a new segment under constructions, draw it.
            if (_isDrawing)
            {
                //When Uncommented the MouseUP event is never called
                //Line wall = new Line();
                //wall.X1 = _NewPt1.X;
                //wall.X2 = _NewPt2.Y;
                //wall.Y1 = _NewPt1.Y;
                //wall.Y2 = _NewPt2.Y;
                //wall.Stroke = Brushes.Black;
                //drawingCanvas.Children.Add(wall);       
            }
        }

        private void btnSizeChanged_Click(object sender, RoutedEventArgs e)
        {
            ChangeSize(int.Parse(tbxHeight.Text), int.Parse( tbxWidth.Text));
        }

        private void MouseMove_(object sender, MouseEventArgs e)
        {

        }

        private void btnDraw_Click(object sender, RoutedEventArgs e)
        {
            _mouseState = ( _mouseState == MouseState.DrawStart )? MouseState.DrawEnd : MouseState.DrawStart;
        }

        public enum MouseState
        {
            DrawStart, DrawEnd, Idle
        }

    }
}

maybe you remove the path which triggers the event.

I solved it by save 10 last pathes by using a Queue

Path LastPath = null;
Queue<Path> GarbagePath = new Queue<Path>(); // save last pathes
private void MainCanvas_MouseMove(object sender, MouseEventArgs e) {
    if (this.IsMouseDown == true && this.ShapeCurr == DrawShape.LINE) {
        this.EndPoint = Mouse.GetPosition(this.mainCanvas);
        if (this.LastPath != null) {
            this.GarbagePath.Enqueue(this.LastPath);
            if (this.GarbagePath.Count == 10) {
                this.mainCanvas.Children.Remove(this.GarbagePath.Dequeue());
            }
            this.LastPath.Visibility = Visibility.Hidden;
        }
        this.LastPath = this.DrawLine(this.BeginPoint, this.EndPoint); // draw
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM