0

I have a WPF c# application that has a window with two Reordering Listboxes right next to each other. I used the examples in this link to make the listbox user control. Unfortunately this allows the user to drag from one box and drop in the other. How can I make sure that this doesn't happen?

Here is my code:

    public void setItems(List<string> values){
        _items = new ObservableCollection<Item>();
        foreach (string s in values)
        {
            _items.Add(new Item(s));
        }

        listBox.DisplayMemberPath = "Name";
        listBox.ItemsSource = _items;

        listBox.PreviewMouseMove += ListBox_PreviewMouseMove;

        var style = new Style(typeof(ListBoxItem));
        style.Setters.Add(new Setter(ListBoxItem.AllowDropProperty, true));
        style.Setters.Add(
            new EventSetter(
                ListBoxItem.PreviewMouseLeftButtonDownEvent,
                new MouseButtonEventHandler(ListBoxItem_PreviewMouseLeftButtonDown)));
        style.Setters.Add(
                new EventSetter(
                    ListBoxItem.DropEvent,
                    new DragEventHandler(ListBoxItem_Drop)));
        listBox.ItemContainerStyle = style;
    }


    private void ListBox_PreviewMouseMove(object sender, MouseEventArgs e)
    {

            Point point = e.GetPosition(null);
            Vector diff = _dragStartPoint - point;
            if (e.LeftButton == MouseButtonState.Pressed &&
                (Math.Abs(diff.X) > SystemParameters.MinimumHorizontalDragDistance ||
                    Math.Abs(diff.Y) > SystemParameters.MinimumVerticalDragDistance))
            {
                var lb = sender as ListBox;
                var lbi = FindVisualParent<ListBoxItem>(((DependencyObject)e.OriginalSource));
                if (lbi != null)
                {
                    DragDrop.DoDragDrop(lbi, lbi.DataContext, DragDropEffects.Move);
                }
            }

    }


    private void ListBoxItem_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        _dragStartPoint = e.GetPosition(null);
    }


    private void ListBoxItem_Drop(object sender, DragEventArgs e)
    {
        if (sender is ListBoxItem)
        {
            var source = e.Data.GetData(typeof(Item)) as Item;
            var target = ((ListBoxItem)(sender)).DataContext as Item;


                int sourceIndex = listBox.Items.IndexOf(source);
                int targetIndex = listBox.Items.IndexOf(target);

                Debug.WriteLine("Target: " + targetIndex.ToString());

                Move(source, sourceIndex, targetIndex);

        }
    }


    private void Move(Item source, int sourceIndex, int targetIndex)
    {
        if (sourceIndex < targetIndex)
        {
            _items.Insert(targetIndex + 1, source);
            _items.RemoveAt(sourceIndex);
        }
        else
        {
            int removeIndex = sourceIndex + 1;
            if (_items.Count + 1 > removeIndex)
            {
                _items.Insert(targetIndex, source);
                _items.RemoveAt(removeIndex);
            }
        }
    }
}
Community
  • 1
  • 1
Renee
  • 17
  • 3
  • So you dont want drag and drop ? simply remove the events associated with it. eg: `ListBoxItem_PreviewMouseLeftButtonDown` , `ListBoxItem_Drop` , `Move` – Abin Aug 07 '15 at 19:08
  • @AbinMathew I want to be able to drag and drop within the same list box, so the items can be reordered inside of a box. I don't want the user to be able to drag from one box and drop in another box. – Renee Aug 11 '15 at 13:53

1 Answers1

0

I figured it out in case anyone else has a similar issue...

I changed the Move function to the following:

 private void Move(Item source, int sourceIndex, int targetIndex)
        {
            IList<Item> prevItems = _items;

            try
            {
                _items.RemoveAt(sourceIndex);
                _items.Insert(targetIndex, source);

            }
            catch(ArgumentOutOfRangeException)
            {
                //User doesn't need to be notified about this. It just means that they dragged out of the box they were ordering. 
                //The application does not need to be stopped when this happens.
                _items = prevItems;
                Debug.WriteLine("User tried to drag between boxes.. Order of boxes were not changed. ");

            }
        }

I realized that if I remove the item first then I won't have to worry about changing the target or remove index based on the position of the sourceIndex in relation to the targetIndex. Instead I can wrap it in a try catch and look for an ArgumentOutOfRangeException, which will happen if the user tries to drag and drop between. If that happens I reset the box to the previous items.

As far as I can tell this solution works fine... There may have been a simpler way to go about this.

Renee
  • 17
  • 3