2

Is there a way to prevent a ScrollViewer from handling mouse scrolling?

The following code isn't sufficient, because the event shall be handled by a child element of the ScrollViewer instead:

private void ScrollViewer_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
     e.Handled = true;
}

EDIT - @Anders Keller Carstensen

I used to instantiate a PlotModel object directly, that's why I didn't see the AddHandler() method. I now changed my code, but the plot doesn't show anything:

public OxyPlot.Wpf.PlotView Plot { get; set; }

public MainWindow()
{
    InitializeComponent();
    DataContext = this;

    Plot = new OxyPlot.Wpf.PlotView();
    Plot.Model = new PlotModel();

    Plot.AddHandler(System.Windows.UIElement.PreviewMouseWheelEvent, new MouseWheelEventHandler(Plot_PreviewMouseWheel), true);

    // Create Line series
    var s1 = new LineSeries();
    s1.Points.Add(new DataPoint(2, 7));
    s1.Points.Add(new DataPoint(7, 9));
    s1.Points.Add(new DataPoint(9, 4));

    // add Series and Axis to plot model
    Plot.Model.Series.Add(s1);
    Plot.Model.InvalidatePlot(false);
}

private void ScrollViewer_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
    e.Handled = true;
}

private void Plot_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
    MessageBox.Show("Button_PreviewMouseWheel");
}

This is the corresponding XAML:

<ScrollViewer Margin="0,25,0,0" PreviewMouseWheel="ScrollViewer_PreviewMouseWheel">
    <oxy:PlotView Model="{Binding Plot}" Height="2000" Margin="0,0,15,0" />
</ScrollViewer>

I'm certain that Model="{Binding Plot}" is wrong, but I don't what to write instead.

Henste93
  • 273
  • 4
  • 21

1 Answers1

2

EDIT - here is a better solution.

You can set e.Handled = true in the ScrollViewer's PreviewMouseWheel event handler, and then still handle the event in your other control.

For example, let's say I have a button inside a grid in the ScrollViewer's Content. In the window's constructor, I subscribe to the button's PreviewMouseWheel event like this:

public ScrollViewerWindow() {
  InitializeComponent();

  btn.AddHandler(UIElement.PreviewMouseWheelEvent, 
                 new MouseWheelEventHandler(Button_PreviewMouseWheel), 
                 true // Handler will be called even though e.Handled = true
                );
}

Then your event handles will look like this:

private void ScrollViewer_PreviewMouseWheel(object sender, MouseWheelEventArgs e) {
  e.Handled = true;
}

private void Button_PreviewMouseWheel(object sender, MouseWheelEventArgs e) {
  MessageBox.Show("Button_PreviewMouseWheel");
}

This is an answer to your new question.

Give the PlotView a name in the XAML, and bind the Model to a PlotModel property.

<ScrollViewer Margin="0,25,0,0" PreviewMouseWheel="ScrollViewer_PreviewMouseWheel">
    <oxy:PlotView x:Name="pv" Model="{Binding PlotModel}" Height="2000" Margin="0,0,15,0" />
</ScrollViewer>

In your code-behind you should add the PlotModel property and initialize it:

public PlotModel PlotModel { get; set; }

public MainWindow()
{
    InitializeComponent();
    DataContext = this;

    pv.AddHandler(System.Windows.UIElement.PreviewMouseWheelEvent, new MouseWheelEventHandler(Plot_PreviewMouseWheel), true);

    // Create Line series
    var s1 = new LineSeries();
    s1.Points.Add(new DataPoint(2, 7));
    s1.Points.Add(new DataPoint(7, 9));
    s1.Points.Add(new DataPoint(9, 4));

    // add Series and Axis to plot model
    PlotModel = new PlotModel();
    PlotModel.Series.Add(s1);
    PlotModel.InvalidatePlot(false);
}

private void ScrollViewer_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
    e.Handled = true;
}

private void Plot_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
    MessageBox.Show("Plot_PreviewMouseWheel");
}

Old solution:

Creating a sub-class of ScrollViewer that responds negative to all HitTest requests seems to solve your problem - however, it may have side-effects that you don't like. Check it out and see if it suits your needs.

First, create the sub-class:

public class MyScrollViewer : ScrollViewer {
  protected override HitTestResult HitTestCore(PointHitTestParameters hitTestParameters) {
    return null;
  }
}

Then, in the XAML, change <ScrollViewer> to <local:MyScrollViewer>.

Make sure the local namespace is declared. It will look something like this:

<Window ....
        xmlns:local="clr-namespace:WPFTest">

Anders Carstensen
  • 2,949
  • 23
  • 23
  • Thanks for your answer. I tried it out, but it didn't change anything. – Henste93 Oct 22 '15 at 13:05
  • I have edited my answer - hopefully this will work for you. – Anders Carstensen Oct 22 '15 at 14:23
  • I appreciate your effort. Unfortunately I don't have a standard UI Element in the Scrollviewer, but a Oxyplot.Wpf.PlotView. It does not have such method like `AddHandler()`. – Henste93 Oct 23 '15 at 06:31
  • @Henste I downloaded OxyPlot from [NuGet](https://www.nuget.org/packages/OxyPlot.Wpf/1.0.0-unstable1870), and `OxyPlot.Wpf.PlotView` does have an `AddHandler()`. I also verified that the above code works on it. – Anders Carstensen Oct 23 '15 at 07:46
  • Thanks, your code works! There is still one major problem: In the `Plot_PreviewMouseWheel()` function I call `PlotModel.ZoomAllAxes(2)`. Although I then call `PlotModel.InvalidatePlot(false)`, the plot first gets updated, when the position of the scrollbar is at the top or bottom of the ScrollViewer. – Henste93 Oct 23 '15 at 12:55
  • @Henste Yeah, I can reproduce that bug too. But it has nothing to do with the solution above; if you remove everything to do with PreviewMouseWheel, and instead put a button that calls ZoomAllAxes, you will have the exact same error when the ScrollViewer is not scrolled to the top/bottom. Perhaps it is a bug in OxyPlot? You could make another question about this specific error - maybe some OxyPlot expert will be able to help. – Anders Carstensen Oct 23 '15 at 14:05