 |
|
 |
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
|
| Sign In·View Thread·PermaLink | 4.00/5 (1 vote) |
|
|
|
 |
|
 |
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 { 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 } }
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
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
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
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
|
| Sign In·View Thread·PermaLink | 5.00/5 (1 vote) |
|
|
|
 |
|
 |
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>
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
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 Imports System.Drawing Imports System.Collections Imports System.Windows.Forms Imports System.ComponentModel
namespace DragNDrop
Public Class DragAndDropListView Inherits ListView
#Region "Private Members" Private m_previousItem As ListViewItem Private m_allowReorder As Boolean Private m_lineColor As Color #End Region
#Region "Public Properties"
"Behavior")> _ Public Property AllowReorder() As Boolean Get Return m_allowReorder End Get Set(ByVal value As Boolean) m_allowReorder = value End Set End Property
"Appearance")> _ Public Property LineColor() As Color Get Return m_lineColor End Get Set(ByVal value As Color) m_lineColor = value End Set End Property #End Region
#Region "Protected and Public Methods" Public Sub New() MyBase.New() m_allowReorder = True m_lineColor = Color.Red
End Sub
Protected Overrides Sub OnDragDrop(ByVal drgevent As DragEventArgs) If Not m_allowReorder Then MyBase.OnDragDrop(drgevent) Return End If
Dim clientPoint As Point = MyBase.PointToClient(New Point(drgevent.X, drgevent.Y)) Dim hoverItem As ListViewItem = MyBase.GetItemAt(clientPoint.X, clientPoint.Y)
If Not drgevent.Data.GetDataPresent(GetType(DragItemData).ToString()) OrElse _ (CType(drgevent.Data.GetData(GetType(DragItemData).ToString()), DragItemData)).ListView Is Nothing OrElse _ (CType(drgevent.Data.GetData(GetType(DragItemData).ToString()), DragItemData)).DragItems.Count = 0 Then Return
Dim data As DragItemData = CType(drgevent.Data.GetData(GetType(DragItemData).ToString()), DragItemData)
If hoverItem Is Nothing Then For i As Integer = 0 To data.DragItems.Count - 1 Dim newItem As ListViewItem = CType(data.DragItems(i), ListViewItem) MyBase.Items.Add(newItem) Next Else Dim hoverIndex As Integer = hoverItem.Index
If Me Is data.ListView Then If hoverIndex > MyBase.SelectedItems(0).Index Then hoverIndex += 1 End If End If For i As Integer = data.DragItems.Count - 1 To 0 Step -1 Dim newItem As ListViewItem = CType(data.DragItems(i), ListViewItem) MyBase.Items.Insert(hoverIndex, newItem) Next End If
If data.ListView IsNot Nothing Then For Each itemToRemove As ListViewItem In data.ListView.SelectedItems data.ListView.Items.Remove(itemToRemove) Next End If
If m_previousItem IsNot Nothing Then m_previousItem = Nothing End If
Me.Invalidate()
MyBase.OnDragDrop(drgevent) End Sub
Protected Overrides Sub OnDragOver(ByVal drgevent As DragEventArgs) If Not m_allowReorder Then MyBase.OnDragOver(drgevent) Return End If
If Not drgevent.Data.GetDataPresent(GetType(DragItemData).ToString()) Then drgevent.Effect = DragDropEffects.None Return End If
If MyBase.Items.Count > 0 Then Dim clientPoint As Point = MyBase.PointToClient(New Point(drgevent.X, drgevent.Y)) Dim hoverItem As ListViewItem = MyBase.GetItemAt(clientPoint.X, clientPoint.Y)
Dim g As Graphics = Me.CreateGraphics()
If hoverItem Is Nothing Then
drgevent.Effect = DragDropEffects.Move
If m_previousItem IsNot Nothing Then m_previousItem = Nothing Invalidate() End If
hoverItem = MyBase.Items(MyBase.Items.Count - 1)
If Me.View = View.Details OrElse Me.View = View.List Then 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)) 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(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)}) 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)}) End If
MyBase.OnDragOver(drgevent)
Return End If
If (m_previousItem IsNot Nothing AndAlso m_previousItem IsNot hoverItem) OrElse m_previousItem Is Nothing Then Me.Invalidate() End If
m_previousItem = hoverItem
If Me.View = View.Details OrElse Me.View = View.List Then 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)) 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(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)}) 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)}) For Each itemToMove As ListViewItem In MyBase.SelectedItems If itemToMove.Index = hoverItem.Index Then drgevent.Effect = DragDropEffects.None hoverItem.EnsureVisible() Return End If Next End If hoverItem.EnsureVisible() End If
drgevent.Effect = DragDropEffects.Move
MyBase.OnDragOver(drgevent) End Sub
Protected Overrides Sub OnDragEnter(ByVal drgevent As DragEventArgs) If Not m_allowReorder Then MyBase.OnDragEnter(drgevent) Return End If
If Not drgevent.Data.GetDataPresent(GetType(DragItemData).ToString()) Then drgevent.Effect = DragDropEffects.None Return
End If
drgevent.Effect = DragDropEffects.Move
MyBase.OnDragEnter(drgevent)
End Sub
Protected Overrides Sub OnItemDrag(ByVal e As ItemDragEventArgs) If Not m_allowReorder Then MyBase.OnItemDrag(e) Return End If
MyBase.DoDragDrop(GetDataForDragDrop(), DragDropEffects.Move)
MyBase.OnItemDrag(e) End Sub
Protected Overrides Sub OnLostFocus(ByVal e As EventArgs) ResetOutOfRange()
Invalidate()
MyBase.OnLostFocus(e) End Sub
Protected Overrides Sub OnDragLeave(ByVal e As EventArgs) ResetOutOfRange()
Invalidate()
MyBase.OnDragLeave(e) End Sub
#Region "Private Methods" Private Function GetDataForDragDrop() As DragItemData Dim data As DragItemData = New DragItemData(Me)
For Each item As ListViewItem In Me.SelectedItems data.DragItems.Add(item.Clone()) Next
Return data End Function
Private Sub ResetOutOfRange() If m_previousItem IsNot Nothing Then m_previousItem = Nothing End If End Sub
#End Region
#End Region
#Region "DragItemData Class" Private Class DragItemData
#Region "Private Members" Private m_listView As DragAndDropListView Private m_dragItems As ArrayList #End Region
#Region "Public Properties"
Public ReadOnly Property ListView() As DragAndDropListView Get Return m_listView End Get End Property
Public ReadOnly Property DragItems() As ArrayList Get Return m_dragItems End Get End Property
#End Region
#Region "Public Methods and Implementation" Public Sub New(ByVal listView As DragAndDropListView) m_listView = listView m_dragItems = New ArrayList() End Sub #End Region
End Class #End Region
End Class
END NAMESPACE
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
It works very well but in LargeIcon or SmallIcon I do some fix in DragAndDropListView.cs as below
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.Black; }
protected override void OnDragDrop(DragEventArgs drgevent) { if (!m_allowReorder) { base.OnDragDrop(drgevent); return; }
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;
DragItemData data = (DragItemData)drgevent.Data.GetData(typeof(DragItemData).ToString());
if (hoverItem == null) { for (int i = 0; i < data.DragItems.Count; i++) { ListViewItem newItem = (ListViewItem)data.DragItems[i]; base.Items.Add(newItem); } } else { int hoverIndex = hoverItem.Index;
if (this == data.ListView) { if (base.SelectedItems[0].Index <= hoverIndex && hoverIndex <= base.SelectedItems[base.SelectedItems.Count - 1].Index + 1) { if (m_previousItem != null) { m_previousItem = null; }
this.Invalidate();
base.OnDragDrop(drgevent); return; } }
for (int i = data.DragItems.Count - 1; i >= 0; i--) { ListViewItem newItem = (ListViewItem)data.DragItems[i]; base.Items.Insert(hoverIndex, newItem); base.Items[hoverIndex].Position = base.Items[hoverIndex + 1].Position; } }
if (data.ListView != null) { foreach (ListViewItem itemToRemove in data.ListView.SelectedItems) { data.ListView.Items.Remove(itemToRemove); } } this.Refresh(); if (m_previousItem != null) { m_previousItem = null; }
this.Invalidate();
base.OnDragDrop(drgevent); }
protected override void OnDragOver(DragEventArgs drgevent) { if (!m_allowReorder) { base.OnDragOver(drgevent); return; }
if (!drgevent.Data.GetDataPresent(typeof(DragItemData).ToString())) { drgevent.Effect = DragDropEffects.None; return; }
if (base.Items.Count > 0) { Point clientPoint = base.PointToClient(new Point(drgevent.X, drgevent.Y)); ListViewItem lastItem = base.Items[base.Items.Count - 1]; Point ptLastItem = new Point(lastItem.Bounds.X + lastItem.Bounds.Width + lastItem.Bounds.X, lastItem.Bounds.Y + lastItem.Bounds.Height); ListViewItem hoverItem = base.GetItemAt(clientPoint.X, clientPoint.Y);
Graphics g = this.CreateGraphics();
if (hoverItem == null && (clientPoint.X > ptLastItem.X || clientPoint.Y > ptLastItem.Y)) { 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)); } 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 - 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) }); 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) }); }
base.OnDragOver(drgevent);
return; }
if ((m_previousItem != null && m_previousItem != hoverItem) || m_previousItem == null) { this.Invalidate(); }
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 )); } 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 - 3, hoverItem.Bounds.Y), new Point(hoverItem.Bounds.X + 3, hoverItem.Bounds.Y), new Point(hoverItem.Bounds.X, hoverItem.Bounds.Y + 3) }); 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) }); }
foreach (ListViewItem itemToMove in base.SelectedItems) { if (itemToMove.Index == hoverItem.Index) { drgevent.Effect = DragDropEffects.None; hoverItem.EnsureVisible(); return; } }
hoverItem.EnsureVisible(); }
drgevent.Effect = DragDropEffects.Move;
base.OnDragOver(drgevent); }
protected override void OnDragEnter(DragEventArgs drgevent) { if (!m_allowReorder) { base.OnDragEnter(drgevent); return; }
if (!drgevent.Data.GetDataPresent(typeof(DragItemData).ToString())) { drgevent.Effect = DragDropEffects.None; return; }
drgevent.Effect = DragDropEffects.Move;
base.OnDragEnter(drgevent); }
protected override void OnItemDrag(ItemDragEventArgs e) { if (!m_allowReorder) { base.OnItemDrag(e); return; }
base.DoDragDrop(GetDataForDragDrop(), DragDropEffects.Move);
base.OnItemDrag(e); }
protected override void OnLostFocus(EventArgs e) { ResetOutOfRange();
Invalidate();
base.OnLostFocus(e); }
protected override void OnDragLeave(EventArgs e) { ResetOutOfRange();
Invalidate();
base.OnDragLeave(e); }
#endregion
#region Private Methods
private DragItemData GetDataForDragDrop() { DragItemData data = new DragItemData(this);
foreach (ListViewItem item in this.SelectedItems) { data.DragItems.Add(item.Clone()); }
return data; }
private void ResetOutOfRange() { 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
private void InitializeComponent() { this.SuspendLayout(); this.ResumeLayout(false);
} } }
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
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.
|
| Sign In·View Thread·PermaLink | 1.00/5 (1 vote) |
|
|
|
 |
