MouseMove event is called even when cursor is outside of canvas. `Border`around canvas did not work

1.1k views Asked by At

short discription of the to-be situation:

As soon as the mouse moves over my canvas I want an ellipse to be displayed on the canvas. The ellipse is supposed to stick to the mouse movement until the user hits the left mouse button. At the time the user hits the left mouse button, the program is expected to place the ellipse on the canvas.

Therefore I used the following xaml code:

    <Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="700" Width="1200">



<Grid>
    <Border ClipToBounds="true">
    <Canvas x:Name="canvasss" Background="AntiqueWhite" Width="524" Height="368" MouseMove="Canvasss_MouseMove" MouseDown="Canvasss_MouseDown">

    </Canvas>
    </Border>
</Grid>

And the c# code:

    using System.Collections.Generic;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Shapes;

    namespace WpfApplication1
    {
         public class Item
         {
            private readonly Ellipse shape;

            public Item(Canvas canvas)
            {
                shape = new Ellipse { Width = 50, Height = 50, Fill = Brushes.Black };
                canvas.Children.Add(shape);
                SetPosition(0.0, 0.0);
            }

            public void SetPosition(double x, double y)
            {
                Canvas.SetLeft(shape, x);
                Canvas.SetTop(shape, y);
            }
        }

        public partial class MainWindow : Window
        {
            private readonly IList<Item> shapes;
            private Item currentMovingShape;

            public MainWindow()
            {
                InitializeComponent();
                shapes = new List<Item>();
                InitMovingShape();
            }

            private void InitMovingShape()
            {
                currentMovingShape = new Item(canvasss);
            }

            private void SetMovingShapePosition(MouseEventArgs e)
            {
                var pos = e.GetPosition(canvasss);
                currentMovingShape.SetPosition(pos.X - 25, pos.Y - 25);
            }

            private void Canvasss_MouseMove(object sender, MouseEventArgs e)
            {
                var pos = e.GetPosition(canvasss);
                currentMovingShape.SetPosition(pos.X - 25, pos.Y - 25);
            }

            private void Canvasss_MouseDown(object sender, MouseButtonEventArgs e)
            {
                shapes.Add(currentMovingShape);
                InitMovingShape();            
            }


         }
    }

The problem is, that as soon as the mouse leaves the canvas, the ellipse still sticks to the mouse and it is even possible to place the ellipse outside the canvas.

First I used the code (code is from stijn: C# - WPF - Mousemove event on canvas will overload the mouse events so click event is not fired) without the Borderaround the canvas in the xaml code. Then I read it might help to place a Borderarround the canvas (MouseMove event is called even when cursor is outside of canvas) and implemented it to the xaml code as you can see. Unfortunetely it did not help.

Can someone help me with a solution? A code solution wold be much appreciated, since I am a total beginner in c#.

1

There are 1 answers

6
Krishna On BEST ANSWER

Looks like you want to implement Adorners in your control. Do read about them as they will come handy to perform operations like these easily in wpf.

However, to fix your problem. You should be implementing MouseEnter and MouseLeave events to your code. Add the shape on MouseEnter and remove the shape on MouseLeave or MouseDown. So when the Mouse ReEnters the canvas the MouseEnter logic will kick in and will add the shape and your MouseMove logic will move the shape with the Mouse. Hope I am being clear here. Let me know if you are still struggling with the code.

EDIT

xaml

<Grid Background="Transparent">
        <Canvas x:Name="canvasss" Background="AntiqueWhite" Width="300" Height="300"  MouseEnter="canvasss_MouseEnter" MouseLeave="canvasss_MouseLeave"  MouseMove="Canvasss_MouseMove" MouseDown="Canvasss_MouseDown" Margin="50" HorizontalAlignment="Center" VerticalAlignment="Center"/>
    </Grid>

Code

public partial class MainWindow : Window
    {
        private readonly IList<Ellipse> shapes;
        private Ellipse currentMovingShape;
        public MainWindow()
        {
            InitializeComponent();
            shapes = new List<Ellipse>();
        }

        private void canvasss_MouseEnter(object sender, MouseEventArgs e)
        {
            AddEllipse();
        }

        private void AddEllipse()
        {
            currentMovingShape = new Ellipse { Width = 50, Height = 50, Fill = Brushes.Black };
            currentMovingShape.IsHitTestVisible = false;
            canvasss.Children.Add(currentMovingShape);
            Canvas.SetLeft(currentMovingShape, Mouse.GetPosition(canvasss).X - 25);
            Canvas.SetTop(currentMovingShape, Mouse.GetPosition(canvasss).Y - 25);
        }

        private void canvasss_MouseLeave(object sender, MouseEventArgs e)
        {
            if (currentMovingShape != null)
            {
                canvasss.Children.Remove(currentMovingShape);
                currentMovingShape = null;
            }
        }
        private void Canvasss_MouseMove(object sender, MouseEventArgs e)
        {
            Canvas.SetLeft(currentMovingShape, e.GetPosition(canvasss).X - 25);
            Canvas.SetTop(currentMovingShape, e.GetPosition(canvasss).Y - 25);
        }

        private void Canvasss_MouseDown(object sender, MouseButtonEventArgs e)
        {
            if (currentMovingShape != null)
            {
                currentMovingShape.IsHitTestVisible = true;
                shapes.Add(currentMovingShape);
                AddEllipse();
            }

        }
    }