一般拖放ListBoxItems

我想使用MVVM模式在多个数据绑定的列表框上实现拖放。 我不是想在列表框之间拖放,而是希望用户能够在每个列表框中拖放listboxitems,以便他们可以重新排列排序顺序。 我在SO上发现这篇post非常有帮助:

WPF C#:通过拖放重新排列列表框中的项目

我想尝试使这些方法更“通用”,以便它可以在任何绑定到不同类型的Observable Collections的列表框上工作。 所以说这是我在VIEW中的XAML:

                 

OC绑定的位置是ObservalbeCollection 和ObservalbeCollection 。 这是VIEW中抓取鼠标移动事件并检查它是否是拖动的方法:

 void ListBoxItem_PreviewMouseMoveEvent(object sender, MouseEventArgs e) { if (e.LeftButton == MouseButtonState.Pressed && sender is ListBoxItem) { ListBoxItem draggedItem = (ListBoxItem)sender; DragDrop.DoDragDrop(draggedItem, draggedItem.DataContext, DragDropEffects.Move); draggedItem.IsSelected = true; } } 

这似乎是“通用的”。 接下来是方法,也是在VIEW中,处理drop,这就是我遇到的问题:

 void ListBoxItem_Drop(object sender, DragEventArgs e) { object Target = ((ListBoxItem)(sender)).DataContext; object Dropped = e.Data.GetData(Target.GetType()); int RemoveIndex = listbox1.Items.IndexOf(Dropped); int TargetIndex = listbox1.Items.IndexOf(Target); ListBox container = ((DependencyObject)sender).GetAncestor(); if (RemoveIndex < TargetIndex) { //THESE WILL NOT WORK IF I AM DOING BINDINGS THROUGH THE ITEMSSOURCE //container.Items.Insert(RemoveIndex + 1, Dropped); //container.Items.RemoveAt(RemoveIndex); //SO HAVE TO USE THE ITEMSSOURCE DIRECTLY BUT HOW WITHOUT A SPECIFIC CAST TO THE OC container.ItemsSource.Insert(RemoveIndex + 1, Dropped); //ERROR: IENUMERATOR DOES NOT CONTAIN A DEFINITION FOR INSERT.... container.ItemsSource.RemoveAt(RemoveIndex); //ERROR: IENUMERATOR DOES NOT CONTAIN A DEFINITION FOR REMOVEAT.... } else if (container.Items.Count > RemoveIndex) { //THESE WILL NOT WORK IF I AM DOING BINDINGS THROUGH THE ITEMSSOURCE //container.Items.Insert(TargetIndex, Dropped); //container.Items.RemoveAt(RemoveIndex + 1); //SO HAVE TO USE THE ITEMSSOURCE DIRECTLY BUT HOW WITHOUT A SPECIFIC CAST TO THE OC container.ItemsSource.Insert(TargetIndex, Dropped); //ERROR: IENUMERATOR DOES NOT CONTAIN A DEFINITION FOR INSERT.... container.ItemsSource.RemoveAt(RemoveIndex + 1); //ERROR: IENUMERATOR DOES NOT CONTAIN A DEFINITION FOR REMOVEAT.... } } 

找到祖先function就是这个(来自SO的另一篇文章):

 static T FindAnchestor(DependencyObject current) where T : DependencyObject { do { if (current is T) return (T)current; current = VisualTreeHelper.GetParent(current); } while (current != null); return null; } 

在drop函数中,如果我直接添加到ListBox的List集合中,这可能会起作用。 但是由于我在VIEWMODEL中对集合进行绑定,因此我必须通过ItemsSource处理这些对象。 但是如果我使用ItemsSource,我将不得不为每个OC类型创建该函数的可疑版本,因为我不会在运行时投射ItemsSource。 我可以使用if语句将其保持为1个函数,该语句确定将其强制转换为显式内容,但如果对于应用于每个新OC,则不必记住更新。

问题是如何在不知道要投射的内容的情况下如何向ItemsSource添加/移动项目?

谢谢你的帮助。

这是一个非常方便的工具/框架。 龚WPF拖放

谢谢你的帮助。 结果比我想象的要简单得多,因为OC实现它并且它就像魅力一样,只需将其转换为IList。 以下是可能需要它的任何人的完整代码。 这可以应用于任何实现IList的集合支持的列表框,包括Observable Collections和generics列表等等:

 void ListBoxItem_Drop(object sender, DragEventArgs e) { object Target = ((ListBoxItem)(sender)).DataContext; object Dropped = e.Data.GetData(Target.GetType()); ListBox container = ((DependencyObject)sender).GetAncestor(); int RemoveIndex = container.Items.IndexOf(Dropped); int TargetIndex = container.Items.IndexOf(Target); IList IList = (IList)container.ItemsSource; if (RemoveIndex < TargetIndex) { IList.Insert(TargetIndex + 1, Dropped); IList.RemoveAt(RemoveIndex); } else if (IList.Count > RemoveIndex) { IList.Insert(TargetIndex, Dropped); IList.RemoveAt(RemoveIndex + 1); } } 

厄尼