7

我在这里使用 Bea 的解决方案已经有一段时间了,发现它很有帮助。现在我遇到的问题是,当我在另一个 ListView 控件内或向另一个 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 滚动的正确方向吗?

谢谢!

4

3 回答 3

2

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

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

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

于 2009-05-28T16:32:41.080 回答
2

我还在纠结这个完全相同的问题。我使用的是 Bea's 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

这是伟大的。然后在装饰器移动的情况下运行上面提到的 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
于 2009-10-02T22:25:45.483 回答
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 滚动一定量,您可以通过设置 ScrollBar 的“SmallAmount”属性来配置该量。

于 2010-02-02T16:32:36.983 回答