Search code examples
c#wpfrectangles

Not able to draw rectangle on Wpf canvas from lower right corner to upper left corner


I am implementing functionality to allow user to draw rectangle on a Wpf canvas at run time by dragging mouse.I am currently able to able to draw the rectangle when I drag mouse from top left corner to bottom left, but the rectangle is not visible when I drag mouse from bottom left corner to top.Below is the xaml code that I am using:

<Canvas x:Name="CanvasContainer" MouseLeftButtonDown="CanvasContainer_MouseLeftButtonDown" MouseLeftButtonUp="CanvasContainer_MouseLeftButtonUp" MouseMove="CanvasContainer_MouseMove" >
   <Rectangle  x:Name="RectangleMarker" Canvas.Left="0"  Stroke="Red" Width="0" Height="0" Panel.ZIndex="1"></Rectangle>
   <Line x:Name="LineMarker"  Stroke="Red" X1="0" Y1="0" X2="0" Y2="0"></Line>
   <Image Canvas.Left="0" Canvas.Top="0"  x:Name="PdfImage" RenderTransformOrigin="0.5,0.5" MouseWheel="PdfImage_MouseWheel"  ClipToBounds="True" Panel.ZIndex="0">
        <Image.LayoutTransform>
            <ScaleTransform ScaleX="1" ScaleY="1"  CenterX="0.5" CenterY="0.5"  />
        </Image.LayoutTransform>
    </Image>
</Canvas>

Below are the event handling to update rectangle's position according to mouse position.

private void CanvasContainer_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    try
    {          
            Point startPoint = Mouse.GetPosition(CanvasContainer);
            Canvas.SetLeft(RectangleMarker, startPoint.X);
            Canvas.SetTop(RectangleMarker,startPoint.Y);      
    }
    catch (Exception ex)
    {

    }
}

private void CanvasContainer_MouseMove(object sender, MouseEventArgs e)
{
    try
    {
        if (e.LeftButton == MouseButtonState.Pressed)
        {               
                Point endPoint = Mouse.GetPosition(CanvasContainer);
                Point startPoint = new Point((double)RectangleMarker.GetValue(Canvas.LeftProperty), (double)RectangleMarker.GetValue(Canvas.TopProperty));
                double x = Math.Min(startPoint.X, endPoint.X);
                double y = Math.Min(startPoint.Y, endPoint.Y);
                double width = endPoint.X - startPoint.X;
                double height = endPoint.Y - startPoint.Y;

                if (width < 0)
                {
                    x = startPoint.X + width;
                }
                if (height < 0)
                {
                    y = startPoint.Y + height;
                }
                RectangleMarker.Width = Math.Abs(width);
                RectangleMarker.Height = Math.Abs(height);
                if (x!=startPoint.X)
                {
                    Canvas.SetLeft(RectangleMarker, x);
                }
                else if(y!=startPoint.Y)
                {
                    Canvas.SetTop(RectangleMarker, y); 
                }                
        }          
    }
    catch (Exception ex)
    {

    }
}

Solution

  • Better use a Path with a RectangleGeometry:

    <Canvas Background="Transparent"
            MouseLeftButtonDown="CanvasContainer_MouseLeftButtonDown"
            MouseLeftButtonUp="CanvasContainer_MouseLeftButtonUp"
            MouseMove="CanvasContainer_MouseMove">
        <Path Stroke="Red">
            <Path.Data>
                <RectangleGeometry x:Name="selectionRect"/>
            </Path.Data>
        </Path>
    </Canvas>
    

    Code behind:

    private Point? startPoint;
    
    private void CanvasContainer_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        var element = (UIElement)sender;
        element.CaptureMouse();
        startPoint = e.GetPosition(element);
    }
    
    private void CanvasContainer_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    {
        ((UIElement)sender).ReleaseMouseCapture();
        startPoint = null;
    }
    
    private void CanvasContainer_MouseMove(object sender, MouseEventArgs e)
    {
        if (startPoint.HasValue)
        {
            selectionRect.Rect = new Rect(
                startPoint.Value, e.GetPosition((IInputElement)sender));
        }
    }