Search code examples
c#wpfrouted-events

WPF how to stop scrollviewer from moving up and down during zooming


I have a Grid inside ScrollViewer. I set a long height for the grid.

Dynamically, I add a Canvas to my Grid and add 2 rectangles inside it. The mouse zoom event is working but when I launch the app and scroll down to the end of the 2 boxes and I try to zoom with the mouse, the scrollviewer goes up to its starting location. I don't want to disable it, I want it to keep showing but not move up.

  • MainWindow.xaml
<ScrollViewer VerticalScrollBarVisibility="Visible" HorizontalScrollBarVisibility="Visible" Name="sv">
    <Grid Name="myGrid">
        <Grid.RowDefinitions>
            <RowDefinition Height="50" />
            <RowDefinition Height="5000" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="330" />
        </Grid.ColumnDefinitions>
    </Grid>
</ScrollViewer>
  • MainWindow.xaml.cs
public partial class MainWindow : Window
{
    double currentZoom = 0;
    ScaleTransform scaleTransform;
    TransformGroup transformGroup;

    public MainWindow()
    {
        InitializeComponent();
        scaleTransform = new ScaleTransform();
        transformGroup = new TransformGroup();

        transformGroup.Children.Add(scaleTransform);
        begin();
    }
    private void begin()
    {
        Canvas canvas = new Canvas();
        Rectangle rectangle1 = new Rectangle
        {
            Width = 300,
            Height = 600,
            Fill = new SolidColorBrush(Color.FromRgb(255, 255, 255)),
            StrokeThickness = 2,
            Stroke = Brushes.Black
        };
        Canvas.SetLeft(rectangle1, 100);
        Canvas.SetTop(rectangle1, 100);
        canvas.Children.Add(rectangle1);

        Rectangle rectangle2 = new Rectangle
        {
            Width = 300,
            Height = 600,
            Fill = new SolidColorBrush(Color.FromRgb(255, 255, 255)),
            StrokeThickness = 2,
            Stroke = Brushes.Black
        };
        Canvas.SetLeft(rectangle2, 200);
        Canvas.SetTop(rectangle2, 200);
        canvas.Children.Add(rectangle2);

        myGrid.Children.Add(canvas);
        myGrid.RenderTransform = transformGroup;
        myGrid.MouseWheel += (sender, e) => wheelEvent(sender, e);
    }
    private void wheelEvent(object sender, MouseWheelEventArgs e)
    {
        Point position = e.GetPosition(myGrid);

        scaleTransform.CenterX = position.X;
        scaleTransform.CenterY = position.Y;

        var newZoom = e.Delta / 120 / (double)50;
        scaleTransform.ScaleX = 1 + newZoom + currentZoom;
        scaleTransform.ScaleY = 1 + newZoom + currentZoom;
        currentZoom += newZoom;
    }
}

Solution

  • You can use MouseWheelEventArgs.Handled property to stop other event handlers from doing their thing.

    private void wheelEvent(object sender, MouseWheelEventArgs e)
    {
        //Might be a good idea to use some custom condition
        //that determines if you are zooming or not like:
        //if(!IsCtrlButtonPressed) return;
        //If you return with e.Handled == false 
        //ScrollViewer's handler will scroll you normally
    
        //suppress MouseWheel event and other MouseWheel responders
        e.Handled = true;
    
        //your zooming logic
    }
    

    More info here: MSDN