Search code examples
c#wpfcomboboxmousewheel

wpf combobox how to handle PreviewMouseWheel


I want to add a handler for the MouseWheel to the ComboBox, but I don't know how.

The reason is that I have scrolling problems with a ComboBox inside DataGrid inside ScrollViewer, see here, and I would like to experiment. I already have code to handle the MouseWheel for the ScrollViewer, and for the DataGrid, but not yet for the ComboBox.

<ComboBox PreviewMouseWheel="theComboBox_PreviewMouseWheel"

code behind:

    private void theScrollViewer_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
    {
        if (sender is ScrollViewer scrollView)
        {
            scrollView.UpdateLayout();
            scrollView.ScrollToVerticalOffset(scrollView.VerticalOffset - e.Delta);
            e.Handled = true;
        }            
    }

    private void theDataGrid_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
    {
        var args = new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta);
        args.RoutedEvent = ScrollViewer.MouseWheelEvent;
        theScrollViewer.RaiseEvent(args);
    }

    /// <summary>
    /// The hypothetical scroll event handler, on the ComboBox,
    /// to make the ComboBox scrollable
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void theComboBox_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
    {
        if (sender is ComboBox cb)
        {
            var args = new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta);
            args.RoutedEvent = ScrollViewer.MouseWheelEvent;
            //cb.ItemsPanel.RaiseEvents(args);//cb has no such property
            //cb.ScrollToVerticalOffset(cb.VerticalOffset - e.Delta);//cb has no such property
            //e.Handled = true;
        }
    }

Solution

  • You can get a reference to the ComboBox's internal ScrollViewer using the VisualTreeHelper class and then access its properties and methods to set the offset:

    private void theComboBox_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
    {
        if (sender is ComboBox cb && e.OriginalSource is DependencyObject depObj)
        {
            ScrollViewer scrollViewer = FindParent<ScrollViewer>(depObj);
            ...
        }
    }
    
    private static T FindParent<T>(DependencyObject dependencyObject) where T : DependencyObject
    {
        var parent = VisualTreeHelper.GetParent(dependencyObject);
        if (parent == null)
            return null;
    
        var parentT = parent as T;
        return parentT ?? FindParent<T>(parent);
    }