2009-02-18 1 views
7

Я работаю с решением Bea here и нахожу его очень полезным. Проблема теперь у меня есть, когда я перетаскиваю элементы в пределах или в другой элемент управления ListView, и я хочу прокручивать вверх/вниз «во время» перетаскивания (перемещение элемента из индекса 30 в индекс 1), этого не происходит. Мне нужно было бы перетащить на верхние части визуальных элементов в ListView, вручную прокрутить вверх, а затем снова перетащить, в конечном итоге оканчиваясь на нужную мне позицию. Это не очень удобно.WPF ListView Databound Перетаскивание Auto Scroll

Теперь я нашел функцию (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 для прокрутки при перемещении по элементам ??

Спасибо!

+0

Hi, Вы нашли решение? Cheers –

+0

Извините, я до сих пор не успел заглянуть в это. Вы столкнулись с чем-то с тех пор, как вы отправили? – ScottN

ответ

2

Я все еще общаюсь с этой же проблемой. Я использую слегка измененную версию Bea's 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 упоминалось выше, с Adorner перемещения, и в духе делать это легко для кого-то позже, я добавил переменную класса 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 
+0

Я, наконец, добрался до реализации этого и протестировал его очень быстро. Выглядит отлично! Работал отлично! Благодаря! – ScottN

+0

Я нашел одну проблему, хотя я использовал двойной щелчок по списку в качестве альтернативы перетаскиванию элементов между двумя элементами управления. Используя описанный выше метод, у него возникли проблемы с обнаружением одного клика между двойным щелчком, а в исходном списке был добавлен элемент, который я только что удалил. Поэтому в функции мыши я добавил «If e.Clicks = 1 Then Do Drag Else Set DraggedData = Nothing», это должно исправить. – ScottN

2

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

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

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

+1

Я дам эту попытку, спасибо за сообщение 3 месяца спустя :) Я думал, что это было забыто о .. – ScottN

+0

спасибо! Я сделал это аналогично lstMessages.ScrollIntoView (lstMessages.Items [lstMessages.Items.Count-1]); –

0

Другая возможность прокрутки является использование ScrollBar-команд. Вы можете сделать это, не спустившись вниз по 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 является похоже на щелкая стреловидные кнопки в ScrollBar: The scrolles ScrollViewer по определенной сумме, которая вы можете настроить, установив свойство «SmallAmount» для ScrollBar.