Geeks With Blogs
Sonam Singh

After going through the web ,I haven't got anything that i can use directly to enable drag drop between two listview controls or within same for multiple items.
The best thing available in my opinion is this one by Josh smith:
http://www.codeproject.com/KB/WPF/ListViewDragDropManager.aspx

But it is for single SelectionMode only

Another one for multiselct is this:
http://www.codeproject.com/KB/WPF/WPF_MultiSelect_DragDrop.aspx
But the second one has many limitations..
So i have done some work to extend it from there..
I don't have much time in near weeks to work on this ,So it is not that much well written.
But it will serve as the good to get u one what u want during drag drop in more graceful way....

A small project which shows demo,U can download it from here:..the code might differ a little bit but the theme remains same,,..:)

http://www.rapidshare.com/files/306026760/Listview.zip.html

The code is as follows:

using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;
using System.Windows.Controls;
using System.Windows;
using System.Windows.Media;
using System.Windows.Controls.Primitives;
using System.Collections.ObjectModel;
using System.Reflection;
using System.Diagnostics;
namespace DragDropManager
{
   public class DragDropManager<T> where T:class,ICloneable
   {
      
        ListView listView;

       // delegate for GetPosition function of DragEventArgs and
       // MouseButtonEventArgs event argument objects. This delegate is used to reuse the code
       // for processing both types of events.
       delegate Point GetPositionDelegate(IInputElement element);

       public DragDropManager(ListView listView)
       {
           this.listView = listView;
           listView.PreviewMouseLeftButtonDown += new System.Windows.Input.MouseButtonEventHandler(listView_PreviewMouseLeftButtonDown);
           listView.Drop += new System.Windows.DragEventHandler(listView_Drop);
       }

       void listView_Drop(object sender, DragEventArgs e)
       {
           int index = this.GetCurrentIndex(e.GetPosition);

           if (index < 0)
               return;

           Dictionary<int,T> draggedItems =  e.Data.GetData(typeof(Dictionary<int,T>)) as Dictionary<int,T>;

        if(sender==this.listView)
       
            this.listView.SelectedItems.Clear();


       int i = 0;

         ObservableCollection<T>  itemsSource=  this.listView.ItemsSource as ObservableCollection<T>;
       
           // finally insert the items into the source collection
         T dropTarget = itemsSource[index];

         if (draggedItems.ContainsValue(dropTarget)) return;
  
  
          foreach(int key in draggedItems.Keys)
          {
              T draggedItemClone = draggedItems[key].Clone() as T;
              itemsSource.Insert(index + i, draggedItemClone);
          
            
              i++;
         
          }
           
     
       }

       void listView_PreviewMouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
       {

           int index = this.GetCurrentIndex(e.GetPosition);

           if (index <0) return;
      
           // this will create the drag "rectangle"
           DragDropEffects allowedEffects = DragDropEffects.Move;

           if (this.listView.SelectedItems.Count == 0)
               return;
         
           Dictionary<int,T> draggedItems = new Dictionary<int, T>();
     
        
       
           foreach(T draggedItem in this.listView.SelectedItems)
           {
            draggedItems[this.listView.Items.IndexOf(draggedItem)] = (draggedItem as T);
            
           }

           T item = this.listView.Items[index] as T;

           if (!draggedItems.ContainsValue(item))
                     return;
          
           DragDrop.DoDragDrop(this.listView, draggedItems, allowedEffects);
       
       }
       ListViewItem GetListViewItem(int index)
       {
           if (this.listView.ItemContainerGenerator.Status != GeneratorStatus.ContainersGenerated)
               return null;

           return this.listView.ItemContainerGenerator.ContainerFromIndex(index) as ListViewItem;
       }

       // returns the index of the item in the ListView
       int GetCurrentIndex(GetPositionDelegate getPosition)
       {
           int index = -1;
           for (int i = 0; i < this.listView.Items.Count; ++i)
           {
               ListViewItem item = GetListViewItem(i);
           if (this.IsMouseOverTarget(item, getPosition))
            
               {
                   index = i;
                   break;
               }
           }
           return index;
       }
      
       bool IsMouseOverTarget(Visual target, GetPositionDelegate getPosition)
       {
           if (target == null)
               return false ;
           Rect bounds = VisualTreeHelper.GetDescendantBounds(target);
       
           Point mousePos=  MouseUtilities.GetMousePosition(target);
           return bounds.Contains(mousePos);
       }
   }
}


..........................................................................
The code for MouseUtilities.cs is :

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Media;

