Search code examples
c#wpfdrag-and-drop

WPF C#: Rearrange items in listbox via drag and drop


I am trying to figure out how to move the items in a pre-populated listbox up and down via mouse drags.

I have looked at the Control.DoDragDrop method from microsoft's api, but I still can't get it to do anything.

I would appreciate any help since I am new to the visual studios environment.


Solution

  • I've tried creating one using ObservableCollection. Have a look.

        ObservableCollection<Emp> _empList = new ObservableCollection<Emp>();
    
        public Window1()
        {
            InitializeComponent();
    
            _empList .Add(new Emp("1", 22));
            _empList .Add(new Emp("2", 18));
            _empList .Add(new Emp("3", 29));
            _empList .Add(new Emp("4", 9));
            _empList .Add(new Emp("5", 29));
            _empList .Add(new Emp("6", 9));
            listbox1.DisplayMemberPath = "Name";
            listbox1.ItemsSource = _empList;
            
            Style itemContainerStyle = new Style(typeof(ListBoxItem));
            itemContainerStyle.Setters.Add(new Setter(ListBoxItem.AllowDropProperty, true));
            itemContainerStyle.Setters.Add(new EventSetter(ListBoxItem.PreviewMouseLeftButtonDownEvent, new MouseButtonEventHandler(s_PreviewMouseLeftButtonDown)));
            itemContainerStyle.Setters.Add(new EventSetter(ListBoxItem.DropEvent, new DragEventHandler(listbox1_Drop)));
            listbox1.ItemContainerStyle = itemContainerStyle;
        }
    

    Drag and drop process:

        void s_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
    
            if (sender is ListBoxItem)
            {
                ListBoxItem draggedItem = sender as ListBoxItem;
                DragDrop.DoDragDrop(draggedItem, draggedItem.DataContext, DragDropEffects.Move);
                draggedItem.IsSelected = true;
            }
        }
    
        void listbox1_Drop(object sender, DragEventArgs e)
        {
            Emp droppedData = e.Data.GetData(typeof(Emp)) as Emp;
            Emp target = ((ListBoxItem)(sender)).DataContext as Emp;
    
            int removedIdx = listbox1.Items.IndexOf(droppedData);
            int targetIdx = listbox1.Items.IndexOf(target);
    
            if (removedIdx < targetIdx)
            {
                _empList.Insert(targetIdx + 1, droppedData);
                _empList.RemoveAt(removedIdx);
            }
            else
            {
                int remIdx = removedIdx+1;
                if (_empList.Count + 1 > remIdx)
                {
                    _empList.Insert(targetIdx, droppedData);
                    _empList.RemoveAt(remIdx);
                }
            }
        }
    

    Note:

    • One thing that sucks in this implementation is that since it uses the PreviewMouseLeftButtonDown event, the dragged item does not look like a selected item.
    • And also for an easier implementation, the drop target is the list box items and not the listbox itself - might need a better solution for this.