2013-02-08 70 views
2

我想,讓點擊滾動使用拖放滾動ScrollViewer(即點擊ScrollViewer任何地方,上下拖動,這將相應地滾動)單擊並拖動使用的ScrollViewer

我有一個StackPanel嵌套一個ScrollViewer和我已經有滾動工作。我相信我在某個地方看到了答案,但我似乎無法再找到答案。

這隻能使用代碼來完成。

回答

5

this code from Matt Hamilton

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, 
      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; 
     if (Math.Abs(dy) > 5) 
     { 
      target.CaptureMouse(); 
     } 

     target.ScrollToVerticalOffset(capture.VerticalOffset - dy); 
    } 

    internal class MouseCapture 
    { 
     public Double VerticalOffset { get; set; } 
     public Point Point { get; set; } 
    } 

}

這裏有一些怪癖。我注意到ScrollViewer實際上是在顯示內容時被加載,卸載並重新加載的。

這意味着我不能只將IsEnabledChanged方法中的事件掛起,並在target_Unloaded事件處理程序中將它們解除掛鉤,因爲它們正被立即取消掛鉤。相反,我不得不將它們連接到Loaded事件的處理程序中,而該事件又永遠不會脫鉤。

這意味着在那裏存在某種「內存泄漏」,但這是我準備好要忍受的一種。

+0

它導致內存泄漏,任何人都有更好的? – digz6666 2013-06-03 02:04:39