Search code examples
c#wpfcombobox

C# - WPF - ComboBox - Prevent scrolling when hovering over a focused ComboBox (using an attached property)


Background

I need to prevent a ComboBox from scrolling when hovering over it (while it is focused) and scrolling using the mouse wheel.

In this circumstance I cannot use code behind, so I am using an attached property.

I just asked this question to adapt the answer from this question from code behind to attached property.

Code

Here is my xaml:

<ComboBox comboBox:NoScrollingBehaviour.Enabled="True"
          IsEditable="True" 
          IsTextSearchEnabled="True" 
          IsTextSearchCaseSensitive="False" 
          StaysOpenOnEdit="True"
          Text="{Binding MyTextProperty}"
          ItemsSource="{Binding DataContext.MySourceProperty, ElementName=MyElementName}"/>

Here is my code that comboBox:NoScrollingBehaviour links to:

public static class NoScrollingBehaviour
{
    public static bool GetEnabled(ComboBox comboBox) =>
        (bool)comboBox.GetValue(EnabledProperty);

    public static void SetEnabled(ComboBox comboBox, bool value) =>
        comboBox.SetValue(EnabledProperty, value);

    public static readonly DependencyProperty EnabledProperty =
        DependencyProperty.RegisterAttached(
        "Enabled",
        typeof(bool),
        typeof(NoScrollingBehaviour),
        new UIPropertyMetadata(false, OnEnabledChanged));

    private static void OnEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        ComboBox comboBox = (ComboBox)d;
        if (GetEnabled(comboBox))
        {
            FrameworkElementFactory stackPanel = new FrameworkElementFactory(typeof(StackPanel));
            stackPanel.AddHandler(FrameworkElement.RequestBringIntoViewEvent, new RequestBringIntoViewEventHandler(OnRequestBringIntoView));
            comboBox.ItemsPanel = new ItemsPanelTemplate() { VisualTree = stackPanel };
        }
    }

    private static void OnRequestBringIntoView(object sender, RequestBringIntoViewEventArgs e)
    {
        if (Keyboard.IsKeyDown(Key.Down) || Keyboard.IsKeyDown(Key.Up))
            return;

        e.Handled = true;
    }
}

What I have Tried

It only reaches OnRequestBringIntoView when clicking on the ComboBox, but not when scrolling with the mouse wheel.

I also tried adding in an event for MouseWheelEvent for stackPanel, but that never seems to get triggered.

I then tried adding in an event for MouseWheelEvent for comboBox, but it only gets triggered when scrolling using the mouse wheel when the ComboBox is not focused.

Question

How do I prevent the ComboBox from scrolling (with the mouse wheel) when it is focused?


Solution

  • If you simply want to disable scrolling using the mouse wheel, you could handle the PreviewMouseWheel event for the ComboBox itself in the attached behaviour:

    public static class NoScrollingBehaviour
    {
        public static bool GetEnabled(ComboBox comboBox) =>
            (bool)comboBox.GetValue(EnabledProperty);
    
        public static void SetEnabled(ComboBox comboBox, bool value) =>
            comboBox.SetValue(EnabledProperty, value);
    
        public static readonly DependencyProperty EnabledProperty =
            DependencyProperty.RegisterAttached(
            "Enabled",
            typeof(bool),
            typeof(NoScrollingBehaviour),
            new UIPropertyMetadata(false, OnEnabledChanged));
    
        private static void OnEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ComboBox comboBox = (ComboBox)d;
            if (GetEnabled(comboBox))
                comboBox.PreviewMouseWheel += OnPreviewMouseWheel;
        }
    
        private static void OnPreviewMouseWheel(object sender, MouseWheelEventArgs e)
        {
            e.Handled = true;
        }
    }