我想使用MVVM模式在多个数据绑定列表框上实现拖放。我不是想在列表框之间拖放,而是希望用户能够在每个列表框中拖放listboxitems,以便他们可以重新排列排序顺序。我在SO上发现这篇帖子非常有帮助:
WPF C#: Rearrange items in listbox via drag and drop
我想尝试使这些方法更“通用”,以便它可以在任何绑定到不同类型的Observable Collections的列表框上工作。所以说这是我在VIEW中的XAML:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<Style TargetType="{x:Type ListBoxItem}" x:Key="ListBoxItemDragDrop">
<Setter Property="AllowDrop" Value="True" />
<EventSetter Event="PreviewMouseMove" Handler="ListBoxItem_PreviewMouseMoveEvent" />
<EventSetter Event="Drop" Handler="listbox1_Drop" />
</Style>
</Window.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<ListBox Name="listbox1"
ItemsSource="{Binding OCofType1}"
ItemContainerStyle="{StaticResource ListBoxItemDragDrop}" />
<ListBox Name="listbox2" Grid.Column="1"
ItemsSource="{Binding OCofType2}"
ItemContainerStyle="{StaticResource ListBoxItemDragDrop}"/>
</Grid>
</Window>
OC绑定是ObservalbeCollection&lt; Type1&gt;和ObservalbeCollection&lt; Type2&gt;。这是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<ListBox>();
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<TYPE#>
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<TYPE#>
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....
}
}
找到祖先功能就是这个(来自SO的另一篇文章):
static T FindAnchestor<T>(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?
感谢您的帮助。
答案 0 :(得分:5)
这是一个非常方便的工具/框架。 Gong WPF Drag & Drop
答案 1 :(得分:2)
感谢帮助人员。结果比我想象的要简单得多,因为OC实现它并且它就像魅力一样,只需将其转换为IList。以下是可能需要它的任何人的完整代码。这可以应用于任何实现IList的集合支持的列表框,包括Observable Collections和泛型列表等等:
void ListBoxItem_Drop(object sender, DragEventArgs e)
{
object Target = ((ListBoxItem)(sender)).DataContext;
object Dropped = e.Data.GetData(Target.GetType());
ListBox container = ((DependencyObject)sender).GetAncestor<ListBox>();
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);
}
}
欧尼