拖放时滚动(WPF)
Posted
技术标签:
【中文标题】拖放时滚动(WPF)【英文标题】:Scrolling while dragging and dropping (WPF) 【发布时间】:2012-05-30 19:21:11 【问题描述】:好的,伙计们,我一直在为这个问题抓狂,并且花了好几个小时试图研究它是如何工作的,但我还没有找到答案,如果你希望看到我的任何 SRC 随意问一下,我会看看我是否可以提供帮助。
基本上我遇到的问题是我的应用程序中有一个TreeView
文件夹,即:
Catalog
Brands
Nike
Adidas
Lactose
Styles
Sandles
Trainers
Boots
我要解决的问题是,当我拖动文件夹时(这在我的DragDropManager
类中处理),我无法向上或向下滚动(仅显示一个可爱的停止标志)。我实际上也无法在树视图中找到滚动条,所以我不确定它是如何生成的(这不是我自己的软件,我最近开始为一家公司工作,所以我不熟悉代码,也没有其他人好像知道了。)
如果我想将某些东西从最顶端移到最底端,这将是一个问题。
滚动无需拖动即可自行正常工作。
如果有人希望看到我的代码的任何部分,请随时询问,因为我不确定要向你们展示什么。
我已经阅读了好几篇文章,只是摸不着头脑。
【问题讨论】:
【参考方案1】:我已经创建了一个附加属性来实现这个行为,看看我的帖子在这里 -
Attached Behavior for auto scrolling containers while doing Drag & Drop
主要逻辑是这样的-
private static void OnContainerPreviewDragOver(object sender, DragEventArgs e)
FrameworkElement container = sender as FrameworkElement;
if (container == null) return;
ScrollViewer scrollViewer = GetFirstVisualChild<ScrollViewer>(container);
if (scrollViewer == null) return;
double tolerance = 60;
double verticalPos = e.GetPosition(container).Y;
double offset = 20;
if (verticalPos < tolerance) // Top of visible list?
//Scroll up
scrollViewer.ScrollToVerticalOffset(scrollViewer.VerticalOffset - offset);
else if (verticalPos > container.ActualHeight - tolerance) //Bottom of visible list?
//Scroll down
scrollViewer.ScrollToVerticalOffset(scrollViewer.VerticalOffset + offset);
关于 SO 的类似问题(虽然它们主要针对 ListBox
/ListView
,但也适用于 TreeView
)-
WPF Listbox auto scroll while dragging
WPF ListView Databound Drag/Drop Auto Scroll
WPF Drag-to-scroll doesn't work correctly
【讨论】:
我一直在尝试在我的列表框上使用它,但如果列表框中的项目无法拖放,它就不起作用。我在列表框中混合了项目,有些可以放下,有些不能。如果靠近顶部(或底部)的那些无法接收掉落,则不会激活滚动。有什么想法可以解决这个问题吗? @Lutz 这很有趣,从来没有遇到过这样的场景,所以不能多说。我可以想到 1. 在当前项目之间添加一些虚拟项目(高度小等,因此它们看起来不会奇怪或浪费空间),使它们可放置,以便始终调用 PreviewDragOver。但是您将不得不处理丢弃等。 2. 使所有项目可丢弃并在丢弃后处理验证。 3. 尝试查找是否为这些不可放置的项目触发了其他事件。 @nikotromus 你能详细说明什么不起作用吗?还有你的场景等等! @akjoshi - 我已经完全按照您的指定添加了您的代码。但是,当我将行 'WpfExtensions:DragDropExtension.ScrollOnDragDrop="True"' 添加到我的 ListView 时,它给了我以下智能错误:“名称 DragDropExtension 不存在于命名空间 'clr-namespace:WpfExtensions' ”跨度> 这个扩展也适用于 ScrollViewers。但是您必须将 ScrollViewer 包装在 Border 中,并将扩展名添加到边框而不是 ScrollViewer。【参考方案2】:我知道这个问题真的很老了,但这里是作为附加属性的 MVVM 方式:
using System.Windows;
using System.Windows.Controls;
namespace androidCtrlUI.XTools.Behaviors
///<summary>
/// TreeItemAttach
///<para/> TreeViewItem
///</summary>
public sealed class TreeItemAttach
#region BringIntoView
///<summary>
/// DependencyProperty
///</summary>
public static readonly DependencyProperty BringIntoViewProperty = DependencyProperty.RegisterAttached("BringIntoView", typeof(bool), typeof(TreeItemAttach), new UIPropertyMetadata(false, (s, e) =>
if ((bool)e.NewValue != (bool)e.OldValue && s is TreeViewItem t)
if ((bool)e.NewValue)
t.Selected += BringIntoView;
else
t.Selected -= BringIntoView;
));
///<summary>
/// Get
///</summary>
///<param name="target">DependencyObject</param>
///<returns>ICommand</returns>
public static bool GetBringIntoView(DependencyObject target)
return (bool)target.GetValue(BringIntoViewProperty);
///<summary>
/// Set
///</summary>
///<param name="target">DependencyObject</param>
///<param name="value">ICommand</param>
public static void SetBringIntoView(DependencyObject target, bool value)
target.SetValue(BringIntoViewProperty, value);
private static void BringIntoView(object sender, RoutedEventArgs e)
if (e.Source is TreeViewItem s)
double h = s.ActualHeight;
if (s.IsExpanded && s.Items.Count > 0)
h = s.ActualHeight / TreeWalker(s);
s.BringIntoView(new Rect(0, h * -1, s.ActualWidth, h * 2.5));
private static long TreeWalker(TreeViewItem item)
long c = item.Items.Count;
foreach (object i in item.Items)
if (i != null && item.ItemContainerGenerator.ContainerFromItem(i) is TreeViewItem t && t.IsExpanded && t.Items.Count > 0)
c += TreeWalker(t);
return c;
#endregion
它可以像这样使用:
<Style x:Key="TreeViewItemStyle" TargetType="x:Type TreeViewItem">
<Setter Property="tool:TreeItemAttach.BringIntoView" Value="True"/>
</Style>
【讨论】:
以上是关于拖放时滚动(WPF)的主要内容,如果未能解决你的问题,请参考以下文章