WPF ListView Databound Drag / Drop Auto Scroll - PullRequest
       45

WPF ListView Databound Drag / Drop Auto Scroll

7 голосов
/ 18 февраля 2009

Я некоторое время работал с решением Беа здесь и нашел его очень полезным. Теперь у меня проблема, когда я перетаскиваю элементы внутри или в другой элемент управления 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», который имеет тип Picture в примере Bea, но это может измениться в зависимости от ObservableCollection, который вы привязали к ListView. Теперь я хочу перетащить 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 прокручиваться при перетаскивании по элементам ??

Спасибо!

Ответы [ 3 ]

2 голосов
/ 03 октября 2009

Я до сих пор бездельничаю с этой же проблемой. Я использую слегка модифицированную версию 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
2 голосов
/ 28 мая 2009

Я использовал метод ListBox.ScrollIntoView. По сути, когда вы обновляете свою цель удаления, вы можете просто вызвать этот метод, и wpf сделает всю работу. Все, что вам нужно знать, это индекс целевого предмета. Это обрабатывает как вертикальную, так и горизонтальную прокрутку.

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

Когда вы используете этот метод, ваш рекламодатель может двигаться с прокруткой ListBox. Чтобы это исправить, я просто установил в родительском слое adorner и родительском слое adorner содержимое окна в верхней части визуального дерева (т.е. topWindow.Content).

0 голосов
/ 02 февраля 2010

Другая возможность прокрутки - использовать ScrollBar-Commands. Вы можете сделать это, не спускаясь по VisualTree. Если у вас есть стили ListBox без рамки, метод GetScrollViewer () - больше не будет работать.

Я использую первый элемент ItemContainerGenerator в качестве CommandTarget для ScrollBar.LineXXXCommand:

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 похож на нажатие кнопок со стрелками на панели прокрутки: ScrollViewer прокручивается на определенную сумму, которую вы можете настроить, установив свойство «SmallAmount» на панели прокрутки.

...