Search code examples
c#.netwpfwpf-4.0wpf-graphics

What is wrong with my Rectangle drawing coordinates?


I'm trying to use the following code to allow the user to draw a rectangle around something on the screen, to select that area.

public partial class MainWindow : Window
{
    public enum DrawMode
    {
        Move,
        Draw
    }

    private DrawMode _drawmode;
    private Point _startPoint;
    private Rectangle _rectangle;
    public MainWindow()
    {
        _rectangle = new Rectangle();
        _rectangle.Stroke = new SolidColorBrush(Colors.Black);
        _rectangle.StrokeThickness = 1;
        InitializeComponent();
    }

    private void MapImageOnMouseDown(object sender, MouseButtonEventArgs e)
    {
        _drawmode = DrawMode.Draw;
        _startPoint = e.GetPosition(DrawCanvas);
    }

    private void MapImageOnMouseUp(object sender, MouseButtonEventArgs e)
    {
        _drawmode = DrawMode.Move;
    }

    private void MapImageOnMouseMove(object sender, MouseEventArgs e)
    {
        if (_drawmode == DrawMode.Draw)
        {
            DrawCanvas.Children.Remove(_rectangle);
            var endPoint = e.GetPosition(DrawCanvas);
            var width = Math.Abs(endPoint.X - _startPoint.X);
            var height = Math.Abs(endPoint.Y - _startPoint.Y);
            _rectangle.Width = width;
            _rectangle.Height = height;
            DrawCanvas.Children.Add(_rectangle);
            Canvas.SetTop(_rectangle, _startPoint.X);
            Canvas.SetLeft(_rectangle, _startPoint.Y);
        }
    }
}

However, although when I mousedown, the top left of the rectangle is nowhere near the point that I mousedown at. Are there different coordinate systems or something?


Solution

  • You have confused X and Y (or Left and Top). Change

    Canvas.SetTop(_rectangle, _startPoint.X);
    Canvas.SetLeft(_rectangle, _startPoint.Y);
    

    to

    Canvas.SetLeft(_rectangle, _startPoint.X);
    Canvas.SetTop(_rectangle, _startPoint.Y);
    

    It is also not necessary to remove and add the Rectangle each time its position changes:

    public MainWindow()
    {
        InitializeComponent();
    
        _rectangle = new Rectangle
        {
            Stroke = Brushes.Black,
            StrokeThickness = 1
        };
    
        DrawCanvas.Children.Add(_rectangle); // add it once
    }
    
    private void MapImageOnMouseMove(object sender, MouseEventArgs e)
    {
        if (_drawmode == DrawMode.Draw)
        {
            var endPoint = e.GetPosition(DrawCanvas);
            _rectangle.Width = Math.Abs(endPoint.X - _startPoint.X);
            _rectangle.Height = Math.Abs(endPoint.Y - _startPoint.Y);
            Canvas.SetLeft(_rectangle, Math.Min(_startPoint.X, endPoint.X));
            Canvas.SetTop(_rectangle, Math.Min(_startPoint.Y, endPoint.Y));
        }
    }