Mouse scroll not working in a scroll viewer with a wpf datagrid and additional UI elements

前端 未结 10 1392
醉话见心
醉话见心 2021-02-03 18:41

I am trying to figure out how to get the mouse scroll working on a wpf window with a scrollviewer and a datagrid within it. The WPF and C# code is below



        
10条回答
  •  时光说笑
    2021-02-03 18:43

    Here is a larger example of creating a WPF behavior that scrolls the DataGrid.

    First define the following base class for gluing together framework element with behavior class and its behavior implementation.

    using System.Diagnostics.CodeAnalysis;
    using System.Windows;
    using System.Windows.Input;
    
    namespace SomeAcme.Client.Infrastructure
    {
    
    
        /// 
        /// Behavior handler class for creating WPF behaviors.
        ///   
         [ExcludeFromCodeCoverage] 
        public class BehaviorHandler 
            where TAssociatedObject: DependencyObject
            where TBehaviorClass : class, IAssociationBehavior, new()
        {
    
            public BehaviorHandler()
            {
            }
    
            public static TBehaviorClass GetBehavior(DependencyObject obj)
            {
                if (obj == null)
                    return null; 
    
                return (TBehaviorClass)obj.GetValue(BehaviorProperty);
            }
    
            public static void SetBehavior(DependencyObject obj, TBehaviorClass value)
            {
                if (obj != null)
                {
                    obj.SetValue(BehaviorProperty, value);
                }
            }
    
            // Using a DependencyProperty as the backing store for Behavior.  This enables animation, styling, binding, etc...
            public static readonly DependencyProperty BehaviorProperty =
                DependencyProperty.RegisterAttached("Behavior", typeof(TBehaviorClass), typeof(object), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.Inherits));
    
    
            public void FindOrCreateBehaviorOnDemand(DependencyObject dependencyObject)
            {
                 //Apply the behavior 
                 TBehaviorClass behavior = FindOrCreateBehavior(dependencyObject);
                 if (behavior != null)
                 {
                     dependencyObject.SetValue(BehaviorProperty, behavior); 
                 }
            }
    
            public TBehaviorClass FindOrCreateBehavior(DependencyObject dependencyObject)
            {
                if (dependencyObject == null)
                    return null;
                var associatedObject = dependencyObject;
                if (associatedObject == null)
                    return null;
                var behavior = dependencyObject.GetValue(BehaviorProperty) as TBehaviorClass;
                if (behavior == null)
                {
                    var behaviorAssociated = new TBehaviorClass();
                    if (behaviorAssociated == null)
                        return null;
                    behaviorAssociated.InitializeAssociation(associatedObject, AssociatedCommands);
                    return behaviorAssociated;
                }
                else
                {
                    return behavior;
                }
            } //TBehaviorClass FindOrCreateBehavior 
    
            /// 
            /// Set the associated commands to pass into the WPF behavior, if desired
            /// 
            public ICommand[] AssociatedCommands { get; set; }
    
        }
    
    }
    

    This looks a bit more complex, but it simplifies boiler plate coding when it comes to gluing together the behavior class with the framework element. In this particular case we will not need to use an associated command.

    Our scroll viewer behavior then looks like this:

        using SomeAcme.Client.Infrastructure;
        using System.Windows;
        using System.Windows.Controls;
        using System.Windows.Input;
    
        namespace SomeAcme.Client.Infrastructure
        {
    
            public static class ScrollViewerMouseWheelScrollBehavior
            {
    
    
                    public static string GetUseMouseScrollForScrollViewer(DependencyObject obj)
                    {
                        if (obj != null)
                        {
                            return (string)obj.GetValue(UseMouseScrollForScrollViewerProperty);
                        }
                        else
                            return null;
                    }
    
                    public static void SetUseMouseScrollForScrollViewer(DependencyObject obj, string value)
                    {
                        if (obj != null)
                        {
                            obj.SetValue(UseMouseScrollForScrollViewerProperty, value);
                        }
                    }
    
    
     public static readonly DependencyProperty UseMouseScrollForScrollViewerCommandProperty =
                        DependencyProperty.RegisterAttached("UseScrollForScrollViewer", typeof(string), typeof(ScrollViewerMouseWheelScrollBehavior),
                            new PropertyMetadata(new PropertyChangedCallback(OnUseScrollForScrollViewerSet)));
    
                    public static void OnUseScrollForScrollViewerSet(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs eventArgs)
                    {
                        bool useScroll;
                        bool.TryParse(eventArgs.NewValue?.ToString(), out useScroll);
                        if (useScroll)
                        {
                            var behaviorHandler =
                                new BehaviorHandler();
                            //behaviorHandler.AssociatedCommands = 
                            //    new Microsoft.Practices.Prism.Commands.DelegateCommand[] { (Microsoft.Practices.Prism.Commands.DelegateCommand)eventArgs.NewValue };
                            behaviorHandler.FindOrCreateBehaviorOnDemand(dependencyObject);
                        }
                    }
    
                }
    
        }
    
        namespace SomeAcme.Client.Infrastructure
        {
            public class ScrollViewerMouseScrollBehaviorImplementation : IAssociationBehavior
            {
                public void InitializeAssociation(DependencyObject associatedObject, params ICommand[] commands)
                {
                    //TODO: Add commands to associate
                    var scrollViewer = associatedObject as ScrollViewer;
                    if (scrollViewer != null)
                    {
                        scrollViewer.PreviewMouseWheel += ScrollViewer_PreviewMouseWheel;
                    }
                }
    
                private void ScrollViewer_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
                {
                    var scrollViewer = sender as ScrollViewer;
                    if (scrollViewer != null)
                    {
                        scrollViewer.ScrollToVerticalOffset(scrollViewer.VerticalOffset - e.Delta);
                    }
                }
            }
        }
    
    
    

    In XAML we then can first define the namespaces:

    xmlns:local="clr-namespace:SomeAcme.Client.Infrastructure"
    xmlns:sys="clr-namespace:System;assembly=mscorlib"
    

    Finally we are ready to use the mouse wheel scroll by using the WPF behavior in the XAML.

    ..

     
            
                
                    
                        
                            
    

    I have tested and verified that this approach works. For developers working with a WPF app, utilizing WPF behaviors keeps amount of code in code behind still to the minimum bits and staying faitfully to the MVVM approach.

    提交回复
    热议问题