Task
My task was to be able to change the order of the service cards in the ListBox by dragging and dropping. I found a good solution on StackOverflow that has a lot of useful features (gong-wpf-drag drop, https://stackoverflow.com/a/33367826/19631476).
Problem
However, I had to face an unpleasant visual bug: when I drag the service card, there is some label that indicates where the dragged object will be moved. So, for some reason, this label is clipped if a number of objects are also clipped and not visible in the ListBox. However, when scrolling, the cropping does not disappear. Moreover, then the label will always point to the line above, wherever it is.
Problem demo
below I will present some screenshots demonstrating the problem
- the normal state of the separator
- the separator is cut off due to the fact that the card does not fit into the container
- the separator continues to be cut off after scrolling
- the separator is shifted up a line, and is still clipped, despite the fact that I move the elements already in another line
My code This is how my ListBox element looks like:
<ListBox
Margin="10 0 10 10"
Background="Cornsilk"
MinWidth="300"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
dd:DragDrop.IsDragSource="True"
dd:DragDrop.IsDropTarget="True"
dd:DragDrop.SelectDroppedItems="True"
ItemsSource="{Binding ServicesListCollectionView.View}"
SelectedIndex="{Binding SelectedServiceIndex}"
SelectedItem="{Binding SelectedService}"
d:ItemsSource="{d:SampleData ItemCount=5}">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Border AllowDrop="True" Style="{StaticResource BorderStyle}">
<DockPanel Background="GhostWhite">
<!-- Service Card Template-->
</DockPanel>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
it contains a custom container so that the service cards can be arranged as a grid from top to bottom
What have I tried to do?
The idea came to my mind to prohibit the use of ScrollBar for the ListBox element. It worked, and the visual bug sort of disappeared. But you can't leave it like that. I wrapped the ListBox in ScrollViewer and allowed it to scroll vertically. This visual bug is no longer there:
code:
<ScrollViewer VerticalScrollBarVisibility="Auto" x:Name="ServiceScroll">
<!-- Here is ListBox -->
</ScrollViewer>
However, this solution is not suitable:
- I lose control of scrolling in the ListBox and can only use scrolling on the ScrollViewer itself
- Scrolling also becomes unavailable when dragging items.
the second problem can be solved by specifying the dd:DragDrop.DropTargetScrollViewer
ScrollViewer with binding to the ScrollViewer element:
<ScrollViewer VerticalScrollBarVisibility="Auto" x:Name="ServiceScroll">
<ListBox
...
dd:DragDrop.IsDragSource="True"
dd:DragDrop.IsDropTarget="True"
dd:DragDrop.SelectDroppedItems="True"
dd:DragDrop.DropTargetScrollViewer="{Binding ElementName=ServiceScroll}"
...
></ListBox>
</ScrollViewer>
but in this case, the visual bug described above appears again, and also, this solution still does not allow you to scroll through the elements inside the ListBox using the mouse wheel.
Any ideas?
To be honest, I do not know what to do. Has anyone encountered anything described above? Maybe I'm doing something wrong, which is why I get such strange behavior? What's wrong with scrolling? Maybe you have good solutions to solve the problem? How else would it be possible to solve the issue of dragging items to the ListBox in the most flexible way?