【问题标题】:Activate horizontal scrolling with mouse on ListView在 ListView 上使用鼠标激活水平滚动
【发布时间】:2019-02-12 17:57:34
【问题描述】:

我有一个自定义的水平 ListView,它的模板中有自定义的 ScrollViewer(使用 Blend 创建)。我希望它在使用鼠标滚轮时水平滚动。 我该怎么做?

【问题讨论】:

    标签: wpf listview scroll mouse


    【解决方案1】:

    这应该使用Behavior 来完成,以提高可重用性。此外,ZSH 的逻辑是多余的,可以简化。这是我的代码:

    /// <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);
        }
    }
    

    您需要添加以下引用: System.WindowsSystem.Windows.ControlsSystem.Windows.Input,您可能需要获取 Blend SDK NuGet 包,并在“程序集扩展”部分找到并引用 System.Windows.Interactivity DLL。

    将此用于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;
         }
    }
    

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

    请注意,它与Windows.System.Media 中的VisualTreeHelper 不同。

    下面是如何在 XAML 中使用它:

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

    i 命名空间被声明为xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"

    behaviors 被声明为

    xmlns:behaviors="clr-namespace:MyNamespace"

    其中MyNamespace 是包含HorizontalScrollBehavior 类的命名空间。

    【讨论】:

    • +1 因为它为我节省了大量时间来寻找合适的解决方案。顺便说一句,这里是VisualTreeHelpers 实现的链接:codereview.stackexchange.com/questions/44760/…
    • 发现i也可以这样引用:xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
    【解决方案2】:

    如果您实现IScrollInfo,您可以覆盖MouseWheelUp 来执行MouseWheelLeft 并以同样的方式向下\向右

    编辑(更简单):

    添加到您的 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"> 
    

    【讨论】:

    • 你的意思是像里面的控件? “自定义”是指我有一个自定义模板。您的解决方案是否需要实现从 WPF ListView 继承的新 ListView 类?
    • 我的解决方案意味着您在自定义面板上实现滚动信息并使用面板
    • 还是不知道放哪里。我的代码如下所示:
    • 其余在后面的代码中
    • 我无法从资源字典中的样式访问代码
    【解决方案3】:

    我有点想寻找最简单的方法来让任何ScrollViewer 左右滚动而不是上下滚动。所以这是其他答案的最简单组合。

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

    和:

    private void ScrollViewer_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
    {
        ScrollViewer scrollViewer = (ScrollViewer)sender;
        if (e.Delta < 0)
        {
            scrollViewer.LineRight();
        }
        else
        {
            scrollViewer.LineLeft();
        }
        e.Handled = true;
    }
    

    【讨论】:

      【解决方案4】:

      Xaml 代码:

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

      C# 代码

      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;
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2016-03-14
        • 1970-01-01
        • 2015-02-25
        • 2021-07-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多