而对于代码...
加价:
<AdornerDecorator Margin="5">
<ListBox x:Name="_listBox" Width="300"
HorizontalAlignment="Left"
ItemsSource="{Binding Path=Items}"
AllowDrop="True" Drop="listBox_Drop">
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<EventSetter Event="ListBoxItem.DragOver" Handler="listBoxItem_DragOver"/>
<EventSetter Event="ListBoxItem.Drop" Handler="listBoxItem_Drop"/>
<EventSetter Event="ListBoxItem.MouseMove" Handler="listBoxItem_MouseMove"/>
<EventSetter Event="ListBoxItem.MouseDown" Handler="listBoxItem_MouseDown"/>
<EventSetter Event="ListBoxItem.PreviewMouseDown" Handler="listBoxItem_MouseDown"/>
<Setter Property="AllowDrop" Value="True"/>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
</AdornerDecorator>
和代码隐藏:
private bool _isDragging;
private void listBox_MouseDown(object sender, MouseButtonEventArgs e)
{
_isDragging = false;
}
Adorner _adorner;
private void listBox_MouseMove(object sender, MouseEventArgs e)
{
if (!_isDragging && e.LeftButton == MouseButtonState.Pressed)
{
_isDragging = true;
if (_listBox.SelectedValue != null)
{
DragDrop.DoDragDrop(_listBox, _listBox.SelectedValue,
DragDropEffects.Move);
}
}
}
private ListBoxItem FindlistBoxItem(DragEventArgs e)
{
var visualHitTest = VisualTreeHelper.HitTest(_listBox, e.GetPosition(_listBox)).VisualHit;
ListBoxItem listBoxItem = null;
while (visualHitTest != null)
{
if (visualHitTest is ListBoxItem)
{
listBoxItem = visualHitTest as ListBoxItem;
break;
}
else if (visualHitTest == _listBox)
{
Console.WriteLine("Found listBox instance");
return null;
}
visualHitTest = VisualTreeHelper.GetParent(visualHitTest);
}
return listBoxItem;
}
void ClearAdorner()
{
if (_adorner != null)
{
var adornerLayer = AdornerLayer.GetAdornerLayer(_listBox);
adornerLayer.Remove(_adorner);
}
}
private void listBox_DragOver(object sender, DragEventArgs e)
{
e.Effects = DragDropEffects.Move;
ClearAdorner();
var listBoxItem = FindlistBoxItem(e);
if (listBoxItem == null || listBoxItem.DataContext == _listBox.SelectedItem) return;
if (IsInFirstHalf(listBoxItem, e.GetPosition(listBoxItem)))
{
var adornerLayer = AdornerLayer.GetAdornerLayer(_listBox);
_adorner = new DropBeforeAdorner(listBoxItem);
adornerLayer.Add(_adorner);
}
else if (IsInLastHalf(listBoxItem, e.GetPosition(listBoxItem)))
{
var adornerLayer = AdornerLayer.GetAdornerLayer(_listBox);
_adorner = new DropAfterAdorner(listBoxItem);
adornerLayer.Add(_adorner);
}
}
private void listBox_Drop(object sender, DragEventArgs e)
{
if (_isDragging)
{
_isDragging = false;
ClearAdorner();
var listBoxItem = FindlistBoxItem(e);
if (listBoxItem == null || listBoxItem.DataContext == _listBox.SelectedItem) return;
var drop = _listBox.SelectedItem as Export.Domain.Components.Component;
var target = listBoxItem.DataContext as Export.Domain.Components.Component;
var listBoxItem = GetlistBoxItemControl(listBoxItem);
if (IsInFirstHalf(listBoxItem, e.GetPosition(listBoxItem)))
{
var vm = this.DataContext as ComponentlistBoxModel;
vm.DropBefore(drop, target);
}
else if (IsInLastHalf(listBoxItem, e.GetPosition(listBoxItem)))
{
var vm = this.DataContext as ComponentlistBoxModel;
vm.DropAfter(drop, target);
}
}
}
public static bool IsInFirstHalf(FrameworkElement container, Point mousePosition)
{
return mousePosition.Y < (container.ActualHeight/2);
}
public static bool IsInLastHalf(FrameworkElement container, Point mousePosition)
{
return mousePosition.Y > (container.ActualHeight/2);
}
您可能不喜欢我的代码隐藏按类型具体引用视图模型的事实,但它完成了工作,并且快速简单,并且从技术上讲它不会破坏 MVVM 模式。我仍然将逻辑留给视图模型。
Addition 1
Animations 可能会提供您正在寻找的效果。在我的实现中,交换发生在丢弃时。但是,您可以通过使用装饰器并在拖动时进行交换来实现动画效果。拖动事件将更新装饰器位置和集合中对象的索引。