namespace DragDropManager
{
    /// <summary>
    /// Provides access to the mouse location by calling unmanaged code.
    /// </summary>
    /// <remarks>
    /// This class was written by Dan Crevier (Microsoft). 
    /// http://blogs.msdn.com/llobo/archive/2006/09/06/Scrolling-Scrollviewer-on-Mouse-Drag-at-the-boundaries.aspx
    /// </remarks>
    public class MouseUtilities
    {
        [StructLayout(LayoutKind.Sequential)]
        private struct Win32Point
        {
            public Int32 X;
            public Int32 Y;
        };

        [DllImport("user32.dll")]
        private static extern bool GetCursorPos(ref Win32Point pt);

        [DllImport("user32.dll")]
        private static extern bool ScreenToClient(IntPtr hwnd, ref Win32Point pt);

        /// <summary>
        /// Returns the mouse cursor location.  This method is necessary during
        /// a drag-drop operation because the WPF mechanisms for retrieving the
        /// cursor coordinates are unreliable.
        /// </summary>
        /// <param name="relativeTo">The Visual to which the mouse coordinates will be relative.</param>
        public static Point GetMousePosition(Visual relativeTo)
        {
            Win32Point mouse = new Win32Point();
            GetCursorPos(ref mouse);

            // Using PointFromScreen instead of Dan Crevier's code (commented out below)
            // is a bug fix created by William J. Roberts.  Read his comments about the fix
            // here: http://www.codeproject.com/useritems/ListViewDragDropManager.asp?msg=1911611#xx1911611xx
            return relativeTo.PointFromScreen(new Point((double)mouse.X, (double)mouse.Y));

            #region Commented Out
            //System.Windows.Interop.HwndSource presentationSource =
            //    (System.Windows.Interop.HwndSource)PresentationSource.FromVisual( relativeTo );
            //ScreenToClient( presentationSource.Handle, ref mouse );
            //GeneralTransform transform = relativeTo.TransformToAncestor( presentationSource.RootVisual );
            //Point offset = transform.Transform( new Point( 0, 0 ) );
            //return new Point( mouse.X - offset.X, mouse.Y - offset.Y );
            #endregion // Commented Out
        }
    }
}

-------------------------------------------------------------------------------------------------------------------------
I have tested the drag drop of nearly 10,000 items from one listview to another and it was excellent(milliseconds).
There are some things that i want to say:
1)If u want to this to work for all SelectionModes,U'll will to do some changes or better to checks before using selectedItems property.

2)The dragDrop between listviews will function when the two controls have same itemType(T) as the observableCollection type.
For any other type,U'll have do some little more coding .:P

3)The reason for ICloneable Interface is because if u drag and drop one item two or more times to another listview,And then select that item in the other listview,U'll get some annoying behaviour of selection.
To Overcome that,I have used IConeable Interface for the meanwhile..

If u have any questions regarding this code or feedback,u r most welcome.

And do let me know if u think to make it more graceful and well written code in near future,becoz I'll have time to work on this after 1-2 months only... hopefully....:)


Posted on Monday, March 2, 2009 5:46 PM .Net , WPF , Fun , C# | Back to top


Comments on this post: ListView DragDrop in WPF,multiselect

# re: ListView DragDrop in WPF,multiselect
Requesting Gravatar...
Hi

Do you by any chance have a sample of a Clonable observableCollection for use with the listview

regards

ed
Left by ed Keane on Nov 03, 2009 11:18 PM

# re: ListView DragDrop in WPF,multiselect
Requesting Gravatar...
Hello!
Thanks for article!
But do you have demo project?
Left by Artyom on Nov 12, 2009 3:35 AM

# re: ListView DragDrop in WPF,multiselect
Requesting Gravatar...
Hey Do you have any Idea why I am getting this exception
on this code execution as
DragDrop.DoDragDrop()

An exception of type 'System.Security.SecurityException' occurred in mscorlib.dll but was not handled in user code

I am newbie for WPF

Trying to use drag drop from any object on webpage to my container which is a rectangle

Can you please share your views on this...
Left by Swapnil on Nov 17, 2009 2:28 AM

# re: ListView DragDrop in WPF,multiselect
Requesting Gravatar...
@swapnil
WebPage?XBAPS?
This was meant for standalone apps..YOu can see the download link.
Left by sonam on Nov 17, 2009 5:43 AM

# re: ListView DragDrop in WPF,multiselect
Requesting Gravatar...
I have just finish to write a drag and drop list view demo with M-V-VM, multi select and thumbnails,...Open Source code is in the site www.bratched.com. Thanks for your post
Left by Bracthed on May 04, 2010 9:40 AM

# re: ListView DragDrop in WPF,multiselect
Requesting Gravatar...
I would like the demo file that you show in your link, but I cannot download it.

Your link:

http://www.rapidshare.com/files/306026760/Listview.zip.html

Can you send it to me?

Thanks!
Left by Chris on Dec 15, 2015 9:31 PM

Your comment:
 (will show your gravatar)


Copyright © sonam | Powered by: GeeksWithBlogs.net