我一直在使用Bea的解决方案here一段时间,并发现它非常有用。现在我遇到的问题是,当我将项目拖放到另一个ListView控件中时,我想在拖动期间向上/向下滚动(将项目从索引30移动到索引1),它不会发生。我必须拖动到ListView中的可视项目的顶部,手动向上滚动,然后再次拖动,最终在我想要的位置结束。这不是非常用户友好。
现在我找到了一个函数(DragDropHelper.DropTarget_PreviewDragOver),我想要测试哪个项目被拖过来,我就是这样。
Dim pt As Point = e.GetPosition(DirectCast(Me.targetItemsControl, UIElement))
' Perform the hit test against a given portion of the visual object tree.
Dim result As HitTestResult = VisualTreeHelper.HitTest(Me.targetItemsControl, pt)
现在我可以从那里获得此视觉命中的DependencyProperty
Dim lvi As ListViewItem = TryCast(GetDependencyObjectFromVisualTree(TryCast(result.VisualHit, DependencyObject), GetType(ListViewItem)), ListViewItem)
哪个是ListViewItem。现在在函数DropTarget_PreviewDragOver中,我有“DraggedItem”,它在Bea的示例中是Picture类型,但是这可以根据你绑定到ListView的ObservableCollection而改变。现在,我想根据鼠标在控件上的位置向上或向下拖动ListView。我尝试使用下面未完成的非工作代码
If lvi IsNot Nothing Then
If pt.Y <= 25 Then
Dim lv As ListView = TryCast(targetItemsControl, ListView)
If lv IsNot Nothing Then
Dim index As Integer = lv.Items.IndexOf(lvi)
If index > 1 Then
lv.ScrollIntoView(lv.Items(index - 1))
End If
End If
Else
If pt.Y >= Me.targetItemsControl.ActualHeight - 25 Then
Debug.Print("Scroll Down")
End If
End If
End If
有人能指出我正确的方向让这个ItemsControl或ListView在拖动项目时滚动吗?
谢谢!
答案 0 :(得分:2)
我所做的是利用了ListBox.ScrollIntoView
方法。基本上,当您更新放置目标时,您可以在其上调用此方法,并且wpf将完成所有工作。您需要知道的只是放置目标项的索引。这可以处理垂直和水平滚动。
this.listView.ScrollIntoView(this.listView.Items[index]);
使用此方法时,您的装饰器可能会随着滚动ListBox一起移动。要解决此问题,我只需将我的装饰父级和装配体图层父级设置为可视树顶部窗口的内容(即topWindow.Content
)。
答案 1 :(得分:2)
我仍然在解决同样的问题。我正在使用稍微修改过的Bea的Drag and Drop版本here,它在VB而不是C#中。当我如上所述使用ScrollIntoView时,我可以向下滚动但不能向上滚动。所以我搞砸了,想出了我的DropTarget_PreviewDragOver:
Private Sub DropTarget_PreviewDragOver(ByVal sender As Object, ByVal e As DragEventArgs)
Dim draggedItem As Object = e.Data.GetData(Me.m_format.Name)
Me.DecideDropTarget(e)
If (Not draggedItem Is Nothing) Then
If (TypeOf m_targetItemsControl Is ListBox) Then
Dim lb As ListBox = CType(m_targetItemsControl, ListBox)
Dim temp As Integer = m_insertionIndex
Dim scroll As ScrollViewer = Utilities.GetScrollViewer(lb)
If scroll.VerticalOffset = temp Then
temp -= 1
End If
If temp >= 0 And temp <= (lb.Items.Count - 1) Then
lb.ScrollIntoView(lb.Items(temp))
End If
End If
Me.ShowDraggedAdorner(e.GetPosition(Me.m_topWindow))
Me.UpdateInsertionAdornerPosition()
End If
e.Handled = True
End Sub
我必须包含此实用程序功能,取自here
Public Shared Function GetScrollViewer(ByVal listBox As ListBox)
Dim scroll_border As Decorator = CType(VisualTreeHelper.GetChild(listBox, 0), Decorator)
If (TypeOf scroll_border Is Decorator) Then
Dim scroll As ScrollViewer = CType(scroll_border.Child, ScrollViewer)
If (TypeOf scroll Is ScrollViewer) Then
Return scroll
Else
Return Nothing
End If
Else
Return Nothing
End If
End Function
这是伟大的。然后在装饰者移动的情况下用尽上面提到的theuberk,并且为了让其他人以后容易这样做,我在DragDropAdorner类中添加了一个变量:
Private m_mouseDelta As Point
将此添加到DragSource_PreviewMouseLeftButtonDown的最后一行:
Me.m_mouseDelta = e.GetPosition(m_sourceItemContainer)
将ShowDraggedAdorner变为:
Private Sub ShowDraggedAdorner(ByVal currentPosition As Point)
If (Me.m_draggedAdorner Is Nothing) Then
Dim adornerLayer As AdornerLayer = adornerLayer.GetAdornerLayer(Me.m_topWindow.Content)
Me.m_draggedAdorner = New DraggedAdorner(Me.m_draggedData, DragDropBehavior.GetDragTemplate(Me.m_sourceItemsControl), m_topWindow.Content, adornerLayer)
End If
Me.m_draggedAdorner.SetPosition((currentPosition.X - m_mouseDelta.X), (currentPosition.Y - m_mouseDelta.Y))
End Sub
答案 2 :(得分:0)
滚动的另一种可能性是使用ScrollBar-Commands。您可以在不降低VisualTree的情况下执行此操作。如果你有一个没有边框的样式ListBox,GetScrollViewer() - 方法就不再有用了。
我使用ItemContainerGenerator的第一个元素作为ScrollBar.LineXXXCommand的CommandTarget:
Point p = e.GetPosition(itemsControl);
IInputElement commandTarget = itemsControl.ItemContainerGenerator.ContainerFromIndex(0) as IInputElement;
if (commandTarget != null)
{
if (p.Y < OFFSET_TO_SCROLL)
ScrollBar.LineUpCommand.Execute(null, commandTarget);
else if (p.Y > itemsControl.ActualHeight - OFFSET_TO_SCROLL)
ScrollBar.LineDownCommand.Execute(null, commandTarget);
if (p.X < OFFSET_TO_SCROLL)
ScrollBar.LineLeftCommand.Execute(null, commandTarget);
else if (p.X > itemsControl.ActualWidth - OFFSET_TO_SCROLL)
ScrollBar.LineRightCommand.Execute(null, commandTarget);
}
调用LineXXXCommands类似于单击ScrollBar的箭头按钮:ScrollViewer按某个ammount滚动,您可以通过设置ScrollBar的'SmallAmount'属性来配置。