Click here to Skip to main content
15,867,308 members
Articles / Desktop Programming / WPF

C# WPF listview Drag & Drop a Custom Item

Rate me:
Please Sign up or sign in to vote.
5.00/5 (10 votes)
26 Mar 2018CPOL2 min read 38.2K   16   3
This article explains how to implement the drag & drop of a custom item within a ListView control with WPF technology.

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.

XML
<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:

C#
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:

C#
using System.Collections.ObjectModel;       // ObservableCollection class

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.

C#
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();

C#
private void InitializeListView()
{
    // Clear data
    lstView.Items.Clear();
    Items.Clear();
    // Add rows
    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.

C#
private void lstView_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    // Get current mouse position
    startPoint = e.GetPosition(null);
}

// Helper to search up the VisualTree
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)
{
    // Get the current mouse position
    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))
    {
        // Get the dragged ListViewItem
        ListView listView = sender as ListView;
        ListViewItem listViewItem = FindAnchestor<ListViewItem>((DependencyObject)e.OriginalSource);
        if (listViewItem == null) return;           // Abort
        // Find the data behind the ListViewItem
        WorkItem item = (WorkItem)listView.ItemContainerGenerator.ItemFromContainer(listViewItem);
        if (item == null) return;                   // Abort
        // Initialize the drag & drop operation
        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)
    {
        // Get the drop ListViewItem destination
        ListView listView = sender as ListView;
        ListViewItem listViewItem = FindAnchestor<ListViewItem>((DependencyObject)e.OriginalSource);
        if (listViewItem == null)
        {
            // Abort
            e.Effects = DragDropEffects.None;
            return;
        }
        // Find the data behind the ListViewItem
        WorkItem item = (WorkItem)listView.ItemContainerGenerator.ItemFromContainer(listViewItem);
        // Move item into observable collection 
        // (this will be automatically reflected to lstView.ItemsSource)
        e.Effects = DragDropEffects.Move;
        index = Items.IndexOf(item);
        if (startIndex >=0 && index >= 0)
        {
            Items.Move(startIndex, index);
        }
        startIndex = -1;        // Done!
    }
}

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

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) Palladio Software House s.r.l.
Italy Italy
My main experience as software developer in short

From 2014-today : WPF C# developing of desktop application and WPF controls (NPoco ORM). Web developer using C# ASP.NET MVC5 and Entity Framework
17/03/2008-2014 : WinForm C# 2005-2008 developer and Web developer (HTML, PHP, MySQL), QlikView Business Intelligence Developer
14/03/2001-15/03/2008 : WinForm VisualBasic 6.0, C#2003, C# 2005 developer and finally, in the 2007-8, also web developer (HTML, PHP, MySQL)
01/11/1992-13/03/2001 : MS-DOS Turbo Pascal 7.0 (OOP), Quick Basic 4.5 developer and WinForm Visual Basic 3.0 / 5.0 developer.
----------------------------

Comments and Discussions

 
GeneralMy vote of 5 Pin
AMMaui22-May-23 18:52
AMMaui22-May-23 18:52 
QuestionConverting to VB.Net Pin
Member 1571849126-Jul-22 10:37
Member 1571849126-Jul-22 10:37 
GeneralMy vote of 5 Pin
James Box1-May-19 6:20
James Box1-May-19 6:20 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.