3

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

4

4 回答 4

5

这应该通过 a 来实现,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

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

以下是如何在 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该类的命名空间在哪里。

于 2014-05-29T21:29:43.917 回答
4

如果您实施IScrollInfo,您可以以相同的方式覆盖MouseWheelUpto doMouseWheelLeft 和 down\right

编辑(更简单):

添加到您的 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();
                }
            }

        }

xml:

<ScrollViewer x:Name="myScrollViewer" HorizontalScrollBarVisibility="Visible" Mouse.PreviewMouseWheel="ScrollViewer_PreviewMouseWheel"> 
于 2012-08-22T10:18:10.883 回答
0

我有点在寻找最简单的方法来使任何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;
}
于 2018-11-09T14:55:36.840 回答
-1

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;
    }
}
于 2019-02-11T08:10:06.207 回答