同一页面上的两个重新排序列表框,防止用户在之间拖放

Posted

技术标签:

【中文标题】同一页面上的两个重新排序列表框,防止用户在之间拖放【英文标题】:Two Reordering ListBoxes on Same page, prevent user from dragging and dropping between 【发布时间】:2015-10-31 07:15:10 【问题描述】:

我有一个 WPF c# 应用程序,它有一个窗口,其中两个重新排序列表框紧挨着彼此。我使用this link 中的示例来制作列表框用户控件。不幸的是,这允许用户从一个盒子中拖动并放入另一个盒子。如何确保不会发生这种情况?

这是我的代码:

    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);
            
        
    

【问题讨论】:

所以你不想拖放?只需删除与之关联的事件。例如:ListBoxItem_PreviewMouseLeftButtonDownListBoxItem_DropMove @AbinMathew 我希望能够在同一个列表框中拖放,以便可以在框内重新排序项目。我不希望用户能够从一个盒子中拖放到另一个盒子中。 【参考方案1】:

我想办法以防其他人有类似的问题......

我将移动功能更改为以下内容:

 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. ");

            
        

我意识到,如果我先删除项目,那么我不必担心根据 sourceIndex 相对于 targetIndex 的位置更改目标或删除索引。相反,我可以将它包装在 try catch 中并查找 ArgumentOutOfRangeException,如果用户尝试在它们之间拖放,就会发生这种情况。如果发生这种情况,我会将框重置为以前的项目。

据我所知,这个解决方案运行良好......可能有一种更简单的方法来解决这个问题。

【讨论】:

以上是关于同一页面上的两个重新排序列表框,防止用户在之间拖放的主要内容,如果未能解决你的问题,请参考以下文章

使用拖放重新排序winforms列表框?

一般拖放 ListBoxItems

QTreeView - 如何判断拖放事件是重新排序还是父母之间的移动?

在 Flutter 中通过拖放重新排序 SliverList 中的项目

拖放以重新排序 HTML 列表

tkinter 列表框用 python 拖放