|
Hi,
i have tested the improved ListView and it works nice.
But if i set the HeaderStyle of the Listview to "None" for a detail ListVIew,
the Scrolling down while drag an item works, the scrolling up dont.
Its reproducible with the demo code.
|
|
|
|
|
Yes, that and I think while dragging down, the line should go below the item so you can see which two items that the new item will be between. Your problem I could fix by hiding the headers under a button(which works fine because I wanted the list up tight under the button anyway). As for mine I set the line to transparent.
|
|
|
|
|
Hello, this has been asked before in the forum but we would like to use this example in our code but the license is not specified. Can you please advise how this example code is licensed and if we are able to use it in a product? Thanks.
|
|
|
|
|
Many thanks you save me from headache! 
|
|
|
|
|
|
Thank you so much for this article, Can someone please help me with some new feature to add to this and make it aweosome: Adding Double Click support to this. So users be able to move items also by double-clicking on them.
Thanks all.
|
|
|
|
|
Great article, thank you for sharing it But still one annoying thing:
when we want to drag-drop between too list views, while the item is being dragged the line indicator JUMPS to the last item of the drag source... How can we prevent it from doing this jump?
|
|
|
|
|
Hi, thanks for this control!
But i have a question - how to get a name of listview item (that was dragged) from target listview?
Thanks.
|
|
|
|
|
I too would like to use this code in commercial software. What are your terms for licensing?
|
|
|
|
|
Hello!
I'm trying to use the DragNDropListView for a data-driven list. Since there is no key property for a ListViewItem like you might find in a dropdown listbox, I need to store the underlying data key in some other property. I've been saving it in either the Tag or Name property of each item.
However, when using the DragNDropListView control, after dragging an item, it's tag and name properties are blank. I have looked through the source code at where items are created, and my only guess is that when it inserts items back into the listview after a drag, only the textual identifier of the ListViewItem is retained. I've tried to set the .tag and .name properties of the item before it is inserted, but to no avail.
Can anyone make a recommendation on how to tweak the code so that my underlying data key is retained through a drag-drop operation?
Rich Gunther
rich@ovostudios.com
|
|
|
|
|
For anyone who is interested in the answer to my question
I did some experimentation with the code underlying the DragAndDrop list, and found a way to ensure that at least the Name property of each ListViewItem persists through a drag-reorder. What I changed in the code is probably overkill: I explicitly set the Name property, cloned each ListViewItem instead of simply doing an add, and used the Items.Add constructor that specifies the name of the ListViewItem. It's important to do this both when you gather the dragItems in GetDataForDragDrop, as well as in the onDragDrop event (both for the insert and add portions).
If you use a listview to display a textual identifier underlaid by a unique data key, this is a great way to implement it.
I've tested this, and it does indeed retain the Name properties of each ListViewItem. Here is the edited code:
using System;
using System.Drawing;
using System.Collections;
using System.Windows.Forms;
using System.ComponentModel;
namespace DragNDrop
{
public class DragAndDropListView : ListView
{
#region Private Members
private ListViewItem m_previousItem;
private bool m_allowReorder;
private Color m_lineColor;
#endregion
#region Public Properties
[Category("Behavior")]
public bool AllowReorder
{
get { return m_allowReorder; }
set { m_allowReorder = value; }
}
[Category("Appearance")]
public Color LineColor
{
get { return m_lineColor; }
set { m_lineColor = value; }
}
#endregion
#region Protected and Public Methods
public DragAndDropListView() : base()
{
m_allowReorder = true;
m_lineColor = Color.Red;
}
protected override void OnDragDrop(DragEventArgs drgevent)
{
if(!m_allowReorder)
{
base.OnDragDrop(drgevent);
return;
}
// get the currently hovered row that the items will be dragged to
Point clientPoint = base.PointToClient(new Point(drgevent.X, drgevent.Y));
ListViewItem hoverItem = base.GetItemAt(clientPoint.X, clientPoint.Y);
if(!drgevent.Data.GetDataPresent(typeof(DragItemData).ToString()) || ((DragItemData) drgevent.Data.GetData(typeof(DragItemData).ToString())).ListView == null || ((DragItemData) drgevent.Data.GetData(typeof(DragItemData).ToString())).DragItems.Count == 0)
return;
// retrieve the drag item data
DragItemData data = (DragItemData) drgevent.Data.GetData(typeof(DragItemData).ToString());
if(hoverItem == null)
{
// the user does not wish to re-order the items, just append to the end
for(int i=0; i<data.dragitems.count; i++)<br="" mode="hold"> {
ListViewItem newItem = (ListViewItem)((ListViewItem)data.DragItems[i]).Clone();
newItem.Name = ((ListViewItem)data.DragItems[i]).Name;
base.Items.Add(newItem.Name, newItem.Text, "");
}
}
else
{
// the user wishes to re-order the items
// get the index of the hover item
int hoverIndex = hoverItem.Index;
// determine if the items to be dropped are from
// this list view. If they are, perform a hack
// to increment the hover index so that the items
// get moved properly.
if(this == data.ListView)
{
if(hoverIndex > base.SelectedItems[0].Index)
hoverIndex++;
}
// insert the new items into the list view
// by inserting the items reversely from the array list
for(int i=data.DragItems.Count - 1; i >= 0; i--)
{
ListViewItem newItem = (ListViewItem) ((ListViewItem) data.DragItems[i]).Clone();
newItem.Name = ((ListViewItem)data.DragItems[i]).Name;
base.Items.Insert(hoverIndex, newItem);
}
}
// remove all the selected items from the previous list view
// if the list view was found
if(data.ListView != null)
{
foreach(ListViewItem itemToRemove in data.ListView.SelectedItems)
{
data.ListView.Items.Remove(itemToRemove);
}
}
// set the back color of the previous item, then nullify it
if(m_previousItem != null)
{
m_previousItem = null;
}
this.Invalidate();
// call the base on drag drop to raise the event
base.OnDragDrop (drgevent);
}
protected override void OnDragOver(DragEventArgs drgevent)
{
if(!m_allowReorder)
{
base.OnDragOver(drgevent);
return;
}
if(!drgevent.Data.GetDataPresent(typeof(DragItemData).ToString()))
{
// the item(s) being dragged do not have any data associated
drgevent.Effect = DragDropEffects.None;
return;
}
if(base.Items.Count > 0)
{
// get the currently hovered row that the items will be dragged to
Point clientPoint = base.PointToClient(new Point(drgevent.X, drgevent.Y));
ListViewItem hoverItem = base.GetItemAt(clientPoint.X, clientPoint.Y);
Graphics g = this.CreateGraphics();
if(hoverItem == null)
{
//MessageBox.Show(base.GetChildAtPoint(new Point(clientPoint.X, clientPoint.Y)).GetType().ToString());
// no item was found, so no drop should take place
drgevent.Effect = DragDropEffects.Move;
if(m_previousItem != null)
{
m_previousItem = null;
Invalidate();
}
hoverItem = base.Items[base.Items.Count - 1];
if(this.View == View.Details || this.View == View.List)
{
g.DrawLine(new Pen(m_lineColor, 2), new Point(hoverItem.Bounds.X, hoverItem.Bounds.Y + hoverItem.Bounds.Height), new Point(hoverItem.Bounds.X + this.Bounds.Width, hoverItem.Bounds.Y + hoverItem.Bounds.Height));
g.FillPolygon(new SolidBrush(m_lineColor), new Point[] {new Point(hoverItem.Bounds.X, hoverItem.Bounds.Y + hoverItem.Bounds.Height - 5), new Point(hoverItem.Bounds.X + 5, hoverItem.Bounds.Y + hoverItem.Bounds.Height), new Point(hoverItem.Bounds.X, hoverItem.Bounds.Y + hoverItem.Bounds.Height + 5)});
g.FillPolygon(new SolidBrush(m_lineColor), new Point[] {new Point(this.Bounds.Width - 4, hoverItem.Bounds.Y + hoverItem.Bounds.Height - 5), new Point(this.Bounds.Width - 9, hoverItem.Bounds.Y + hoverItem.Bounds.Height), new Point(this.Bounds.Width - 4, hoverItem.Bounds.Y + hoverItem.Bounds.Height + 5)});
}
else
{
g.DrawLine(new Pen(m_lineColor, 2), new Point(hoverItem.Bounds.X + hoverItem.Bounds.Width, hoverItem.Bounds.Y), new Point(hoverItem.Bounds.X + hoverItem.Bounds.Width, hoverItem.Bounds.Y + hoverItem.Bounds.Height));
g.FillPolygon(new SolidBrush(m_lineColor), new Point[] {new Point(hoverItem.Bounds.X + hoverItem.Bounds.Width - 5, hoverItem.Bounds.Y), new Point(hoverItem.Bounds.X + hoverItem.Bounds.Width + 5, hoverItem.Bounds.Y), new Point(hoverItem.Bounds.X + hoverItem.Bounds.Width, hoverItem.Bounds.Y + 5)});
g.FillPolygon(new SolidBrush(m_lineColor), new Point[] {new Point(hoverItem.Bounds.X + hoverItem.Bounds.Width - 5, hoverItem.Bounds.Y + hoverItem.Bounds.Height), new Point(hoverItem.Bounds.X + hoverItem.Bounds.Width + 5, hoverItem.Bounds.Y + hoverItem.Bounds.Height), new Point(hoverItem.Bounds.X + hoverItem.Bounds.Width, hoverItem.Bounds.Y + hoverItem.Bounds.Height - 5)});
}
// call the base OnDragOver event
base.OnDragOver(drgevent);
return;
}
// determine if the user is currently hovering over a new
// item. If so, set the previous item's back color back
// to the default color.
if((m_previousItem != null && m_previousItem != hoverItem) || m_previousItem == null)
{
this.Invalidate();
}
// set the background color of the item being hovered
// and assign the previous item to the item being hovered
//hoverItem.BackColor = Color.Beige;
m_previousItem = hoverItem;
if(this.View == View.Details || this.View == View.List)
{
g.DrawLine(new Pen(m_lineColor, 2), new Point(hoverItem.Bounds.X, hoverItem.Bounds.Y), new Point(hoverItem.Bounds.X + this.Bounds.Width, hoverItem.Bounds.Y));
g.FillPolygon(new SolidBrush(m_lineColor), new Point[] {new Point(hoverItem.Bounds.X, hoverItem.Bounds.Y - 5), new Point(hoverItem.Bounds.X + 5, hoverItem.Bounds.Y), new Point(hoverItem.Bounds.X, hoverItem.Bounds.Y + 5)});
g.FillPolygon(new SolidBrush(m_lineColor), new Point[] {new Point(this.Bounds.Width - 4, hoverItem.Bounds.Y - 5), new Point(this.Bounds.Width - 9, hoverItem.Bounds.Y), new Point(this.Bounds.Width - 4, hoverItem.Bounds.Y + 5)});
}
else
{
g.DrawLine(new Pen(m_lineColor, 2), new Point(hoverItem.Bounds.X, hoverItem.Bounds.Y), new Point(hoverItem.Bounds.X, hoverItem.Bounds.Y + hoverItem.Bounds.Height));
g.FillPolygon(new SolidBrush(m_lineColor), new Point[] {new Point(hoverItem.Bounds.X - 5, hoverItem.Bounds.Y), new Point(hoverItem.Bounds.X + 5, hoverItem.Bounds.Y), new Point(hoverItem.Bounds.X, hoverItem.Bounds.Y + 5)});
g.FillPolygon(new SolidBrush(m_lineColor), new Point[] {new Point(hoverItem.Bounds.X - 5, hoverItem.Bounds.Y + hoverItem.Bounds.Height), new Point(hoverItem.Bounds.X + 5, hoverItem.Bounds.Y + hoverItem.Bounds.Height), new Point(hoverItem.Bounds.X, hoverItem.Bounds.Y + hoverItem.Bounds.Height - 5)});
}
// go through each of the selected items, and if any of the
// selected items have the same index as the item being
// hovered, disable dropping.
foreach(ListViewItem itemToMove in base.SelectedItems)
{
if(itemToMove.Index == hoverItem.Index)
{
drgevent.Effect = DragDropEffects.None;
hoverItem.EnsureVisible();
return;
}
}
// ensure that the hover item is visible
hoverItem.EnsureVisible();
}
// everything is fine, allow the user to move the items
drgevent.Effect = DragDropEffects.Move;
// call the base OnDragOver event
base.OnDragOver(drgevent);
}
protected override void OnDragEnter(DragEventArgs drgevent)
{
if(!m_allowReorder)
{
base.OnDragEnter(drgevent);
return;
}
if(!drgevent.Data.GetDataPresent(typeof(DragItemData).ToString()))
{
// the item(s) being dragged do not have any data associated
drgevent.Effect = DragDropEffects.None;
return;
}
// everything is fine, allow the user to move the items
drgevent.Effect = DragDropEffects.Move;
// call the base OnDragEnter event
base.OnDragEnter(drgevent);
}
protected override void OnItemDrag(ItemDragEventArgs e)
{
if(!m_allowReorder)
{
base.OnItemDrag(e);
return;
}
// call the DoDragDrop method
base.DoDragDrop(GetDataForDragDrop(), DragDropEffects.Move);
// call the base OnItemDrag event
base.OnItemDrag(e);
}
protected override void OnLostFocus(EventArgs e)
{
// reset the selected items background and remove the previous item
ResetOutOfRange();
Invalidate();
// call the OnLostFocus event
base.OnLostFocus(e);
}
protected override void OnDragLeave(EventArgs e)
{
// reset the selected items background and remove the previous item
ResetOutOfRange();
Invalidate();
// call the base OnDragLeave event
base.OnDragLeave(e);
}
#endregion
#region Private Methods
private DragItemData GetDataForDragDrop()
{
// create a drag item data object that will be used to pass along with the drag and drop
DragItemData data = new DragItemData(this);
// go through each of the selected items and
// add them to the drag items collection
// by creating a clone of the list item
foreach(ListViewItem item in this.SelectedItems)
{
ListViewItem newItem = (ListViewItem)item.Clone();
newItem.Name = item.Name;
data.DragItems.Add(newItem);
}
return data;
}
private void ResetOutOfRange()
{
// determine if the previous item exists,
// if it does, reset the background and release
// the previous item
if(m_previousItem != null)
{
m_previousItem = null;
}
}
#endregion
#region DragItemData Class
private class DragItemData
{
#region Private Members
private DragAndDropListView m_listView;
private ArrayList m_dragItems;
#endregion
#region Public Properties
public DragAndDropListView ListView
{
get { return m_listView; }
}
public ArrayList DragItems
{
get { return m_dragItems; }
}
#endregion
#region Public Methods and Implementation
public DragItemData(DragAndDropListView listView)
{
m_listView = listView;
m_dragItems = new ArrayList();
}
#endregion
}
#endregion
}
}
|
|
|
|
|
I was recieving a jumping of the selector when dragging downward. This appeared to be related to the dragging over the horizontal scrollbar. I fixed this by detecting if the jump should be applied or not (not tested for multiple listviews)
private const int WS_HSCROLL = 0x100000;
private const int GWL_STYLE = (-16);
[DllImport("user32", CharSet=CharSet.Auto)]
private static extern int GetWindowLong(IntPtr hwnd, int nIndex);
private bool IsHorizontalScrollBarVisible()
{
if (!this.IsHandleCreated)
return false;
return (GetWindowLong(this.Handle, GWL_STYLE) & WS_HSCROLL) != 0;
}
will detect if the scrollbar is present, and in OnDragOver() before the call to CreateGraphics
if( hoverItem == null )
{
if ( IsHorizontalScrollBarVisible() )
{
// added 2 px to scrollbar to avoid jump in gutter
hoverItem = base.GetItemAt(clientPoint.X, clientPoint.Y -
SystemInformation.HorizontalScrollBarHeight + 2 );
if( hoverItem != null )
{
if ( hoverItem.Index == this.Items.Count - 1 )
{
// found the last one, we want to drop at the bottom
hoverItem = null;
}
else
{
this.EnsureVisible( hoverItem.Index + 1 );
}
}
}
}
This works for horizontal scrollbar visible or not, with arbritrary vertical scrollbar.
Additionally I found the dragging down counter intuitive as it dropped an item 2 nodes below instead of "in the middle" where the selector was (due to the line being at the top of each node). I therefore took out the code below from OnDragDrop()
// determine if the items to be dropped are from
// this list view. If they are, perform a hack
// to increment the hover index so that the items
// get moved properly.
// if(this == data.ListView)
// {
// if(hoverIndex > base.SelectedItems[0].Index)
// hoverIndex++;
//}
Please note these alterations are not tested on multiple list boxes
|
|
|
|
|
Hi
Thanks for creating such an useful control.
I have come across a serious problem while using it.
it works fine until the sorting property is set to none.but when i change it to ascending or descending,the drag and drop WITHIN the same listview does not work.
i works fine if i drag an item from one list view and drop it to another.
Anyone has the solution ? pls reply
modified on Monday, February 11, 2008 6:09 AM
|
|
|
|
|
When the horizontal scroll bar is visible and the display rectangle for the listview is a couple of pixles smaller than N complete items, you cannot drag an item down the list...
To fix this you need to add an extra if statement to the OnDragOver() method. Add the following after the call to GetItemAt(clientPoint.X, clientPoint.Y) but before CreateGraphics().
<code>
// If we are trying to scroll down, we might be stuck on the horizontal scroll bar, get the
// item and scroll the next item into view.
if( hoverItem == null )
{
hoverItem = base.GetItemAt(clientPoint.X, clientPoint.Y - SystemInformation.HorizontalScrollBarHeight );
if( hoverItem != null )
{
this.EnsureVisible( hoverItem.Index + 1 );
}
}
</code>
|
|
|
|
|
It took me to convert to VB about 3hs+, I'm newbie and think that this can help someone (I used some tools to convert the code but none of those work well, then I manually translate the code...)
Imports System<br />
Imports System.Drawing<br />
Imports System.Collections<br />
Imports System.Windows.Forms<br />
Imports System.ComponentModel<br />
<br />
namespace DragNDrop<br />
<br />
Public Class DragAndDropListView<br />
Inherits ListView<br />
<br />
#Region "Private Members"<br />
Private m_previousItem As ListViewItem<br />
Private m_allowReorder As Boolean<br />
Private m_lineColor As Color<br />
#End Region<br />
<br />
#Region "Public Properties"<br />
<br />
<Category("Behavior")> _<br />
Public Property AllowReorder() As Boolean<br />
Get<br />
Return m_allowReorder<br />
End Get<br />
Set(ByVal value As Boolean)<br />
m_allowReorder = value<br />
End Set<br />
End Property<br />
<br />
<Category("Appearance")> _<br />
Public Property LineColor() As Color<br />
Get<br />
Return m_lineColor<br />
End Get<br />
Set(ByVal value As Color)<br />
m_lineColor = value<br />
End Set<br />
End Property<br />
#End Region<br />
<br />
#Region "Protected and Public Methods"<br />
Public Sub New()<br />
MyBase.New()<br />
m_allowReorder = True<br />
m_lineColor = Color.Red<br />
<br />
'Me.FullRowSelect = False<br />
End Sub<br />
<br />
Protected Overrides Sub OnDragDrop(ByVal drgevent As DragEventArgs)<br />
If Not m_allowReorder Then<br />
MyBase.OnDragDrop(drgevent)<br />
Return<br />
End If<br />
<br />
' get the currently hovered row that the items will be dragged to<br />
Dim clientPoint As Point = MyBase.PointToClient(New Point(drgevent.X, drgevent.Y))<br />
Dim hoverItem As ListViewItem = MyBase.GetItemAt(clientPoint.X, clientPoint.Y)<br />
<br />
If Not drgevent.Data.GetDataPresent(GetType(DragItemData).ToString()) OrElse _<br />
(CType(drgevent.Data.GetData(GetType(DragItemData).ToString()), DragItemData)).ListView Is Nothing OrElse _<br />
(CType(drgevent.Data.GetData(GetType(DragItemData).ToString()), DragItemData)).DragItems.Count = 0 Then Return<br />
<br />
'retrieve the drag item data<br />
Dim data As DragItemData = CType(drgevent.Data.GetData(GetType(DragItemData).ToString()), DragItemData)<br />
<br />
If hoverItem Is Nothing Then<br />
'the user does not wish to re-order the items, just append to the end<br />
For i As Integer = 0 To data.DragItems.Count - 1<br />
Dim newItem As ListViewItem = CType(data.DragItems(i), ListViewItem)<br />
MyBase.Items.Add(newItem)<br />
Next<br />
Else<br />
' the user wishes to re-order the items<br />
<br />
' get the index of the hover item<br />
Dim hoverIndex As Integer = hoverItem.Index<br />
<br />
' determine if the items to be dropped are from<br />
' this list view. If they are, perform a hack<br />
' to increment the hover index so that the items<br />
' get moved properly.<br />
If Me Is data.ListView Then<br />
If hoverIndex > MyBase.SelectedItems(0).Index Then<br />
hoverIndex += 1<br />
End If<br />
End If<br />
' insert the new items into the list view<br />
' by inserting the items reversely from the array list<br />
For i As Integer = data.DragItems.Count - 1 To 0 Step -1<br />
Dim newItem As ListViewItem = CType(data.DragItems(i), ListViewItem)<br />
MyBase.Items.Insert(hoverIndex, newItem)<br />
Next<br />
End If<br />
<br />
' remove all the selected items from the previous list view<br />
' if the list view was found<br />
If data.ListView IsNot Nothing Then<br />
For Each itemToRemove As ListViewItem In data.ListView.SelectedItems<br />
data.ListView.Items.Remove(itemToRemove)<br />
Next<br />
End If<br />
<br />
' set the back color of the previous item, then nullify it<br />
If m_previousItem IsNot Nothing Then<br />
m_previousItem = Nothing<br />
End If<br />
<br />
Me.Invalidate()<br />
<br />
' call the base on drag drop to raise the event<br />
MyBase.OnDragDrop(drgevent)<br />
End Sub<br />
<br />
Protected Overrides Sub OnDragOver(ByVal drgevent As DragEventArgs)<br />
If Not m_allowReorder Then<br />
MyBase.OnDragOver(drgevent)<br />
Return<br />
End If<br />
<br />
If Not drgevent.Data.GetDataPresent(GetType(DragItemData).ToString()) Then<br />
' the item(s) being dragged do not have any data associated<br />
drgevent.Effect = DragDropEffects.None<br />
Return<br />
End If<br />
<br />
If MyBase.Items.Count > 0 Then<br />
' get the currently hovered row that the items will be dragged to<br />
Dim clientPoint As Point = MyBase.PointToClient(New Point(drgevent.X, drgevent.Y))<br />
Dim hoverItem As ListViewItem = MyBase.GetItemAt(clientPoint.X, clientPoint.Y)<br />
<br />
Dim g As Graphics = Me.CreateGraphics()<br />
<br />
If hoverItem Is Nothing Then<br />
<br />
'MessageBox.Show(base.GetChildAtPoint(new Point(clientPoint.X, clientPoint.Y)).GetType().ToString());<br />
<br />
' no item was found, so no drop should take place<br />
drgevent.Effect = DragDropEffects.Move<br />
<br />
If m_previousItem IsNot Nothing Then<br />
m_previousItem = Nothing<br />
Invalidate()<br />
End If<br />
<br />
hoverItem = MyBase.Items(MyBase.Items.Count - 1)<br />
<br />
If Me.View = View.Details OrElse Me.View = View.List Then<br />
g.DrawLine(New Pen(m_lineColor, 2), New Point(hoverItem.Bounds.X, hoverItem.Bounds.Y + hoverItem.Bounds.Height), New Point(hoverItem.Bounds.X + Me.Bounds.Width, hoverItem.Bounds.Y + hoverItem.Bounds.Height))<br />
g.FillPolygon(New SolidBrush(m_lineColor), New Point() {New Point(hoverItem.Bounds.X, hoverItem.Bounds.Y + hoverItem.Bounds.Height - 5), New Point(hoverItem.Bounds.X + 5, hoverItem.Bounds.Y + hoverItem.Bounds.Height), New Point(hoverItem.Bounds.X, hoverItem.Bounds.Y + hoverItem.Bounds.Height + 5)})<br />
g.FillPolygon(New SolidBrush(m_lineColor), New Point() {New Point(Me.Bounds.Width - 4, hoverItem.Bounds.Y + hoverItem.Bounds.Height - 5), New Point(Me.Bounds.Width - 9, hoverItem.Bounds.Y + hoverItem.Bounds.Height), New Point(Me.Bounds.Width - 4, hoverItem.Bounds.Y + hoverItem.Bounds.Height + 5)})<br />
Else<br />
g.DrawLine(New Pen(m_lineColor, 2), New Point(hoverItem.Bounds.X + hoverItem.Bounds.Width, hoverItem.Bounds.Y), New Point(hoverItem.Bounds.X + hoverItem.Bounds.Width, hoverItem.Bounds.Y + hoverItem.Bounds.Height))<br />
g.FillPolygon(New SolidBrush(m_lineColor), New Point() {New Point(hoverItem.Bounds.X + hoverItem.Bounds.Width - 5, hoverItem.Bounds.Y), New Point(hoverItem.Bounds.X + hoverItem.Bounds.Width + 5, hoverItem.Bounds.Y), New Point(hoverItem.Bounds.X + hoverItem.Bounds.Width, hoverItem.Bounds.Y + 5)})<br />
g.FillPolygon(New SolidBrush(m_lineColor), New Point() {New Point(hoverItem.Bounds.X + hoverItem.Bounds.Width - 5, hoverItem.Bounds.Y + hoverItem.Bounds.Height), New Point(hoverItem.Bounds.X + hoverItem.Bounds.Width + 5, hoverItem.Bounds.Y + hoverItem.Bounds.Height), New Point(hoverItem.Bounds.X + hoverItem.Bounds.Width, hoverItem.Bounds.Y + hoverItem.Bounds.Height - 5)})<br />
End If<br />
<br />
' call the base OnDragOver event<br />
MyBase.OnDragOver(drgevent)<br />
<br />
Return<br />
End If<br />
<br />
' determine if the user is currently hovering over a new<br />
' item. If so, set the previous item's back color back<br />
' to the default color.<br />
If (m_previousItem IsNot Nothing AndAlso m_previousItem IsNot hoverItem) OrElse m_previousItem Is Nothing Then<br />
Me.Invalidate()<br />
End If<br />
<br />
' set the background color of the item being hovered<br />
' and assign the previous item to the item being hovered<br />
'hoverItem.BackColor = Color.Beige;<br />
m_previousItem = hoverItem<br />
<br />
If Me.View = View.Details OrElse Me.View = View.List Then<br />
g.DrawLine(New Pen(m_lineColor, 2), New Point(hoverItem.Bounds.X, hoverItem.Bounds.Y), New Point(hoverItem.Bounds.X + Me.Bounds.Width, hoverItem.Bounds.Y))<br />
g.FillPolygon(New SolidBrush(m_lineColor), New Point() {New Point(hoverItem.Bounds.X, hoverItem.Bounds.Y - 5), New Point(hoverItem.Bounds.X + 5, hoverItem.Bounds.Y), New Point(hoverItem.Bounds.X, hoverItem.Bounds.Y + 5)})<br />
g.FillPolygon(New SolidBrush(m_lineColor), New Point() {New Point(Me.Bounds.Width - 4, hoverItem.Bounds.Y - 5), New Point(Me.Bounds.Width - 9, hoverItem.Bounds.Y), New Point(Me.Bounds.Width - 4, hoverItem.Bounds.Y + 5)})<br />
Else<br />
g.DrawLine(New Pen(m_lineColor, 2), New Point(hoverItem.Bounds.X, hoverItem.Bounds.Y), New Point(hoverItem.Bounds.X, hoverItem.Bounds.Y + hoverItem.Bounds.Height))<br />
g.FillPolygon(New SolidBrush(m_lineColor), New Point() {New Point(hoverItem.Bounds.X - 5, hoverItem.Bounds.Y), New Point(hoverItem.Bounds.X + 5, hoverItem.Bounds.Y), New Point(hoverItem.Bounds.X, hoverItem.Bounds.Y + 5)})<br />
g.FillPolygon(New SolidBrush(m_lineColor), New Point() {New Point(hoverItem.Bounds.X - 5, hoverItem.Bounds.Y + hoverItem.Bounds.Height), New Point(hoverItem.Bounds.X + 5, hoverItem.Bounds.Y + hoverItem.Bounds.Height), New Point(hoverItem.Bounds.X, hoverItem.Bounds.Y + hoverItem.Bounds.Height - 5)})<br />
' go through each of the selected items, and if any of the<br />
' selected items have the same index as the item being<br />
' hovered, disable dropping.<br />
<br />
For Each itemToMove As ListViewItem In MyBase.SelectedItems<br />
If itemToMove.Index = hoverItem.Index Then<br />
drgevent.Effect = DragDropEffects.None<br />
hoverItem.EnsureVisible()<br />
Return<br />
End If<br />
Next<br />
End If<br />
' ensure that the hover item is visible<br />
hoverItem.EnsureVisible()<br />
End If<br />
<br />
' everything is fine, allow the user to move the items<br />
drgevent.Effect = DragDropEffects.Move<br />
<br />
' call the base OnDragOver event<br />
MyBase.OnDragOver(drgevent)<br />
End Sub<br />
<br />
Protected Overrides Sub OnDragEnter(ByVal drgevent As DragEventArgs)<br />
If Not m_allowReorder Then<br />
MyBase.OnDragEnter(drgevent)<br />
Return<br />
End If<br />
<br />
If Not drgevent.Data.GetDataPresent(GetType(DragItemData).ToString()) Then<br />
' the item(s) being dragged do not have any data associated<br />
drgevent.Effect = DragDropEffects.None<br />
Return<br />
<br />
End If<br />
<br />
' everything is fine, allow the user to move the items<br />
drgevent.Effect = DragDropEffects.Move<br />
<br />
' call the base OnDragEnter event<br />
MyBase.OnDragEnter(drgevent)<br />
<br />
End Sub<br />
<br />
Protected Overrides Sub OnItemDrag(ByVal e As ItemDragEventArgs)<br />
If Not m_allowReorder Then<br />
MyBase.OnItemDrag(e)<br />
Return<br />
End If<br />
<br />
' call the DoDragDrop method<br />
MyBase.DoDragDrop(GetDataForDragDrop(), DragDropEffects.Move)<br />
<br />
' call the base OnItemDrag event<br />
MyBase.OnItemDrag(e)<br />
End Sub<br />
<br />
Protected Overrides Sub OnLostFocus(ByVal e As EventArgs)<br />
' reset the selected items background and remove the previous item<br />
ResetOutOfRange()<br />
<br />
Invalidate()<br />
<br />
' call the OnLostFocus event<br />
MyBase.OnLostFocus(e)<br />
End Sub<br />
<br />
Protected Overrides Sub OnDragLeave(ByVal e As EventArgs)<br />
' reset the selected items background and remove the previous item<br />
ResetOutOfRange()<br />
<br />
Invalidate()<br />
<br />
' call the base OnDragLeave event<br />
MyBase.OnDragLeave(e)<br />
End Sub<br />
<br />
#Region "Private Methods"<br />
Private Function GetDataForDragDrop() As DragItemData<br />
' create a drag item data object that will be used to pass along with the drag and drop<br />
Dim data As DragItemData = New DragItemData(Me)<br />
<br />
' go through each of the selected items and <br />
' add them to the drag items collection<br />
' by creating a clone of the list item<br />
<br />
For Each item As ListViewItem In Me.SelectedItems<br />
data.DragItems.Add(item.Clone())<br />
Next<br />
<br />
Return data<br />
End Function<br />
<br />
Private Sub ResetOutOfRange()<br />
' determine if the previous item exists,<br />
' if it does, reset the background and release <br />
' the previous item<br />
If m_previousItem IsNot Nothing Then<br />
m_previousItem = Nothing<br />
End If<br />
End Sub<br />
<br />
#End Region<br />
<br />
<br />
#End Region<br />
<br />
#Region "DragItemData Class"<br />
Private Class DragItemData<br />
<br />
#Region "Private Members"<br />
Private m_listView As DragAndDropListView<br />
Private m_dragItems As ArrayList<br />
#End Region<br />
<br />
#Region "Public Properties"<br />
<br />
Public ReadOnly Property ListView() As DragAndDropListView<br />
Get<br />
Return m_listView<br />
End Get<br />
End Property<br />
<br />
Public ReadOnly Property DragItems() As ArrayList<br />
Get<br />
Return m_dragItems<br />
End Get<br />
End Property<br />
<br />
#End Region<br />
<br />
#Region "Public Methods and Implementation"<br />
Public Sub New(ByVal listView As DragAndDropListView)<br />
m_listView = listView<br />
m_dragItems = New ArrayList()<br />
End Sub<br />
#End Region<br />
<br />
End Class<br />
#End Region<br />
<br />
End Class<br />
<br />
END NAMESPACE
|
|
|
|
|
It works very well but in LargeIcon or SmallIcon
I do some fix in DragAndDropListView.cs as below
using System;<br />
using System.Drawing;<br />
using System.Collections;<br />
using System.Windows.Forms;<br />
using System.ComponentModel;<br />
<br />
namespace DragNDrop<br />
{<br />
public class DragAndDropListView : ListView<br />
{<br />
#region Private Members<br />
<br />
private ListViewItem m_previousItem;<br />
private bool m_allowReorder;<br />
private Color m_lineColor;<br />
<br />
#endregion<br />
<br />
#region Public Properties<br />
<br />
[Category("Behavior")]<br />
public bool AllowReorder<br />
{<br />
get { return m_allowReorder; }<br />
set { m_allowReorder = value; }<br />
}<br />
<br />
[Category("Appearance")]<br />
public Color LineColor<br />
{<br />
get { return m_lineColor; }<br />
set { m_lineColor = value; }<br />
}<br />
<br />
#endregion<br />
<br />
#region Protected and Public Methods<br />
<br />
public DragAndDropListView()<br />
: base()<br />
{<br />
m_allowReorder = true;<br />
m_lineColor = Color.Black;<br />
}<br />
<br />
protected override void OnDragDrop(DragEventArgs drgevent)<br />
{<br />
if (!m_allowReorder)<br />
{<br />
base.OnDragDrop(drgevent);<br />
return;<br />
}<br />
<br />
Point clientPoint = base.PointToClient(new Point(drgevent.X, drgevent.Y));<br />
ListViewItem hoverItem = base.GetItemAt(clientPoint.X, clientPoint.Y);<br />
<br />
if (!drgevent.Data.GetDataPresent(typeof(DragItemData).ToString()) || ((DragItemData)drgevent.Data.GetData(typeof(DragItemData).ToString())).ListView == null || ((DragItemData)drgevent.Data.GetData(typeof(DragItemData).ToString())).DragItems.Count == 0)<br />
return;<br />
<br />
DragItemData data = (DragItemData)drgevent.Data.GetData(typeof(DragItemData).ToString());<br />
<br />
if (hoverItem == null)<br />
{<br />
for (int i = 0; i < data.DragItems.Count; i++)<br />
{<br />
ListViewItem newItem = (ListViewItem)data.DragItems[i];<br />
base.Items.Add(newItem);<br />
}<br />
}<br />
else<br />
{<br />
<br />
int hoverIndex = hoverItem.Index;<br />
<br />
if (this == data.ListView)<br />
{<br />
if (base.SelectedItems[0].Index <= hoverIndex && hoverIndex <= base.SelectedItems[base.SelectedItems.Count - 1].Index + 1)<br />
{<br />
if (m_previousItem != null)<br />
{<br />
m_previousItem = null;<br />
}<br />
<br />
this.Invalidate();<br />
<br />
base.OnDragDrop(drgevent);<br />
return;<br />
}<br />
}<br />
<br />
for (int i = data.DragItems.Count - 1; i >= 0; i--)<br />
{<br />
ListViewItem newItem = (ListViewItem)data.DragItems[i];<br />
base.Items.Insert(hoverIndex, newItem);<br />
base.Items[hoverIndex].Position = base.Items[hoverIndex + 1].Position;<br />
}<br />
}<br />
<br />
if (data.ListView != null)<br />
{<br />
foreach (ListViewItem itemToRemove in data.ListView.SelectedItems)<br />
{<br />
data.ListView.Items.Remove(itemToRemove);<br />
}<br />
}<br />
<br />
this.Refresh();<br />
if (m_previousItem != null)<br />
{<br />
m_previousItem = null;<br />
}<br />
<br />
this.Invalidate();<br />
<br />
base.OnDragDrop(drgevent);<br />
}<br />
<br />
protected override void OnDragOver(DragEventArgs drgevent)<br />
{<br />
if (!m_allowReorder)<br />
{<br />
base.OnDragOver(drgevent);<br />
return;<br />
}<br />
<br />
if (!drgevent.Data.GetDataPresent(typeof(DragItemData).ToString()))<br />
{<br />
drgevent.Effect = DragDropEffects.None;<br />
return;<br />
}<br />
<br />
if (base.Items.Count > 0)<br />
{<br />
Point clientPoint = base.PointToClient(new Point(drgevent.X, drgevent.Y));<br />
ListViewItem lastItem = base.Items[base.Items.Count - 1];<br />
Point ptLastItem = new Point(lastItem.Bounds.X + lastItem.Bounds.Width + lastItem.Bounds.X, lastItem.Bounds.Y + lastItem.Bounds.Height);<br />
ListViewItem hoverItem = base.GetItemAt(clientPoint.X, clientPoint.Y);<br />
<br />
Graphics g = this.CreateGraphics();<br />
<br />
if (hoverItem == null && (clientPoint.X > ptLastItem.X || clientPoint.Y > ptLastItem.Y))<br />
{<br />
<br />
drgevent.Effect = DragDropEffects.Move;<br />
<br />
if (m_previousItem != null)<br />
{<br />
m_previousItem = null;<br />
Invalidate();<br />
}<br />
<br />
hoverItem = base.Items[base.Items.Count - 1];<br />
<br />
if (this.View == View.Details || this.View == View.List)<br />
{<br />
g.DrawLine(new Pen(m_lineColor, 2), new Point(hoverItem.Bounds.X, hoverItem.Bounds.Y + hoverItem.Bounds.Height), new Point(hoverItem.Bounds.X + this.Bounds.Width, hoverItem.Bounds.Y + hoverItem.Bounds.Height));<br />
}<br />
else<br />
{<br />
g.DrawLine(new Pen(m_lineColor, 2), new Point(hoverItem.Bounds.X + hoverItem.Bounds.Width, hoverItem.Bounds.Y), new Point(hoverItem.Bounds.X + hoverItem.Bounds.Width, hoverItem.Bounds.Y + hoverItem.Bounds.Height));<br />
g.FillPolygon(new SolidBrush(m_lineColor), new Point[] { new Point(hoverItem.Bounds.X + hoverItem.Bounds.Width - 3, hoverItem.Bounds.Y), new Point(hoverItem.Bounds.X + hoverItem.Bounds.Width + 3, hoverItem.Bounds.Y), new Point(hoverItem.Bounds.X + hoverItem.Bounds.Width, hoverItem.Bounds.Y + 3) });<br />
g.FillPolygon(new SolidBrush(m_lineColor), new Point[] { new Point(hoverItem.Bounds.X + hoverItem.Bounds.Width - 4, hoverItem.Bounds.Y + hoverItem.Bounds.Height), new Point(hoverItem.Bounds.X + hoverItem.Bounds.Width + 4, hoverItem.Bounds.Y + hoverItem.Bounds.Height), new Point(hoverItem.Bounds.X + hoverItem.Bounds.Width, hoverItem.Bounds.Y + hoverItem.Bounds.Height - 4) });<br />
}<br />
<br />
base.OnDragOver(drgevent);<br />
<br />
return;<br />
}<br />
<br />
if ((m_previousItem != null && m_previousItem != hoverItem) || m_previousItem == null)<br />
{<br />
this.Invalidate();<br />
}<br />
<br />
m_previousItem = hoverItem;<br />
<br />
if (this.View == View.Details || this.View == View.List)<br />
{<br />
g.DrawLine(new Pen(m_lineColor, 2), new Point(hoverItem.Bounds.X, hoverItem.Bounds.Y), new Point(hoverItem.Bounds.X + this.Bounds.Width, hoverItem.Bounds.Y ));<br />
}<br />
else<br />
{<br />
g.DrawLine(new Pen(m_lineColor, 2), new Point(hoverItem.Bounds.X, hoverItem.Bounds.Y), new Point(hoverItem.Bounds.X, hoverItem.Bounds.Y + hoverItem.Bounds.Height));<br />
g.FillPolygon(new SolidBrush(m_lineColor), new Point[] { new Point(hoverItem.Bounds.X - 3, hoverItem.Bounds.Y), new Point(hoverItem.Bounds.X + 3, hoverItem.Bounds.Y), new Point(hoverItem.Bounds.X, hoverItem.Bounds.Y + 3) });<br />
g.FillPolygon(new SolidBrush(m_lineColor), new Point[] { new Point(hoverItem.Bounds.X - 4, hoverItem.Bounds.Y + hoverItem.Bounds.Height), new Point(hoverItem.Bounds.X + 4, hoverItem.Bounds.Y + hoverItem.Bounds.Height), new Point(hoverItem.Bounds.X, hoverItem.Bounds.Y + hoverItem.Bounds.Height - 4) });<br />
}<br />
<br />
foreach (ListViewItem itemToMove in base.SelectedItems)<br />
{<br />
if (itemToMove.Index == hoverItem.Index)<br />
{<br />
drgevent.Effect = DragDropEffects.None;<br />
hoverItem.EnsureVisible();<br />
return;<br />
}<br />
}<br />
<br />
hoverItem.EnsureVisible();<br />
}<br />
<br />
drgevent.Effect = DragDropEffects.Move;<br />
<br />
base.OnDragOver(drgevent);<br />
}<br />
<br />
protected override void OnDragEnter(DragEventArgs drgevent)<br />
{<br />
if (!m_allowReorder)<br />
{<br />
base.OnDragEnter(drgevent);<br />
return;<br />
}<br />
<br />
if (!drgevent.Data.GetDataPresent(typeof(DragItemData).ToString()))<br />
{<br />
drgevent.Effect = DragDropEffects.None;<br />
return;<br />
}<br />
<br />
drgevent.Effect = DragDropEffects.Move;<br />
<br />
base.OnDragEnter(drgevent);<br />
}<br />
<br />
protected override void OnItemDrag(ItemDragEventArgs e)<br />
{<br />
if (!m_allowReorder)<br />
{<br />
base.OnItemDrag(e);<br />
return;<br />
}<br />
<br />
base.DoDragDrop(GetDataForDragDrop(), DragDropEffects.Move);<br />
<br />
base.OnItemDrag(e);<br />
}<br />
<br />
protected override void OnLostFocus(EventArgs e)<br />
{<br />
ResetOutOfRange();<br />
<br />
Invalidate();<br />
<br />
base.OnLostFocus(e);<br />
}<br />
<br />
protected override void OnDragLeave(EventArgs e)<br />
{<br />
ResetOutOfRange();<br />
<br />
Invalidate();<br />
<br />
base.OnDragLeave(e);<br />
}<br />
<br />
#endregion<br />
<br />
#region Private Methods<br />
<br />
private DragItemData GetDataForDragDrop()<br />
{<br />
DragItemData data = new DragItemData(this);<br />
<br />
foreach (ListViewItem item in this.SelectedItems)<br />
{<br />
data.DragItems.Add(item.Clone());<br />
}<br />
<br />
return data;<br />
}<br />
<br />
private void ResetOutOfRange()<br />
{<br />
if (m_previousItem != null)<br />
{<br />
m_previousItem = null;<br />
}<br />
<br />
}<br />
<br />
#endregion<br />
<br />
#region DragItemData Class<br />
<br />
private class DragItemData<br />
{<br />
#region Private Members<br />
<br />
private DragAndDropListView m_listView;<br />
private ArrayList m_dragItems;<br />
<br />
#endregion<br />
<br />
#region Public Properties<br />
<br />
public DragAndDropListView ListView<br />
{<br />
get { return m_listView; }<br />
}<br />
<br />
public ArrayList DragItems<br />
{<br />
get { return m_dragItems; }<br />
}<br />
<br />
#endregion<br />
<br />
#region Public Methods and Implementation<br />
<br />
public DragItemData(DragAndDropListView listView)<br />
{<br />
m_listView = listView;<br />
m_dragItems = new ArrayList();<br />
}<br />
<br />
#endregion<br />
}<br />
<br />
#endregion<br />
<br />
private void InitializeComponent()<br />
{<br />
this.SuspendLayout();<br />
this.ResumeLayout(false);<br />
<br />
}<br />
}<br />
}
|
|
|
|
|
Thank you so much for the fix. The control was not working until I switched to this code with large icons. Without this fix the large Icon I was dragging would always move to the bottom.
|
|
|
|
|
Hello!
I am newbie to C#.
The problem is:
I have two Drag and Drop List Views in my form.
1.Dragging and dropping from one list to another should not be allowed.I mean,I should only allow dragging and dropping for List1 elements only in List1. How to do this?
2.Can I dinamically change the List element attributes when the dragged list element is dropped? How to do this?
3.How to sort the List by one element attribute? Currently I am working with XML. So I fetch the data from XML into a List<string[]>, perform sorting by writing own comparer and only after then load the Drag And Drop List View with sorted data. Maybe there is an easier way?
3.How to retrieve current Drag And Drop List View with all elements in order how they are displayed.
Thanks Everyone!
Misha
|
|
|
|
|
Just let me say that I love your code. Good comments and easy to follow.
Now for my question.
I would need to have one of the listviews to have 3rd column (which I can do) with permanent information in it. Such as row 1, row 2 etc.
So as when you drag a selection from one listview (the one with only 2 columns) to the other
(the one with the row count) the row count stays in the first column and the other two are inserted.
GOD, I hope i'm explaining myself correctly... lol I may be long-winded here, just want to make sure someone understands me...
So...
listview #1 has:
list1 | item 1
listview #2 has:
row 1 | <nothing here=""> | <also nothing="">
When dragging from list 1 over to 2 it displays
row 1 | list1 | item1
Hope this is clear.. been busting my back-side over this, would really need some help on this one.
Really...
Thank you for any help..
LoneFerret
Cross my heart, smack me dead...stick a lobster on my head.
|
|
|
|
|
This is a great control and its exactly what i need. Can I use it in comercial code(recognition will be given in the design document)?
|
|
|
|
|
Hi,
When I use your component, and if ListView.View = LargeIcon
then item reorder - did not work.
Any idea to solve this problem ?
|
|
|
|
|
This is exactly what I needed, thanks! Only problem I have is hideous flicker when dragging. I've tried a few different things, but with no success. Any ideas?
|
|
|
|
|
When creating the listview make it doubleBuffered.
|
|
|
|
|
|
Hi,
When I use your component, and if i have setup the image list property.
The image appear on the left of the listviewitem ... and disappear after a drag&drop.
Any idea to solve this problem ?
Didier.
|
|
|
|
|