Search code examples
drag-and-dropblazormudblazor

MudBlazor MudDropZone keep originating item in the source dropzone


Using MudBlazor's MudDropZone, I have been able to successfully drag from one zone to another. However, I was wondering if there is a way to keep the item being dragged, from a specific drop zone identifier, in origin drop zone but also allow it to be dragged to it's destination drop zone. My ultimate goal is to have the source item stay in the source drop zone, keep it's original source index, and create another copy in the destination drop zone.

Have tried creating a new item in the item list in ItemDropped event but source item reindexes itself upon drag/drop into new zone. I can keep it in the original list but the IndexInZone puts it at the bottom of the source list.

TryMudBlazor Snippet


Solution

  • I forced the order of the elements of the list every time we move those. This might be improved for performance, but I aimed at make it work.

    The main issue was that the event handler that put the drag item at the bottom of the source dropzone was executed after ItemUpdated. Consequently, I made sure to execute my reordering process after this event: I do it in OnAfterRenderAsync() (this might be improved by maybe overriding the right event handler instead, if possible). I use await Task.Yield() to force the rerendering of the container.

    <MudDropContainer 
        T="DragDropItem" 
        Items="Items" 
        ItemDropped="ItemUpdated"
        ItemsSelector="@((item,dropzone) => item.Identifier == dropzone)"
        Class="d-flex flex-wrap flex-grow-1"
        @ref="MudDropContainerRef">
        <ChildContent>
            <MudPaper 
                Class="ma-4 flex-grow-1">
                    <MudList 
                        Clickable="true" 
                        Class="d-flex flex-column mud-height-full">
                        <MudListSubheader>Destination Zone</MudListSubheader>
                        <MudDropZone 
                            T="DragDropItem"
                            Identifier="DestinationZone" 
                            Class="flex-grow-1"
                            AllowReorder="true"/>
                    </MudList>
            </MudPaper>
    
            <MudPaper 
                Class="flex-grow-1">
                <MudList 
                    Clickable="true" 
                    Class="d-flex flex-column mud-height-full">
                    <MudListSubheader>Source Zone</MudListSubheader>
                    <MudDropZone 
                        T="DragDropItem"
                        Identifier="SourceZone"
                        Class="flex-grow-1"
                        AllowReorder="true"/>
                </MudList>
            </MudPaper>
        </ChildContent>
        <ItemRenderer>
            <MudListItem Text="@context.Text" />
        </ItemRenderer>
    </MudDropContainer>
    
    @code {
       MudDropContainer<DragDropItem> MudDropContainerRef {get;set;}
    
       public bool DragItemMoved {get;set;} = false;
    
       public class DragDropItem{
           public int Order {get;set;}
           public string Text {get;set;}
           public string Identifier {get;set;}
       }
    
       public List<DragDropItem> Items = new()
        {
            new DragDropItem() {
                Order = 1,
                Text = "Item1",
                Identifier = "SourceZone"
            },
            new DragDropItem() {
                Order = 2,
                Text = "Item2",
                Identifier = "SourceZone"
            }
        };
        
        private void ItemUpdated(MudItemDropInfo<DragDropItem> dropItem)
        {
            if (dropItem.Item.Identifier == "SourceZone" && dropItem.DropzoneIdentifier != "SourceZone"){
                if (!Items.Exists(x => x.Text == dropItem.Item.Text && x.Identifier == dropItem.DropzoneIdentifier)){
                    var newItem = new DragDropItem(){
                        Order = -1,
                        Text = dropItem.Item.Text,
                        Identifier = dropItem.DropzoneIdentifier
                    };
    
                    Items.Insert(dropItem.IndexInZone == -1 ? 0 : dropItem.IndexInZone,newItem);
                }
            }
            else if (dropItem.Item.Identifier != "SourceZone" && dropItem.DropzoneIdentifier != "SourceZone"){
                dropItem.Item.Identifier = dropItem.DropzoneIdentifier;
            }
    
            DragItemMoved = true;   
        }
    
        protected override async Task OnAfterRenderAsync(bool firstRender)
        {
            if(DragItemMoved)
            {
                DragItemMoved = false;
    
                Items = Items.OrderBy(i => i.Order).ToList();
    
                await Task.Yield();
                MudDropContainerRef.Refresh();
            }
        }
    }