Aar*_*ron 56 c# wpf drag-and-drop
我试图弄清楚如何通过鼠标拖动上下移动预先填充的列表框中的项目.
我从microsoft的api看过Control.DoDragDrop方法,但我仍然无法做任何事情.
我很感激任何帮助,因为我是视觉工作室环境的新手.
dnr*_*nr3 69
我尝试使用observablecollection创建一个,看看
ObservableCollection<Emp> _empList = new ObservableCollection<Emp>();
public Window1()
{
InitializeComponent();
_empList .Add(new Emp("1", 22));
_empList .Add(new Emp("2", 18));
_empList .Add(new Emp("3", 29));
_empList .Add(new Emp("4", 9));
_empList .Add(new Emp("5", 29));
_empList .Add(new Emp("6", 9));
listbox1.DisplayMemberPath = "Name";
listbox1.ItemsSource = _empList;
Style itemContainerStyle = new Style(typeof(ListBoxItem));
itemContainerStyle.Setters.Add(new Setter(ListBoxItem.AllowDropProperty, true));
itemContainerStyle.Setters.Add(new EventSetter(ListBoxItem.PreviewMouseLeftButtonDownEvent, new MouseButtonEventHandler(s_PreviewMouseLeftButtonDown)));
itemContainerStyle.Setters.Add(new EventSetter(ListBoxItem.DropEvent, new DragEventHandler(listbox1_Drop)));
listbox1.ItemContainerStyle = itemContainerStyle;
}
Run Code Online (Sandbox Code Playgroud)
拖放过程
void s_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (sender is ListBoxItem)
{
ListBoxItem draggedItem = sender as ListBoxItem;
DragDrop.DoDragDrop(draggedItem, draggedItem.DataContext, DragDropEffects.Move);
draggedItem.IsSelected = true;
}
}
void listbox1_Drop(object sender, DragEventArgs e)
{
Emp droppedData = e.Data.GetData(typeof(Emp)) as Emp;
Emp target = ((ListBoxItem)(sender)).DataContext as Emp;
int removedIdx = listbox1.Items.IndexOf(droppedData);
int targetIdx = listbox1.Items.IndexOf(target);
if (removedIdx < targetIdx)
{
_empList.Insert(targetIdx + 1, droppedData);
_empList.RemoveAt(removedIdx);
}
else
{
int remIdx = removedIdx+1;
if (_empList.Count + 1 > remIdx)
{
_empList.Insert(targetIdx, droppedData);
_empList.RemoveAt(remIdx);
}
}
}
Run Code Online (Sandbox Code Playgroud)
注意:
PreviewMouseLeftButtonDown事件,被拖动的项目看起来没有被选中Wie*_*tés 21
使用dnr3的答案我创建了具有固定选择问题的版本.
Window1.xaml
<Window x:Class="ListBoxReorderDemo.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="ListBoxReorderDemo" Height="300" Width="300"
WindowStartupLocation="CenterScreen">
<Grid>
<ListBox x:Name="listBox"/>
</Grid>
</Window>
Run Code Online (Sandbox Code Playgroud)
Window1.xaml.cs
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
namespace ListBoxReorderDemo
{
public class Item
{
public string Name { get; set; }
public Item(string name)
{
this.Name = name;
}
}
public partial class Window1 : Window
{
private Point _dragStartPoint;
private T FindVisualParent<T>(DependencyObject child)
where T : DependencyObject
{
var parentObject = VisualTreeHelper.GetParent(child);
if (parentObject == null)
return null;
T parent = parentObject as T;
if (parent != null)
return parent;
return FindVisualParent<T>(parentObject);
}
private IList<Item> _items = new ObservableCollection<Item>();
public Window1()
{
InitializeComponent();
_items.Add(new Item("1"));
_items.Add(new Item("2"));
_items.Add(new Item("3"));
_items.Add(new Item("4"));
_items.Add(new Item("5"));
_items.Add(new Item("6"));
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);
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);
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
支持泛型和数据绑定的版本.
Window1.xaml
<Window x:Class="ListBoxReorderDemo.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ListBoxReorderDemo"
Title="ListBoxReorderDemo" Height="300" Width="300"
WindowStartupLocation="CenterScreen">
<Grid>
<local:ItemDragAndDropListBox x:Name="listBox" ItemsSource="{Binding}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</local:ItemDragAndDropListBox>
</Grid>
</Window>
Run Code Online (Sandbox Code Playgroud)
Window1.xaml.cs
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
namespace ListBoxReorderDemo
{
public class DragAndDropListBox<T> : ListBox
where T : class
{
private Point _dragStartPoint;
private P FindVisualParent<P>(DependencyObject child)
where P : DependencyObject
{
var parentObject = VisualTreeHelper.GetParent(child);
if (parentObject == null)
return null;
P parent = parentObject as P;
if (parent != null)
return parent;
return FindVisualParent<P>(parentObject);
}
public DragAndDropListBox()
{
this.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)));
this.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(T)) as T;
var target = ((ListBoxItem)(sender)).DataContext as T;
int sourceIndex = this.Items.IndexOf(source);
int targetIndex = this.Items.IndexOf(target);
Move(source, sourceIndex, targetIndex);
}
}
private void Move(T source, int sourceIndex, int targetIndex)
{
if (sourceIndex < targetIndex)
{
var items = this.DataContext as IList<T>;
if (items != null)
{
items.Insert(targetIndex + 1, source);
items.RemoveAt(sourceIndex);
}
}
else
{
var items = this.DataContext as IList<T>;
if (items != null)
{
int removeIndex = sourceIndex + 1;
if (items.Count + 1 > removeIndex)
{
items.Insert(targetIndex, source);
items.RemoveAt(removeIndex);
}
}
}
}
}
public class Item
{
public string Name { get; set; }
public Item(string name)
{
this.Name = name;
}
}
public class ItemDragAndDropListBox : DragAndDropListBox<Item> { }
public partial class Window1 : Window
{
private IList<Item> _items = new ObservableCollection<Item>();
public Window1()
{
InitializeComponent();
_items.Add(new Item("1"));
_items.Add(new Item("2"));
_items.Add(new Item("3"));
_items.Add(new Item("4"));
_items.Add(new Item("5"));
_items.Add(new Item("6"));
listBox.DataContext = _items;
}
}
}
Run Code Online (Sandbox Code Playgroud)
我建议使用名为GongSolutions.WPF.DragDrop的拖放行为.它允许使用附加属性设置器的MVVM样式用例启用它,不需要在视图中隐藏代码.您应该查看链接以获取一个简单示例.
我采用了 dnr3 的答案并对其进行了更改,以便在 XAML 中实现。相同的结果,只是更喜欢在 XAML 中做我能做的,而不是在代码隐藏中。
代替代码隐藏:
Style itemContainerStyle = new Style(typeof(ListBoxItem));
itemContainerStyle.Setters.Add(new Setter(AllowDropProperty, true));
itemContainerStyle.Setters.Add(new EventSetter(PreviewMouseLeftButtonDownEvent, new MouseButtonEventHandler(s_PreviewMouseLeftButtonDown)));
itemContainerStyle.Setters.Add(new EventSetter(DropEvent, new DragEventHandler(listbox1_Drop)));
listbox1.ItemContainerStyle = itemContainerStyle;
Run Code Online (Sandbox Code Playgroud)
把它放在 XAML 中:
<Window.Resources>
<Style x:Key="ListBoxDragDrop" TargetType="{x:Type ListBoxItem}">
<Setter Property="AllowDrop" Value="true"/>
<EventSetter Event="PreviewMouseMove" Handler="s_PreviewMouseMoveEvent"/>
<EventSetter Event="Drop" Handler="listbox1_Drop"/>
</Style>
</Window.Resources>
<Grid>
<ListBox x:Name="listbox1" ItemContainerStyle="{StaticResource ListBoxDragDrop}" HorizontalAlignment="Left" Height="299" Margin="10,10,0,0" VerticalAlignment="Top" Width="224"/>
</Grid>
Run Code Online (Sandbox Code Playgroud)
这是放置在 XAML 代码隐藏中的鼠标处理程序。
void s_PreviewMouseMoveEvent(object sender, MouseEventArgs e)
{
if (sender is ListBoxItem && e.LeftButton == MouseButtonState.Pressed)
{
ListBoxItem draggedItem = sender as ListBoxItem;
DragDrop.DoDragDrop(draggedItem, draggedItem.DataContext, DragDropEffects.Move);
draggedItem.IsSelected = true;
}
}
Run Code Online (Sandbox Code Playgroud)