I need to prevent a ComboBox
from scrolling (using the scroll wheel) when it is focused
.
However, I need its parent UIElement
to still scroll.
I got the following code from this question, which prevents any scrolling, including that of the parent UIElement
.
<ComboBox comboBox:NoScrollingBehaviour.Enabled="True"
IsEditable="True"
IsTextSearchEnabled="True"
IsTextSearchCaseSensitive="False"
StaysOpenOnEdit="True"
Text="{Binding MyTextProperty}"
ItemsSource="{Binding DataContext.MySourceProperty, ElementName=MyElementName}"/>
using System.Windows;
using System.Windows.Input;
namespace AE.UI.ComboBox
{
public static class NoScrollingBehaviour
{
public static readonly DependencyProperty EnabledProperty =
DependencyProperty.RegisterAttached("Enabled", typeof(bool), typeof(NoScrollingBehaviour),
new UIPropertyMetadata(false, OnEnabledChanged));
public static bool GetEnabled(System.Windows.Controls.ComboBox comboBox) => (bool)comboBox.GetValue(EnabledProperty);
public static void SetEnabled(System.Windows.Controls.ComboBox comboBox, bool value) => comboBox.SetValue(EnabledProperty, value);
private static void OnEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var comboBox = (System.Windows.Controls.ComboBox)d;
if (GetEnabled(comboBox))
comboBox.PreviewMouseWheel += OnPreviewMouseWheel;
}
private static void OnPreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
var comboBox = (System.Windows.Controls.ComboBox)sender;
if (!GetEnabled(comboBox))
return;
if (comboBox.IsDropDownOpen)
return;
e.Handled = true;
}
}
}
How do I allow the parent UIElement
to scroll, while still preventing the ComboBox
from scrolling?
I was able to propagate this up using the following code
private static void OnPreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
var comboBox = (System.Windows.Controls.ComboBox)sender;
if (!GetEnabled(comboBox))
return;
if (comboBox.IsDropDownOpen)
return;
e.Handled = true;
var parentScrollViewer = comboBox.GetVisualParent<ScrollViewer>();
parentScrollViewer?.ScrollToVerticalOffset(parentScrollViewer.VerticalOffset - e.Delta * 0.4);
}
public static T GetVisualParent<T>(this DependencyObject child) where T : Visual
{
while ((child != null) && !(child is T))
{
child = VisualTreeHelper.GetParent(child);
}
return child as T;
}
Note: You may need to scale the e.Delta
(I required a scaling of 0.4
, but I am uncertain if this is the same everywhere)