views:

663

answers:

2

I have a usercontrol that has a scrollviewer, then a bunch of child controls like text boxes, radio buttons, and listboxes, etc inside of it. I can use the mouse wheel to scroll the parent scrollviewer until my mouse lands inside a listbox then, the mouse wheel events start going to the listbox. is there any way to have the listbox send those events back up to the parent control? removing the listbox from within side the parent control like this question suggests (http://stackoverflow.com/questions/761243/wpf-mouse-wheel-not-working-when-over-scrollviewers-child-controls) isnt a solution.

I have tried

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

but that didnt work either.

Thanks

+1  A: 

The answer you have referenced is exactly what is causing your problem, the ListBox (which is composed of among other things a ScrollViewer) inside your ScrollViewer catches the MouseWheel event and handles it, preventing it from bubbling and thus the ScrollViewer has no idea the event ever occurred.

Use the following extremely simple ControlTemplate for your ListBox to demonstrate (note it does not have a ScrollViewer in it and so the MouseWheel event will not be caught) The ScrollViewer will still scroll with the mouse over the ListBox.

<UserControl.Resources>
     <ControlTemplate x:Key="NoScroll">
         <ItemsPresenter></ItemsPresenter>
     </ControlTemplate>
</UserControl.Resources>

<ScrollViewer>
    <SomeContainerControl>
        <.... what ever other controls are inside your ScrollViewer>
        <ListBox Template="{StaticResource NoScroll}"></ListBox>
    <SomeContainerControl>
</ScrollViewer>

You do have the option of capturing the mouse when it enters the ScrollViewer though so it continues to receive all mouse events until the mouse is released, however this option would require you to delgate any further mouse events to the controls contained within the ScrollViewer if you want a response...the following MouseEnter MouseLeave event handlers will be sufficient.

private void ScrollViewerMouseEnter(object sender, MouseEventArgs e)
{
    ((ScrollViewer)sender).CaptureMouse();
}

private void ScrollViewerMouseLeave(object sender, MouseEventArgs e)
{
    ((ScrollViewer)sender).ReleaseMouseCapture();
}

Neither of the workarounds I have provided are really preferred however and I would suggest rethinking what you are actually trying to do. If you explain what you are trying to achieve in your question I'm sure you will get some more suggestions...

Simon Fox
A: 

As Simon said, it's the ScrollViewer in the standard ListBox template that's catching the event. To bypass it you can provide your own template.

<ControlTemplate x:Key="NoWheelScrollListBoxTemplate" TargetType="ListBox">
    <Border BorderThickness="{TemplateBinding Border.BorderThickness}" Padding="1,1,1,1" BorderBrush="{TemplateBinding Border.BorderBrush}" Background="{TemplateBinding Panel.Background}" Name="Bd" SnapsToDevicePixels="True">
        <!-- This is the new control -->
        <l:NoWheelScrollViewer Padding="{TemplateBinding Control.Padding}" Focusable="False">
            <ItemsPresenter SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
        </l:NoWheelScrollViewer>
    </Border>
    <ControlTemplate.Triggers>
        <Trigger Property="UIElement.IsEnabled" Value="False">
            <Setter TargetName="Bd" Property="Panel.Background" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" />
        </Trigger>
        <Trigger Property="ItemsControl.IsGrouping" Value="True">
            <Setter Property="ScrollViewer.CanContentScroll" Value="False" />
        </Trigger>
    </ControlTemplate.Triggers>
</ControlTemplate>

And the implementation for NoWheelScrollViewer is pretty simple.

public class NoWheelScrollViewer : ScrollViewer
{
    protected override void OnMouseWheel(MouseWheelEventArgs e)
    {
        // Do nothing
    }
}

Then, whenever you want a listbox to not handle the mouse wheel.

<ListBox Template="{StaticResource NoWheelScrollListBoxTemplate}">
Cameron MacFarland