1
votes

I have a canvas which has a zooming function. There are a lot of elements inside of it so, for selection I was going to use a selection box which I create dynamically when selection box is clicked. On clicking the button, I add the rectangle to the canvas and again, on clicking the button, I remove it. I have the following xaml code:

<Viewbox x:Name="vbCanvas">
            <Grid x:Name="theGrid"
                  MouseDown="Grid_MouseDown"
                  MouseUp="Grid_MouseUp"
                  MouseMove="Grid_MouseMove"
                  Background="Transparent">

                <Canvas Name="canvasWaSNA" Margin="0,10,10,10" Height="720" Width="1280">

                </Canvas>
            </Grid>
        </Viewbox>

mouse events of theGrid draws the rectangle on runtime on the canvas. The codes for those events are:

bool mouseDown = false; 
Point mouseDownPos;
Point mouseUpPos;
private void Grid_MouseDown(object sender, MouseButtonEventArgs e)
    {
            mouseDown = true;
            mouseDownPos = e.GetPosition(theGrid);
            theGrid.CaptureMouse();
            // Initial placement of the drag selection box.         
            Canvas.SetLeft(sBox, mouseDownPos.X);
            Canvas.SetTop(sBox, mouseDownPos.Y);
            sBox.Width = 0;
            sBox.Height = 0;

            // Make the drag selection box visible.
            sBox.Visibility = Visibility.Visible;
        }
    }

    private void Grid_MouseUp(object sender, MouseButtonEventArgs e)
    {
            // Release the mouse capture and stop tracking it.
            mouseDown = false;
            mouseUpPos = e.GetPosition(theGrid);

            theGrid.ReleaseMouseCapture();

            // Show the drag selection box.
            sBox.Visibility = Visibility.Visible;

            MessageBox.Show(mouseDownPos.ToString() + " " + mouseUpPos.ToString());

    }

    private void Grid_MouseMove(object sender, MouseEventArgs e)
    {
            if (mouseDown)
            {
                // When the mouse is held down, reposition the drag selection box.
                Point mousePos = e.GetPosition(theGrid);

                if (mouseDownPos.X < mousePos.X)
                {
                    Canvas.SetLeft(sBox, mouseDownPos.X);
                    sBox.Width = mousePos.X - mouseDownPos.X;
                }
                else
                {
                    Canvas.SetLeft(sBox, mousePos.X);
                    sBox.Width = mouseDownPos.X - mousePos.X;
                }

                if (mouseDownPos.Y < mousePos.Y)
                {
                    Canvas.SetTop(sBox, mouseDownPos.Y);
                    sBox.Height = mousePos.Y - mouseDownPos.Y;
                }
                else
                {
                    Canvas.SetTop(sBox, mousePos.Y);
                    sBox.Height = mouseDownPos.Y - mousePos.Y;
                }
            }

    }

To create a Rectangle at runtime, I have to click a button. The event of that button is as follows:

private void select_Click_1(object sender, RoutedEventArgs e)
    {

            if (!canvasWaSNA.Children.Contains(sBox))
            {

                sBox.Name = "selectionBox";
                sBox.StrokeThickness = 1.5 / zoomfactor;
                sBox.StrokeDashArray = new DoubleCollection { 1, 2 };
                sBox.Visibility = System.Windows.Visibility.Collapsed;
                sBox.Stroke = Brushes.Gray;
                canvasWaSNA.Children.Add(sBox);

        }
        else
        {
            sBox.Visibility = System.Windows.Visibility.Collapsed;
            canvasWaSNA.Children.Remove(sBox);

        }
    }

I am using the following code to zoom into the canvas:

double zoomfactor = 1.0;
    void window_MouseWheel(object sender, MouseWheelEventArgs e)
    {
        Point p = e.MouseDevice.GetPosition(canvasWaSNA); //gets the location of the canvas at which the mouse is pointed

        Matrix m = canvasWaSNA.RenderTransform.Value;
        if (e.Delta > 0)
        { //the amount of wheel of mouse changed. e.Delta holds int value.. +ve for uproll and -ve for downroll
            m.ScaleAtPrepend(1.1, 1.1, p.X, p.Y);
            zoomfactor *= 1.1;
        }
        else
        {
            m.ScaleAtPrepend(1 / 1.1, 1 / 1.1, p.X, p.Y);
            zoomfactor /= 1.1;
        }

        canvasWaSNA.RenderTransform = new MatrixTransform(m);
    }

When my canvas is on original size, The rectangle is drawn perfectly but as I zoom in or zoom out, rectangle is drawn abnormally. It starts to draw from other points. What might be the problem? Please help

1

1 Answers

0
votes

Well, I wasnot supposed to capture the mouse position with respect to theGrid, as I had to create the rectangle with respect to canvas. So, I have to get the position as e.GetPosition(canvasWaSNA) and the intended result was shown. It captured the mouse position on the canvas. Now, the rectangle is drawn perfectly even when zoomed in or zoomed out. Also, I improved the StrokeThickness of the rectangle drawn by referencing it with the zoomfactor of the canvas.

private void Grid_MouseDown(object sender, MouseButtonEventArgs e)
    {mouseDown = true;
            mouseDownPos = e.GetPosition(canvasWaSNA);
            theGrid.CaptureMouse();
            sBox.StrokeThickness = 1.5 / zoomfactor;

            // Initial placement of the drag selection box.         
            Canvas.SetLeft(sBox, mouseDownPos.X);
            Canvas.SetTop(sBox, mouseDownPos.Y);
            sBox.Width = 0;
            sBox.Height = 0;

            // Make the drag selection box visible.
            sBox.Visibility = Visibility.Visible;
        }