WPF ListView Databound Drag/Drop Auto Scroll

后端 未结 3 670
轻奢々
轻奢々 2021-02-06 09:03

I\'ve been working with Bea\'s solution here for a while and finding it very helpful. Problem now I\'m having is when I drag-n-drop items within or to another ListView control

相关标签:
3条回答
  • 2021-02-06 09:46

    Another possibility to scroll is to use the ScrollBar-Commands. You can do this without climbing down the VisualTree. If you have a styles ListBox with no border the GetScrollViewer()-Method would not work anymore.

    I use the first Element of the ItemContainerGenerator as CommandTarget for the 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);
      }
    

    Calling the LineXXXCommands is similiar to clicking the Arrow-Buttons of a ScrollBar: The ScrollViewer scrolles by a certain ammount which you can configure by setting the 'SmallAmount' Property of the ScrollBar.

    0 讨论(0)
  • 2021-02-06 09:58

    What I did was took advantage of the ListBox.ScrollIntoView method. Basically, when you update your drop target, you can just call this method on it and wpf will do all the work. All you need to know is the index of the drop target item. This handles both vertical and horizontal scrolling.

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

    When you use this method, your adorner might move with the scrolling ListBox. To fix this, I just set my adorner parent and adorner layer parent to the content of the window at the top of the visual tree (i.e. topWindow.Content).

    0 讨论(0)
  • 2021-02-06 10:05

    I'm still messing around with this exact same issue too. I'm using a slightly modified version of Bea's Drag and Drop found here, which is in VB instead of C#. When I used ScrollIntoView as described above, I could scroll down but not up. So I messed around and came up with this as my 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
    

    and I had to include this utility function, taken from 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
    

    which is great and all. Then running out what theuberk mentioned above with the adorner moving, and in the spirit of making this easy for someone else later, I added a variable to the DragDropAdorner class:

        Private m_mouseDelta As Point
    

    Added this to the last line of DragSource_PreviewMouseLeftButtonDown:

            Me.m_mouseDelta = e.GetPosition(m_sourceItemContainer)
    

    And turned ShowDraggedAdorner into:

        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
    
    0 讨论(0)
提交回复
热议问题