Search code examples
c#wpfcombobox

WPF - ComboBox - Prevent Scrolling - WIthout using Code Behind


Issue

I need to prevent scrolling through the ComboBox selected items when the mouse hovers over the closed ComboBox.

I have seen this done using code behind (e.g. this), but I need to do it without code behind, in a way that could be easily reused throughout the project.

For example, elsewhere in our project we use IValueConverter to do make a StaticResource that can easily be added where required.

Question

Is there a way to make a StaticResource for the ComboBox that could prevent scrolling?

Is there an interface like IValueConveter that could be used in place of the EventSetter Handler?


Solution

  • but I need to do it without code behind, in a way that could be easily reused throughout the project.

    So wrap the code-behind functionality in an 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))
            {
                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;
        }
    }
    

    You can then easily reuse it for different ComboBox elements:

    <ComboBox local:NoScrollingBehaviour.Enabled="true" />