Here is an example how I've done it.
XAML:
<Window.DataContext>
<local:MyViewModel />
</Window.DataContext>
<Grid>
<ScrollViewer>
<ListView ItemsSource="{Binding MyData}" HorizontalAlignment="Stretch" Name="listview" ScrollViewer.PanningMode="VerticalOnly">
<ListView.ItemTemplate>
<DataTemplate>
<Button Content="{Binding}"
Command="{Binding DataContext.MyCommand, RelativeSource={RelativeSource AncestorType=ItemsControl}}"
CommandParameter="{Binding}"
Margin="5 2" Width="150" Height="50"
FontSize="30" />
</DataTemplate>
</ListView.ItemTemplate>
<ListView.Resources>
<Style TargetType="Button">
<EventSetter Event="PreviewMouseMove" Handler="PreviewMouseMove" />
<EventSetter Event="Drop" Handler="Drop" />
<Setter Property="AllowDrop" Value="True" />
</Style>
</ListView.Resources>
</ListView>
</ScrollViewer>
</Grid>
ViewModel:
class MyViewModel
{
public MyViewModel()
{
MyCommand = new ICommandImplementation();
}
public ObservableCollection<string> MyData
{
get
{
return new ObservableCollection<string>(new string[]{
"one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten",
"eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen", "twenty"
});
}
}
public ICommand MyCommand { get; private set; }
private class ICommandImplementation : ICommand
{
public bool CanExecute(object parameter) { return true; }
public event EventHandler CanExecuteChanged;
public void Execute(object parameter) { System.Windows.MessageBox.Show("Button clicked! " + (parameter ?? "").ToString()); }
}
}
Events:
private void Drop(object sender, DragEventArgs e)
{
var source = e.Data.GetData("Source") as string;
if (source != null)
{
int newIndex = listview.Items.IndexOf((sender as Button).Content);
var list = listview.ItemsSource as ObservableCollection<string>;
list.RemoveAt(list.IndexOf(source));
list.Insert(newIndex, source);
}
}
private void PreviewMouseMove(object sender, MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed)
{
Task.Factory.StartNew(new Action(() =>
{
Thread.Sleep(500);
App.Current.Dispatcher.BeginInvoke(new Action(() =>
{
if (e.LeftButton == MouseButtonState.Pressed)
{
var data = new DataObject();
data.SetData("Source", (sender as Button).Content);
DragDrop.DoDragDrop(sender as DependencyObject, data, DragDropEffects.Move);
e.Handled = true;
}
}), null);
}), CancellationToken.None);
}
}
Above example is a little complex cause every item of list
is a Button
and on Button
click
I also have to do some action. Your case is relatively easy.
Drag & Drop can be confusing for many developers. But below
are the some key points how to do it:
Use PreviewMouseMove
event to actually start a drag and in handler use DragDrop.DoDragDrop
event to raise DragDrop
related
events and Cursors
. sender
argument is the element that has
captured the mouse currently in this case the UIElement
that is
being dragged.
Use DragEnter
& DragOver
event if want to change the visual of element over which the Mouse
is currently dragging. sender
argument is the element that has currently dragged over / that just
ended drag over situation.
Use Drop
event to handle the dropped element. sender
argument is the element on which the Drop happened.
Use DataObject
object to pass info between these events. SetData
method of the class is used to add data in this. This method
has two arguments, and they work like key-value
pair. Once set you
can get this data in next called event of DragDrop
by using
GetData
method by passing the key
as argument. (i.e.
e.Data.GetData("Source")
)
Here is a relative post.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…