Activate horizontal scrolling with mouse on ListView

后端 未结 4 1108
不思量自难忘°
不思量自难忘° 2020-12-18 13:30

I\'ve got a custom horizontal ListView with custom ScrollViewer inside it\'s template (created with Blend). I want it to scroll horizontally when using mouse scrolling wheel

相关标签:
4条回答
  • 2020-12-18 14:01

    This should be done with a Behavior for greater reusability. Also, the logic from ZSH is redundant and could be simplified. Here's my code:

    /// <summary>
    /// Allows an <see cref="ItemsControl"/> to scroll horizontally by listening to the
    /// <see cref="PreviewMouseWheel"/> event of its internal <see cref="ScrollViewer"/>.
    /// </summary>
    public class HorizontalScrollBehavior : Behavior<ItemsControl>
    {
        /// <summary>
        /// A reference to the internal ScrollViewer.
        /// </summary>
        private ScrollViewer ScrollViewer { get; set; }
    
        /// <summary>
        /// By default, scrolling down on the wheel translates to right, and up to left.
        /// Set this to true to invert that translation.
        /// </summary>
        public bool IsInverted { get; set; }
    
        /// <summary>
        /// The ScrollViewer is not available in the visual tree until the control is loaded.
        /// </summary>
        protected override void OnAttached()
        {
            base.OnAttached();
    
            AssociatedObject.Loaded += OnLoaded;
        }
    
        private void OnLoaded(object sender, RoutedEventArgs e)
        {
            AssociatedObject.Loaded -= OnLoaded;
    
            ScrollViewer = VisualTreeHelpers.FindVisualChild<ScrollViewer>(AssociatedObject);
    
            if (ScrollViewer != null)
            {
                ScrollViewer.PreviewMouseWheel += OnPreviewMouseWheel;
            }
        }
    
        protected override void OnDetaching()
        {
            base.OnDetaching();
    
            if (ScrollViewer != null)
            {
                ScrollViewer.PreviewMouseWheel -= OnPreviewMouseWheel;
            }
        }
    
        private void OnPreviewMouseWheel(object sender, MouseWheelEventArgs e)
        {
            var newOffset = IsInverted ?
                ScrollViewer.HorizontalOffset + e.Delta :
                ScrollViewer.HorizontalOffset - e.Delta;
    
            ScrollViewer.ScrollToHorizontalOffset(newOffset);
        }
    }
    

    You'll need to add the following references: System.Windows, System.Windows.Controls, System.Windows.Input, and you may need to get the Blend SDK NuGet package, and find and reference the System.Windows.Interactivity DLL in the Assemblies Extensions section.

    Use this for VisualTreeHelpers:

    public class VisualTreeHelpers
    {
        /// <summary>
        /// Return the first visual child of element by type.
        /// </summary>
        /// <typeparam name="T">The type of the Child</typeparam>
        /// <param name="obj">The parent Element</param>
        public static T FindVisualChild<T>(DependencyObject obj) where T : DependencyObject
        {
            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
            {
                DependencyObject child = VisualTreeHelper.GetChild(obj, i);
                if (child != null && child is T)
                    return (T)child;
                else
                {
                    T childOfChild = FindVisualChild<T>(child);
                    if (childOfChild != null)
                        return childOfChild;
                }
            }
            return null;
         }
    }
    

    Reference: https://codereview.stackexchange.com/questions/44760/is-there-a-better-way-to-get-a-child

    Note that it is NOT the same as VisualTreeHelper in Windows.System.Media.

    Here's how to use it in XAML:

    <ListBox>
        <i:Interaction.Behaviors>
            <behaviors:HorizontalScrollBehavior />
        </i:Interaction.Behaviors>
    </ListBox>
    

    Where the i namespace is declared as xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" and

    behaviors is declared as

    xmlns:behaviors="clr-namespace:MyNamespace"

    where MyNamespace is the namespace that contains the HorizontalScrollBehavior class.

    0 讨论(0)
  • 2020-12-18 14:08

    if you implement IScrollInfo you can override the MouseWheelUp to do MouseWheelLeft and down\right the in same way

    edit (much more simple):

    add to your ScrollViewer PreviewMouseWheel

    private void ScrollViewer_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
            {
                if (e.Delta < 0) // wheel down
                {
                    if (myScrollViewer.HorizontalOffset + e.Delta > 0)
                    {
                        myScrollViewer.ScrollToHorizontalOffset(myScrollViewer.HorizontalOffset + e.Delta);  
                    }
                    else
                    {
                        myScrollViewer.ScrollToLeftEnd();
                    }
                }
                else //wheel up
                {
                    if (myScrollViewer.ExtentWidth > myScrollViewer.HorizontalOffset + e.Delta)
                    {
                        myScrollViewer.ScrollToHorizontalOffset(myScrollViewer.HorizontalOffset + e.Delta);  
                    }
                    else
                    {
                        myScrollViewer.ScrollToRightEnd();
                    }
                }
    
            }
    

    xaml:

    <ScrollViewer x:Name="myScrollViewer" HorizontalScrollBarVisibility="Visible" Mouse.PreviewMouseWheel="ScrollViewer_PreviewMouseWheel"> 
    
    0 讨论(0)
  • 2020-12-18 14:10

    Xaml Code:

    <ScrollViewer HorizontalScrollBarVisibility="Visible" 
                  VerticalScrollBarVisibility="Visible" 
                  PreviewMouseWheel="ScrollViewer_PreviewMouseWheel"> 
    </ScrollViewer>
    

    C# Code

    private void ScrollViewer_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
    {
        var scrollViewer = (ScrollViewer)sender;
        if (Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift))
        {
            scrollViewer.ScrollToHorizontalOffset(scrollViewer.HorizontalOffset - e.Delta);
            e.Handled = true;
        }
    }
    
    0 讨论(0)
  • 2020-12-18 14:17

    I was kinda looking for the most simple way to make any ScrollViewer scroll left-right instead of up-down. So here is the simplest combination of the other answers.

    <ScrollViewer HorizontalScrollBarVisibility="Visible"
                  PreviewMouseWheel="ScrollViewer_PreviewMouseWheel"> 
    

    and:

    private void ScrollViewer_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
    {
        ScrollViewer scrollViewer = (ScrollViewer)sender;
        if (e.Delta < 0)
        {
            scrollViewer.LineRight();
        }
        else
        {
            scrollViewer.LineLeft();
        }
        e.Handled = true;
    }
    
    0 讨论(0)
提交回复
热议问题