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. How can I do that?
问题:
回答1:
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">
回答2:
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.
回答3:
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;
}
回答4:
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;
}
}