使用 ScrollViewer 单击并拖动滚动 [英] Click and drag scrolling using ScrollViewer
问题描述
我想允许使用 ScrollViewer
进行点击和拖动滚动(即点击 ScrollViewer
中的任意位置并向上或向下拖动,它会相应地滚动)>
我有一个 StackPanel
嵌套在 ScrollViewer
中,并且我已经可以进行滚动了.我相信我在某处看到过那个答案,但我似乎再也找不到了.
这只能使用代码来完成.
public class TouchScrolling : DependencyObject{public static bool GetIsEnabled(DependencyObject obj){返回(布尔)obj.GetValue(IsEnabledProperty);}public static void SetIsEnabled(DependencyObject obj, bool value){obj.SetValue(IsEnabledProperty, value);}公共布尔值已启用{获取{返回(布尔)GetValue(IsEnabledProperty);}set { SetValue(IsEnabledProperty, value);}}public static readonly DependencyProperty IsEnabledProperty =DependencyProperty.RegisterAttached("IsEnabled", typeof(bool), typeof(TouchScrolling), new UIPropertyMetadata(false, IsEnabledChanged));静态字典<对象,MouseCapture>_captures = new Dictionary
}
这里有一些怪癖.我注意到在显示内容时实际上正在加载、卸载和再次加载 ScrollViewer.
这意味着我不能只在 IsEnabledChanged
方法中连接事件并在 target_Unloaded
事件处理程序中取消它们,因为它们会立即被取消.相反,我不得不将它们挂接到 Loaded 事件的处理程序中,而后者永远不会解开.
这意味着存在某种内存泄漏",但我已准备好接受它.
I would like to allow click and drag scrolling using a ScrollViewer
(i.e. click anywhere in the ScrollViewer
and drag up or down, and it will scroll accordingly)
I have a StackPanel
nested inside a ScrollViewer
and I already have the scrolling working. I believe I saw that answer somewhere, but I can't seem to find it anymore.
This has to be done using code only.
Look at 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; }
}
}
There are some quirks here. I noticed that the ScrollViewer was actually being loaded, unloaded and loaded again when the content was shown.
That meant that I couldn't just hook up the events in the IsEnabledChanged
method and unhook them in the target_Unloaded
event handler, because they were being unhooked immediately. Instead, I've had to hook them up in a handler for the Loaded event, which in turn never gets unhooked.
That means that there's something of a "memory leak" in there, but it's one I'm prepared to live with.
这篇关于使用 ScrollViewer 单击并拖动滚动的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!