Introduction
This article shows step by step how to implement drag & drop in a ListView
object of the current selected item to change the presentation sequence. Row items are defined using a custom class. It will also be shown how to move an item using two buttons.
Pic.1 - "Row 3" has been moved from last position to the first position
Using the Code
Create a new project and in the XAML code editor that defines the main window, insert this code to add a couple of buttons and a ListView
object. In the ListView
object, it is important to set this property AllowDrop = "True"
, otherwise the drag & drop will not be enabled.
<Button x:Name="btnUp" Content="Move Up" HorizontalAlignment="Left" Height="28"
Margin="10,12,0,0" VerticalAlignment="Top" Width="68" Click="btnUp_Click"/>
<Button x:Name="btnDown" Content="Move Dn" HorizontalAlignment="Left" Height="28"
Margin="83,12,0,0" VerticalAlignment="Top" Width="68" Click="btnDown_Click"/>
<ListView Margin="10,50,10,10" Name="lstView" BorderBrush="WhiteSmoke"
AllowDrop="True" PreviewMouseLeftButtonDown="lstView_PreviewMouseLeftButtonDown"
MouseMove="lstView_MouseMove" DragEnter="lstView_DragEnter" Drop="lstView_Drop">
<ListView.View>
<GridView>
<GridViewColumn Header="Sel." Width="32">
<GridViewColumn.CellTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding IsSelected}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Title" Width="120" DisplayMemberBinding="{Binding Title}" />
<GridViewColumn Header="Note" Width="150" DisplayMemberBinding="{Binding Note}" />
</GridView>
</ListView.View>
</ListView>
Code 1 - This XAML code must be inserted between the <Grid></Grid> data block.
Create a new class and add the following code:
public class WorkItem
{
public bool IsSelected { get; set; }
public string Title { get; set; }
public string Note { get; set; }
public WorkItem(bool isSelected, string title, string note)
{
this.IsSelected = isSelected;
this.Title = title;
this.Note = note;
}
}
This class is the model that represents the data item of the ListView
object. To display your custom item, you must modify the properties of the WorkItem
class and the XAML code to define your data columns and the correct data binding to your custom class.
Open the code editor for the main window and add the following code in the using
section:
using System.Collections.ObjectModel;
The list of items will be managed through the ObservableCollection
object because this exposes methods to make it easier to move items within the collection.
Add the following private
variables at the window class level.
private Point startPoint = new Point();
private ObservableCollection<WorkItem> Items = new ObservableCollection<WorkItem>();
private int startIndex = -1;
To insert test data in the ListView
control, call the InitializeListView();
function from the class constructor, for example after the call of the standard function InitializeComponent();
private void InitializeListView()
{
lstView.Items.Clear();
Items.Clear();
Items.Add(new WorkItem(true, "Row 1", "First orw"));
Items.Add(new WorkItem(false, "Row 2", "Second row"));
Items.Add(new WorkItem(true, "Row 3", "Third row"));
lstView.ItemsSource = Items;
}
Add the following code to implement the events associated with the on-screen objects. Using the btnUp
and btnDown
buttons, you can move the selected item in the ListView
control without using the drag & drop function.
private void lstView_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
startPoint = e.GetPosition(null);
}
private 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;
}
private void lstView_MouseMove(object sender, MouseEventArgs e)
{
Point mousePos = e.GetPosition(null);
Vector diff = startPoint - mousePos;
if (e.LeftButton == MouseButtonState.Pressed &&
(Math.Abs(diff.X) > SystemParameters.MinimumHorizontalDragDistance ||
Math.Abs(diff.Y) > SystemParameters.MinimumVerticalDragDistance))
{
ListView listView = sender as ListView;
ListViewItem listViewItem = FindAnchestor<ListViewItem>((DependencyObject)e.OriginalSource);
if (listViewItem == null) return;
WorkItem item = (WorkItem)listView.ItemContainerGenerator.ItemFromContainer(listViewItem);
if (item == null) return;
startIndex = lstView.SelectedIndex;
DataObject dragData = new DataObject("WorkItem", item);
DragDrop.DoDragDrop(listViewItem, dragData, DragDropEffects.Copy | DragDropEffects.Move);
}
}
private void lstView_DragEnter(object sender, DragEventArgs e)
{
if (!e.Data.GetDataPresent("WorkItem") || sender != e.Source)
{
e.Effects = DragDropEffects.None;
}
}
private void lstView_Drop(object sender, DragEventArgs e)
{
int index = -1;
if (e.Data.GetDataPresent("WorkItem") && sender == e.Source)
{
ListView listView = sender as ListView;
ListViewItem listViewItem = FindAnchestor<ListViewItem>((DependencyObject)e.OriginalSource);
if (listViewItem == null)
{
e.Effects = DragDropEffects.None;
return;
}
WorkItem item = (WorkItem)listView.ItemContainerGenerator.ItemFromContainer(listViewItem);
e.Effects = DragDropEffects.Move;
index = Items.IndexOf(item);
if (startIndex >=0 && index >= 0)
{
Items.Move(startIndex, index);
}
startIndex = -1;
}
}
private void btnUp_Click(object sender, RoutedEventArgs e)
{
WorkItem item = null;
int index = -1;
if (lstView.SelectedItems.Count != 1) return;
item = (WorkItem)lstView.SelectedItems[0];
index = Items.IndexOf(item);
if (index > 0)
{
Items.Move(index, index - 1);
}
}
private void btnDown_Click(object sender, RoutedEventArgs e)
{
WorkItem item = null;
int index = -1;
if (lstView.SelectedItems.Count != 1) return;
item = (WorkItem)lstView.SelectedItems[0];
index = Items.IndexOf(item);
if (index < Items.Count - 1)
{
Items.Move(index, index + 1);
}
}
That's all! Thank you for taking the time to read this article. If you found it useful, please rate it.
History
- Version 1.0.0 - 26/03/2018