Bodekaer
asked on
Drag and drop ListView items, with fade/transparent effect.
How do I create a listview item dragger... I want to be able to move arround the icons inside a listview.
Is it also possible to use the cool XP effect where the icons become transparent when moving files/folders arround in Windows.
Thanks in advance,
Michael
Is it also possible to use the cool XP effect where the icons become transparent when moving files/folders arround in Windows.
Thanks in advance,
Michael
Do you want to move the items around inside the same listview or do you want to be able to drag items between different listviews?
Here is how to do a simple drag for a single list view item...
1. Subscribe to the following events...
this.listView1.DragOver += new System.Windows.Forms.DragE ventHandle r(this.lis tView1_Dra gOver);
this.listView1.DragDrop += new System.Windows.Forms.DragE ventHandle r(this.lis tView1_Dra gDrop);
this.listView1.DragEnter += new System.Windows.Forms.DragE ventHandle r(this.lis tView1_Dra gEnter);
this.listView1.ItemDrag += new System.Windows.Forms.ItemD ragEventHa ndler(this .listView1 _ItemDrag) ;
2. Implement the following event handlers...
private void listView1_DragDrop(object sender, System.Windows.Forms.DragE ventArgs e)
{
// Convert screen position into listview position...
Point curPoint = listView1.PointToClient(ne w Point(e.X, e.Y));
// Determine destination item based on mouse position...
ListViewItem destItem = listView1.GetItemAt(curPoi nt.X, curPoint.Y);
// Retrieve source item from event data...
ListViewItem srcItem = e.Data.GetData(typeof(List ViewItem)) as ListViewItem;
// Create copy of list view items (for some reason removing an item from
// listview1.Items and inserting it again DOES NOT reorder the items!!)...
ArrayList items = new ArrayList(listView1.Items) ;
// Get index of destination item...
int index = items.IndexOf(destItem);
// Remove source item...
items.Remove(srcItem);
// Insert source item in new position...
items.Insert(index, srcItem);
// Repopulate list view...
listView1.Items.Clear();
listView1.Items.AddRange(( ListViewIt em[])items .ToArray(t ypeof(List ViewItem)) );
// Set source item to be selected...
listView1.SelectedItems.Cl ear();
srcItem.Selected = true;
}
private void listView1_DragEnter(object sender, System.Windows.Forms.DragE ventArgs e)
{
// Set to move...
e.Effect = DragDropEffects.Move;
}
private void listView1_DragOver(object sender, System.Windows.Forms.DragE ventArgs e)
{
// Convert screen position into listview position...
Point curPoint = listView1.PointToClient(ne w Point(e.X, e.Y));
// Determine destination item based on mouse position...
ListViewItem destItem = listView1.GetItemAt(curPoi nt.X, curPoint.Y);
// Retrieve source item from event data...
ListViewItem srcItem = e.Data.GetData(typeof(List ViewItem)) as ListViewItem;
if(destItem != null)
{
// Select both source and destination items...
listView1.SelectedItems.Cl ear();
srcItem.Selected = true;
destItem.Selected = true;
}
}
private void listView1_ItemDrag(object sender, System.Windows.Forms.ItemD ragEventAr gs e)
{
// Start drag operation with selected item...
listView1.DoDragDrop(e.Ite m, DragDropEffects.All);
}
Performing the "cool XP effect" is slightly harder, I'll post some additional code shortly which demonstrates how that can be done.
1. Subscribe to the following events...
this.listView1.DragOver += new System.Windows.Forms.DragE
this.listView1.DragDrop += new System.Windows.Forms.DragE
this.listView1.DragEnter += new System.Windows.Forms.DragE
this.listView1.ItemDrag += new System.Windows.Forms.ItemD
2. Implement the following event handlers...
private void listView1_DragDrop(object sender, System.Windows.Forms.DragE
{
// Convert screen position into listview position...
Point curPoint = listView1.PointToClient(ne
// Determine destination item based on mouse position...
ListViewItem destItem = listView1.GetItemAt(curPoi
// Retrieve source item from event data...
ListViewItem srcItem = e.Data.GetData(typeof(List
// Create copy of list view items (for some reason removing an item from
// listview1.Items and inserting it again DOES NOT reorder the items!!)...
ArrayList items = new ArrayList(listView1.Items)
// Get index of destination item...
int index = items.IndexOf(destItem);
// Remove source item...
items.Remove(srcItem);
// Insert source item in new position...
items.Insert(index, srcItem);
// Repopulate list view...
listView1.Items.Clear();
listView1.Items.AddRange((
// Set source item to be selected...
listView1.SelectedItems.Cl
srcItem.Selected = true;
}
private void listView1_DragEnter(object
{
// Set to move...
e.Effect = DragDropEffects.Move;
}
private void listView1_DragOver(object sender, System.Windows.Forms.DragE
{
// Convert screen position into listview position...
Point curPoint = listView1.PointToClient(ne
// Determine destination item based on mouse position...
ListViewItem destItem = listView1.GetItemAt(curPoi
// Retrieve source item from event data...
ListViewItem srcItem = e.Data.GetData(typeof(List
if(destItem != null)
{
// Select both source and destination items...
listView1.SelectedItems.Cl
srcItem.Selected = true;
destItem.Selected = true;
}
}
private void listView1_ItemDrag(object sender, System.Windows.Forms.ItemD
{
// Start drag operation with selected item...
listView1.DoDragDrop(e.Ite
}
Performing the "cool XP effect" is slightly harder, I'll post some additional code shortly which demonstrates how that can be done.
The following method can be used to make a drag image, it's not really transparent but unless you look really closely you can hardly tell...
(C#)
private Image CreateDragImage(ListViewIt em item)
{
// Ensure the node is completely visible...
item.EnsureVisible();
// Calculate node rectange (including item icon)...
Rectangle itemRect = new Rectangle(
item.Bounds.Left - 20, item.Bounds.Top,
item.Bounds.Width + 20, item.Bounds.Height);
// Set selected node to null & redraw...
listView1.SelectedItems.Cl ear();
listView1.Update();
// Get reference to tree control graphics...
Graphics listviewGraphics = listView1.CreateGraphics() ;
// Create bitmap and get reference to it's graphics...
Bitmap memBitmap = new Bitmap(itemRect.Width, itemRect.Height);
Graphics memGraphics = Graphics.FromImage(memBitm ap);
// Get references to device context handles...
IntPtr treeDC = listviewGraphics.GetHdc();
IntPtr memDC = memGraphics.GetHdc();
// Copy required region of screen to bitmap...
BitBlt(
memDC, 0, 0, itemRect.Width, itemRect.Height,
treeDC,itemRect.Left, itemRect.Top, 0xCC0020);
// Release device contexts...
listviewGraphics.ReleaseHd c(treeDC);
memGraphics.ReleaseHdc(mem DC);
// Make it look faded...
memGraphics.FillRectangle( new SolidBrush(Color.FromArgb( 128, listView1.BackColor)), 0, 0, itemRect.Width, itemRect.Height);
// Make selection color transparent, leaving text only...
memBitmap.MakeTransparent( listView1. BackColor) ;
// Return image...
return memBitmap;
}
You will also need to import the following method;
(C#)
[DllImport("gdi32.dll")]
public static extern bool BitBlt(
IntPtr hdcDest, // handle to destination DC
int nXDest, // x-coord of destination upper-left corner
int nYDest, // y-coord of destination upper-left corner
int nWidth, // width of destination rectangle
int nHeight, // height of destination rectangle
IntPtr hdcSrc, // handle to source DC
int nXSrc, // x-coordinate of source upper-left corner
int nYSrc, // y-coordinate of source upper-left corner
System.Int32 dwRop // raster operation code
);
The following describes how to integrate it into the drag and drop example...
1. Define some member variables
(C#)
private Image m_dragImage = null;
private Point m_dragPosition;
2. Change the "listView1_ItemDrag" handler as follows.
(C#)
private void listView1_ItemDrag(object sender, System.Windows.Forms.ItemD ragEventAr gs e)
{
m_dragImage = CreateDragImage(e.Item as ListViewItem);
// Start drag operation with selected item...
listView1.DoDragDrop(e.Ite m, DragDropEffects.All);
}
3. Add the following code to the END of the "listView1_DragOver" handler.
if(m_dragImage != null && m_dragPosition != curPoint)
{
// Redraw last image position...
listView1.Invalidate(new Rectangle(m_dragPosition.X , m_dragPosition.Y, m_dragImage.Width, m_dragImage.Height));
listView1.Update();
// Determine new image position...
Point imagePos = new Point(curPoint.X, curPoint.Y);
// Draw image...
Graphics.FromHwnd(listView 1.Handle). DrawImage( m_dragImag e, imagePos);
m_dragPosition = curPoint;
}
4. You might also need a call to "listView1.Refresh()" at the end of the "listView1_DragDrop" handler
(C#)
private Image CreateDragImage(ListViewIt
{
// Ensure the node is completely visible...
item.EnsureVisible();
// Calculate node rectange (including item icon)...
Rectangle itemRect = new Rectangle(
item.Bounds.Left - 20, item.Bounds.Top,
item.Bounds.Width + 20, item.Bounds.Height);
// Set selected node to null & redraw...
listView1.SelectedItems.Cl
listView1.Update();
// Get reference to tree control graphics...
Graphics listviewGraphics = listView1.CreateGraphics()
// Create bitmap and get reference to it's graphics...
Bitmap memBitmap = new Bitmap(itemRect.Width, itemRect.Height);
Graphics memGraphics = Graphics.FromImage(memBitm
// Get references to device context handles...
IntPtr treeDC = listviewGraphics.GetHdc();
IntPtr memDC = memGraphics.GetHdc();
// Copy required region of screen to bitmap...
BitBlt(
memDC, 0, 0, itemRect.Width, itemRect.Height,
treeDC,itemRect.Left, itemRect.Top, 0xCC0020);
// Release device contexts...
listviewGraphics.ReleaseHd
memGraphics.ReleaseHdc(mem
// Make it look faded...
memGraphics.FillRectangle(
// Make selection color transparent, leaving text only...
memBitmap.MakeTransparent(
// Return image...
return memBitmap;
}
You will also need to import the following method;
(C#)
[DllImport("gdi32.dll")]
public static extern bool BitBlt(
IntPtr hdcDest, // handle to destination DC
int nXDest, // x-coord of destination upper-left corner
int nYDest, // y-coord of destination upper-left corner
int nWidth, // width of destination rectangle
int nHeight, // height of destination rectangle
IntPtr hdcSrc, // handle to source DC
int nXSrc, // x-coordinate of source upper-left corner
int nYSrc, // y-coordinate of source upper-left corner
System.Int32 dwRop // raster operation code
);
The following describes how to integrate it into the drag and drop example...
1. Define some member variables
(C#)
private Image m_dragImage = null;
private Point m_dragPosition;
2. Change the "listView1_ItemDrag" handler as follows.
(C#)
private void listView1_ItemDrag(object sender, System.Windows.Forms.ItemD
{
m_dragImage = CreateDragImage(e.Item as ListViewItem);
// Start drag operation with selected item...
listView1.DoDragDrop(e.Ite
}
3. Add the following code to the END of the "listView1_DragOver" handler.
if(m_dragImage != null && m_dragPosition != curPoint)
{
// Redraw last image position...
listView1.Invalidate(new Rectangle(m_dragPosition.X
listView1.Update();
// Determine new image position...
Point imagePos = new Point(curPoint.X, curPoint.Y);
// Draw image...
Graphics.FromHwnd(listView
m_dragPosition = curPoint;
}
4. You might also need a call to "listView1.Refresh()" at the end of the "listView1_DragDrop" handler
ASKER
Ok, looks great. What if I want it to work with VB.NET ? :)
(it was within the same listview)
(it was within the same listview)
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.