借鉴地址:http://matthamilton.net/touchscrolling-for-scrollviewer
改造后支持上下和左右鼠标拖动滚动:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Input; namespace TestTouchScroll { public class TouchScrolling : DependencyObject { public static bool GetIsEnabled(DependencyObject obj) { return (bool)obj.GetValue(IsEnabledProperty); } public static void SetIsEnabled(DependencyObject obj, bool value) { obj.SetValue(IsEnabledProperty, value); } public bool IsEnabled { get { return (bool)GetValue(IsEnabledProperty); } set { SetValue(IsEnabledProperty, value); } } public static readonly DependencyProperty IsEnabledProperty = DependencyProperty.RegisterAttached("IsEnabled", typeof(bool), typeof(TouchScrolling), new UIPropertyMetadata(false, IsEnabledChanged)); static Dictionary<object, MouseCapture> _captures = new Dictionary<object, MouseCapture>(); static void IsEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var target = d as ScrollViewer; if (target == null) return; if ((bool)e.NewValue) { target.Loaded += target_Loaded; } else { target_Unloaded(target, new RoutedEventArgs()); } } static void target_Unloaded(object sender, RoutedEventArgs e) { System.Diagnostics.Debug.WriteLine("Target Unloaded"); var target = sender as ScrollViewer; if (target == null) return; _captures.Remove(sender); target.Loaded -= target_Loaded; target.Unloaded -= target_Unloaded; target.PreviewMouseLeftButtonDown -= target_PreviewMouseLeftButtonDown; target.PreviewMouseMove -= target_PreviewMouseMove; target.PreviewMouseLeftButtonUp -= target_PreviewMouseLeftButtonUp; } static void target_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e) { var target = sender as ScrollViewer; if (target == null) return; _captures[sender] = new MouseCapture { VerticalOffset = target.VerticalOffset, HorticalOffset = target.HorizontalOffset, Point = e.GetPosition(target), }; } static void target_Loaded(object sender, RoutedEventArgs e) { var target = sender as ScrollViewer; if (target == null) return; System.Diagnostics.Debug.WriteLine("Target Loaded"); target.Unloaded += target_Unloaded; target.PreviewMouseLeftButtonDown += target_PreviewMouseLeftButtonDown; target.PreviewMouseMove += target_PreviewMouseMove; target.PreviewMouseLeftButtonUp += target_PreviewMouseLeftButtonUp; } static void target_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e) { var target = sender as ScrollViewer; if (target == null) return; target.ReleaseMouseCapture(); } static void target_PreviewMouseMove(object sender, MouseEventArgs e) { if (!_captures.ContainsKey(sender)) return; if (e.LeftButton != MouseButtonState.Pressed) { _captures.Remove(sender); return; } var target = sender as ScrollViewer; if (target == null) return; var capture = _captures[sender]; var point = e.GetPosition(target); var dy = point.Y - capture.Point.Y; var dx = point.X - capture.Point.X; if (Math.Abs(dy) > 5) { target.CaptureMouse(); } if (Math.Abs(dx) > 5) { target.CaptureMouse(); } target.ScrollToVerticalOffset(capture.VerticalOffset - dy); target.ScrollToHorizontalOffset(capture.HorticalOffset - dx); } internal class MouseCapture { public Double VerticalOffset { get; set; } public Double HorticalOffset { get; set; } public Point Point { get; set; } } } }
UI:
<Window x:Class="TestTouchScroll.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:my="clr-namespace:TestTouchScroll" Title="MainWindow" Height="410" Width="888"> <Grid> <ScrollViewer my:TouchScrolling.IsEnabled="True" HorizontalAlignment="Right" Width="351"> <StackPanel> <Button Height="120" Margin="12" Click="Button_Click">hello wgscd</Button> <Button Height="120" Margin="12" Click="Button_Click">hello wgscd</Button> <Button Height="120" Margin="12" Click="Button_Click">hello wgscd</Button> <Button Height="120" Margin="12" Click="Button_Click">hello wgscd</Button> <Button Height="120" Margin="12" Click="Button_Click">hello wgscd</Button> <Button Height="120" Margin="12" Click="Button_Click">hello wgscd</Button> <Button Height="120" Margin="12" Click="Button_Click">hello wgscd</Button> </StackPanel> </ScrollViewer> <ScrollViewer my:TouchScrolling.IsEnabled="True" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Disabled" HorizontalAlignment="Left" Width="458" Background="#FFEBEBEB"> <StackPanel Orientation="Horizontal" > <Button Height="328" Width="182" Margin="12" Click="Button_Click">hello wgscd</Button> <Button Height="328" Width="182" Margin="12" Click="Button_Click">hello wgscd</Button> <Button Height="328" Width="182" Margin="12" Click="Button_Click">hello wgscd</Button> <Button Height="328" Width="182" Margin="12" Click="Button_Click">hello wgscd</Button> <Button Height="328" Width="182" Margin="12" Click="Button_Click">hello wgscd</Button> <Button Height="328" Width="182" Margin="12" Click="Button_Click">hello wgscd</Button> <Button Height="328" Width="182" Margin="12" Click="Button_Click">hello wgscd</Button> </StackPanel> </ScrollViewer> </Grid> </Window>
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; namespace TestTouchScroll { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private void Button_Click(object sender, RoutedEventArgs e) { MessageBox.Show("hello"); } } }