同一页面上的两个重新排序列表框,防止用户在之间拖放
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_PreviewMouseLeftButtonDown
、ListBoxItem_Drop
、Move
@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,如果用户尝试在它们之间拖放,就会发生这种情况。如果发生这种情况,我会将框重置为以前的项目。
据我所知,这个解决方案运行良好......可能有一种更简单的方法来解决这个问题。
【讨论】:
以上是关于同一页面上的两个重新排序列表框,防止用户在之间拖放的主要内容,如果未能解决你的问题,请参考以下文章
QTreeView - 如何判断拖放事件是重新排序还是父母之间的移动?