Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to disable ScrollViewer in ListBox?

I have a ListBox. It has internal ScrollViewer, so I can scroll ListBox content with mouse wheel. It works fine until I set item template that contains another ListBox (in fact, I have 4 nested ListBoxes =)). Problem is that internal ListBox's ScrollViewer steals wheeling event. Is there any easy way to prevent this behavior?


I had ListBox with ItemContainerStyle like this:

<Style x:Key="ListBoxItemStyle" TargetType="{x:Type ListBoxItem}">
    <Setter Property="BorderBrush" Value="Black"/>
     ... 
</Style>
<ListBox ItemContainerStyle="{StaticResource ListBoxItemStyle}" />

How can I set style for ItemContainer's item border in resources like this? As I know ContentPresenter is item container of ItemsControl. But it hasn't Border, so I can't style it.

like image 981
levanovd Avatar asked Nov 15 '09 23:11

levanovd


3 Answers

You can remove the ScrollViewer from a ListBox by changing its control template to something much simpler:

<ListBox>
    <ListBox.Template>
        <ControlTemplate>
            <ItemsPresenter />
        </ControlTemplate>
    </ListBox.Template>
    ...
</ListBox>

However, I question the value of nesting ListBoxes. Remember that each ListBox is a Selector and has a concept of which item is "selected". Does it really make sense to have a selected item inside a selected item, inside a selected item?

I would suggest changing the "inner" ListBoxes to simple ItemsControls so that the nested lists can't have selected items. That would make for a much simpler user experience. You may still need to retemplate the inner ItemsControls in the same way to remove the scrollbars, but at least the user won't get confused about which item is "selected".

like image 189
Matt Hamilton Avatar answered Oct 06 '22 19:10

Matt Hamilton


You can disable stealing scroll events by catching scroll event in XAML:

<ListBox PreviewMouseWheel="ScrollViewer_PreviewMouseWheel">

and re-publishing it in Code behind:

private void ScrollViewer_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
    {
        if (sender is ListBox && !e.Handled)
        {
            e.Handled = true;
            var eventArg = new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta);
            eventArg.RoutedEvent = UIElement.MouseWheelEvent;
            eventArg.Source = sender;
            var parent = ((Control)sender).Parent as UIElement;
            parent.RaiseEvent(eventArg);
        }
    }

The solution is exactly for ListBox, it helped me with ListView.

I found this solution here:

https://social.msdn.microsoft.com/Forums/vstudio/en-US/3a3bb6b0-e088-494d-8ef2-60814415fd89/swallowing-mouse-scroll?forum=wpf

like image 14
tequilacat Avatar answered Oct 06 '22 20:10

tequilacat


I like to create a behavior for this type of thing.

xmlns:bhv="http://schemas.microsoft.com/xaml/behaviors"

<ListView ItemsSource="{Binding Items}">
    <bhv:Interaction.Behaviors>
        <bhvs:NoScrollingBehavior/>
    </bhv:Interaction.Behaviors>
</ListView>

The behavior itself.

public class NoScrollingBehavior : Behavior<UIElement>
{
    public NoScrollingBehavior()
    { }

    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.PreviewMouseWheel += PreviewMouseWheel;
    }

    protected override void OnDetaching()
    {
        AssociatedObject.PreviewMouseWheel -= PreviewMouseWheel;
        base.OnDetaching();
    }

    private void PreviewMouseWheel(object sender, MouseWheelEventArgs e)
    {
        e.Handled = true;
        var eventArg = new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta);
        eventArg.RoutedEvent = UIElement.MouseWheelEvent;
        eventArg.Source = sender;
        var parent = ((Control)sender).Parent as UIElement;
        parent.RaiseEvent(eventArg);
    }
}
like image 4
Blackey Avatar answered Oct 06 '22 18:10

Blackey