I cannot determine how to scroll horizontally using the mouse wheel. Vertical scrolling works well automatically, but I need to scroll my content horizontally. My code looks lik
(sender as ScrollViewer).ScrollToHorizontalOffset( (sender as ScrollViewer).ContentHorizontalOffset + e.Delta);
I wrote an Attached Property
for this purpose to reuse it on every ItemsControl
containing an ScrollViewer. FindChildByType
is an Telerik extension but can also be found here.
public static readonly DependencyProperty UseHorizontalScrollingProperty = DependencyProperty.RegisterAttached(
"UseHorizontalScrolling", typeof(bool), typeof(ScrollViewerHelper), new PropertyMetadata(default(bool), UseHorizontalScrollingChangedCallback));
private static void UseHorizontalScrollingChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
{
ItemsControl itemsControl = dependencyObject as ItemsControl;
if (itemsControl == null) throw new ArgumentException("Element is not an ItemsControl");
itemsControl.PreviewMouseWheel += delegate(object sender, MouseWheelEventArgs args)
{
ScrollViewer scrollViewer = itemsControl.FindChildByType<ScrollViewer>();
if (scrollViewer == null) return;
if (args.Delta < 0)
{
scrollViewer.LineRight();
}
else
{
scrollViewer.LineLeft();
}
};
}
public static void SetUseHorizontalScrolling(ItemsControl element, bool value)
{
element.SetValue(UseHorizontalScrollingProperty, value);
}
public static bool GetUseHorizontalScrolling(ItemsControl element)
{
return (bool)element.GetValue(UseHorizontalScrollingProperty);
}
Try this:
<ListBox x:Name="receiptList"
Margin="5,0"
Grid.Row="1"
ItemTemplate="{StaticResource receiptListItemDataTemplate}"
ItemsSource="{Binding OpenReceipts}"
ScrollViewer.VerticalScrollBarVisibility="Disabled"
ScrollViewer.HorizontalScrollBarVisibility="Visible"
>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ListBox>
UPDATE Ooops, missed the part about the mouse wheel! Sorry
To make the mouse wheel work, you will have to subscribe to the mouse wheel event and manuaaly move the scroll bar... This can nicelly be encapsulated by a behavior but I think thats the only way to make it work!
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;
}
This is basically what John Gardner suggested just with the actual code. I'm also quoting my answer from similar question here.
The easiest way is to add PreviewMouseWheel
listener to the ScrollViewer
, check for shift (or whatever you want to do to indicate horizontal scroll), and then call LineLeft
or LineRight
(or PageLeft
/ PageRight
) depending on the value of the Delta
value of the MouseWheelEventArgs
Here's a complete behaviour. Add the below class to your code, then in your XAML set the attached property to true on any UIElement
that contains a ScrollViewer
as a visual child.
<MyVisual ScrollViewerHelper.ShiftWheelScrollsHorizontally="True" />
The class:
public static class ScrollViewerHelper
{
public static readonly DependencyProperty ShiftWheelScrollsHorizontallyProperty
= DependencyProperty.RegisterAttached("ShiftWheelScrollsHorizontally",
typeof(bool),
typeof(ScrollViewerHelper),
new PropertyMetadata(false, UseHorizontalScrollingChangedCallback));
private static void UseHorizontalScrollingChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var element = d as UIElement;
if (element == null)
throw new Exception("Attached property must be used with UIElement.");
if ((bool)e.NewValue)
element.PreviewMouseWheel += OnPreviewMouseWheel;
else
element.PreviewMouseWheel -= OnPreviewMouseWheel;
}
private static void OnPreviewMouseWheel(object sender, MouseWheelEventArgs args)
{
var scrollViewer = ((UIElement)sender).FindDescendant<ScrollViewer>();
if (scrollViewer == null)
return;
if (Keyboard.Modifiers != ModifierKeys.Shift)
return;
if (args.Delta < 0)
scrollViewer.LineRight();
else
scrollViewer.LineLeft();
args.Handled = true;
}
public static void SetShiftWheelScrollsHorizontally(ItemsControl element, bool value) => element.SetValue(ShiftWheelScrollsHorizontallyProperty, value);
public static bool GetShiftWheelScrollsHorizontally(ItemsControl element) => (bool)element.GetValue(ShiftWheelScrollsHorizontallyProperty);
[CanBeNull]
private static T FindDescendant<T>([CanBeNull] this DependencyObject d) where T : DependencyObject
{
if (d == null)
return null;
var childCount = VisualTreeHelper.GetChildrenCount(d);
for (var i = 0; i < childCount; i++)
{
var child = VisualTreeHelper.GetChild(d, i);
var result = child as T ?? FindDescendant<T>(child);
if (result != null)
return result;
}
return null;
}
}
This answer fixes a few bugs in Johannes' answer, such as not filtering by Shift key, scrolling both horizontally and vertically at the same time (motion was diagonal) and the inability to disable the behaviour by setting the property to false.