WPF ListView数据绑定拖放自动滚动



data-binding collections (2)

我一直在和Bea的解决方案工作一段时间,发现它非常有帮助。 现在我遇到的问题是,当我拖放项目内或另一个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的例子中的图片类型,但这可以改变,取决于你绑定到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滚动时拖动项目?

谢谢!

https://src-bin.com


Answer #1

我所做的就是利用ListBox.ScrollIntoView方法。 基本上,当你更新你的放置目标时,你可以调用这个方法,wpf将完成所有的工作。 所有你需要知道的是放置目标项目的索引。 这处理垂直和水平滚动。

this.listView.ScrollIntoView(this.listView.Items[index]);

当你使用这个方法时,你的装饰器可能会移动滚动的ListBox。 为了解决这个问题,我只是将我的装饰父母和装饰图层父母设置为可视树顶部的窗口内容(即topWindow.Content )。


Answer #2

我还在搞这个完全相同的问题。 我正在使用稍微修改过的Bea的Drag and Drop版本, 这里是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

我不得不包含这个从这里取得的效用函数

    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

这是伟大的一切。 然后用装饰器移动上面提到的东西,并且在稍后让其他人变得容易的精神,我在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




drag-and-drop