|
 |
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, 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
|
| Sign In·View Thread·PermaLink | 1.00/5 (1 vote) |
|
|
|
 |
|
 |
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 | |
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.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
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)?
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Hi,
When I use your component, and if ListView.View = LargeIcon then item reorder - did not work.
Any idea to solve this problem ?
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
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?
|
| Sign In·View Thread·PermaLink | 1.00/5 (1 vote) |
|
|
|
 |
|
|
 |
|
 |
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.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
 |
First, let me thank you for your control, it's quite amazing.
Now my problem is that I'd still like to allow external files drag & dropping to one of my listviews, while still allowing items reordering. When I drag a file over my listview, the DragEnter even is not even called. If I disable AllowReorder, everything works fine.
What can I do to enable both at the same time ?
Thanks in advance.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
For others who have this problem (I had it too). I just changed some of the logic. All drag and drop handlers should call the corresponding base events no matter what at some point in the code. Also, a drag drop should turn off column sorting just in case it's on so that reordering by dragging takes precedence over sorting.
Cheers...
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
 |
1. you cant drag items from a standard listview, only from dragndrop control 2. it appears that the listview items when dragged down the listview, are added one extra line down, but when dragging up everything works fine.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
int hoverIndex = hoverItem.Index;
// determine if the items to be dropped are from // this list view. If they are, perform a hack // to (increment) decrement the hover index so that the items // get moved properly. if(this == data.ListView) { if(hoverIndex > base.SelectedItems[0].Index) hoverIndex-= base.SelectedItems.Count; }
this piece needs to be a decrement. That fixes the problem of the selected items being placed too far down.
Another thing I added to it is down below this piece I've changed the order a bit. Instead of first adding the listItems and then removing them from thier source list, I've removed them first, and then added them setting thier Selected Property to true, so that they stay selected when they are dropped.
I've only briefly looked at it, so if someone sees a reason why this would break it, please do tell. This control is great by the way.
-J
|
| Sign In·View Thread·PermaLink | 2.00/5 (1 vote) |
|
|
|
 |
|
 |
In the OnDragOver event handler, the drawing of the horizontal line and triangles takes place.
When the scrollbar is displayed, the right hand triangle is drawn underneath the scrollbar. To correct this, you need to use ClientSize.Width, rather than the width of the hoverItem when drawing the line and triangle.
You can also use hoverItem.Bounds.Bottom rather than adding the Y+Height together - it makes the code a little simpler!
In addition, it's usually a good idea to Dispose of Brushes and Pens as soon as you've used them. This is easily done by wrapping them in a using() statement.
Apart from this - it's worked perfectly. Thanks.
|
| Sign In·View Thread·PermaLink | 3.00/5 (4 votes) |
|
|
|
 |
|
 |
It works brilliantly. Thanks! One thing to remember - in case you are in the habit of subclassing ListItem and adding the subclass to the ListView (giving you a nice bit of polymorphism), you will need to override the Clone() method, cloning any data you store in the subclass. Also remember to provide a public, parameterless constructor to your subclass.
|
| Sign In·View Thread·PermaLink | 2.30/5 (7 votes) |
|
|
|
 |
|