Hello Bernard,
It is still "work in progress" and I think it can be better optimised, but I believe I have working solution. It is not perfect (strange things happen when SfListView is scrolled during item dragging. It works fine, but empty space appears in other locations. I guess it is connected with cell reusing). Below, I will copy my current solution, if you need more info, let me know.
Regards,
Radek
Code behind:
view constructor:
SfListView.DragDropController = new CustomDragDropController(SfListView) {UpdateSource = false};
others:
private async void SfListView_OnItemDragging(object sender, ItemDraggingEventArgs e)
{
var draggedItem = e.ItemData as PersonViewModel;
var element = FindViewByBindingContext(draggedItem);
switch (e.Action)
{
case DragAction.Start:
{
_startPositionY = e.Position.Y;
var grid = GetGrid(element as ListViewItem);
_ = grid.ChangeBackgroundColorTo(Color.FromRgba(0x51, 0x33, 0x47, 0x80), 160, Easing.SinOut);
break;
}
case DragAction.Dragging:
{
var dropTarget = FindCurrentTarget(element);
ClearTargetsBackground(dropTarget, element);
if (dropTarget != null && dropTarget != element)
{
MarkTargetBackground(dropTarget);
}
else
{
_previousDropTarget = dropTarget;
}
break;
}
case DragAction.Drop:
{
var dropTarget = FindCurrentTarget(element);
e.Cancel = true;
var grid = GetGrid(element as ListViewItem);
grid.BackgroundColor = Color.Transparent;
ClearTargetsBackground(null);
if (dropTarget is null || dropTarget == element)
{
return;
}
var source = (PersonViewModel) e.ItemData;
var destination = (PersonViewModel) dropTarget.BindingContext;
var vm = (SplitPageViewModel) BindingContext;
vm.Split.Link(source, destination);
await Task.Delay(100);
SfListView.RefreshView();
break;
}
}
}
private Grid GetGrid(ListViewItem listViewItem)
{
var grid = (Grid)listViewItem.Content;
return grid;
}
private VisualElement FindViewByBindingContext(object bindingContext)
{
var elements = ((VisualContainer)((ScrollView)SfListView.Children[0]).Children[0]).Children;
var rows = elements.Where(element => element is ListViewItem item).ToList();
VisualElement result = null;
foreach (var row in rows)
{
if (row.BindingContext == bindingContext)
{
result = row;
break;
}
}
return result;
}
private View FindCurrentTarget(VisualElement element)
{
var coordinates = _platformLocation.GetCoordinates(element);
coordinates.X += (float)element.Width / 2.0f;
coordinates.Y += (float)element.Height / 2.0f;
var dropList = ((VisualContainer)((ScrollView)SfListView.Children[0]).Children[0]).Children;
foreach (var view in dropList)
{
if(view.BindingContext is null)
{
continue;
}
var item = (ListViewItem)view;
var targetCoordinates = _platformLocation.GetCoordinates(item);
if (
coordinates.Y >= targetCoordinates.Y &&
coordinates.Y <= targetCoordinates.Y + item.Content.Height &&
coordinates.X >= targetCoordinates.X &&
coordinates.X <= targetCoordinates.X + item.Content.Width)
{
return item;
}
}
return null;
}
XAML:
customSyncfusion:CustomSfListView x:Name="SfListView"
SelectionMode="None"
DragStartMode="OnHold"
ItemDragging="SfListView_OnItemDragging"/>
others:
public class CustomSfListView : SfListView
{
protected override bool ShouldInvalidateOnChildRemoved(View child)
{
return true;
}
protected override bool ShouldInvalidateOnChildAdded(View child)
{
return true;
}
}
class CustomDragDropController : DragDropController
{
public CustomDragDropController(SfListView listView):base(listView)
{
}
protected override async Task<bool> OnLayoutItem(View element, Rectangle rect)
{
return true;
}
}