C# ListView DragDrop - Multiple drag and drop methods - c#

I have two ListView's. One has options that are to be dragged into the other. This is the "fields" ListView. The other one is the "builder" ListView. The problem I am having is that I cannot have ListViewItem's inserted where the user drags it AND also be added to the bottom if they drag it to whitespace. I can do one or the other at this time. I need a solution for this.
private void builder_DragEnter(object sender, DragEventArgs e)
{
e.Effect = DragDropEffects.Move;
}
private void fields_DragEnter(object sender, DragEventArgs e)
{
e.Effect = DragDropEffects.Move;
}
private void fields_ItemDrag(object sender, ItemDragEventArgs e)
{
fromBuilder = false;
fields.DoDragDrop(e.Item, DragDropEffects.Move);
}
private void builder_ItemDrag(object sender, ItemDragEventArgs e)
{
fromBuilder = true;
builder.DoDragDrop(e.Item, DragDropEffects.Move);
}
private void builderAndFields_DragDrop(object sender, DragEventArgs e)
{
ListViewItem i = new ListViewItem();
i = e.Data.GetData(typeof(ListViewItem)) as ListViewItem;
// Since this function works for both the builder and the fields,
// we have to check to see where we are dropping, the sender
// is the ListView we are dropping onto
if (sender.Equals(builder))
{
ListViewItem c = new ListViewItem();
c = (ListViewItem)i.Clone();
Point cp = builder.PointToClient(new Point(e.X, e.Y));
Console.WriteLine("cp: " + cp);
ListViewItem dragToItem = builder.GetItemAt(cp.X, cp.Y);
Console.WriteLine("dragToItem: " + dragToItem);
int dropIndex = dragToItem.Index;
// Now, we have to check to see if we are reordering or adding
// So, we check the flag to see if the dragDrop was initiated
// on the builder or on the fields ListView
if (fromBuilder)
{
builder.Items.Insert(dropIndex, c);
builder.Items.Remove(i);
}
else
{
// ## Problem - Attempted solution ##
if (String.IsNullOrWhiteSpace(dragToItem.ToString()))
builder.Items.Add(c);
else
{
Console.WriteLine(dropIndex);
builder.Items.Insert(dropIndex, c);
}
}
}
// If the sender is the fields listView, the user is trying to remove
// the item from the builder.
else
{
builder.Items.Remove(i);
}
}

Thank you for your comment Hans. It was very helpful! Here is the solution to two problems I was having. The other was being able to reorder the ListView and drag items to the bottom of the list.
// Generic DragEnter
private void ddEnter_DragEnter(object sender, DragEventArgs e)
{
e.Effect = DragDropEffects.Move;
}
// ItemDrag Events
private void fields_ItemDrag(object sender, ItemDragEventArgs e)
{
fromBuilder = false;
fields.DoDragDrop(e.Item, DragDropEffects.Move);
}
private void builder_ItemDrag(object sender, ItemDragEventArgs e)
{
fromBuilder = true;
packetBuilder.DoDragDrop(e.Item, DragDropEffects.Move);
}
// DragDrop Events
private void builderAndFields_DragDrop(object sender, DragEventArgs e)
{
ListViewItem i = new ListViewItem();
i = e.Data.GetData(typeof(ListViewItem)) as ListViewItem;
// Since this function works for both the builder and the fields,
// we have to check to see where we are dropping, the sender
// is the ListView we are dropping onto
Console.WriteLine(sender.Equals(packetBuilder));
if (sender.Equals(packetBuilder))
{
ListViewItem c = new ListViewItem();
c = (ListViewItem)i.Clone();
Point cp = packetBuilder.PointToClient(new Point(e.X, e.Y));
// Now, we have to check to see if we are reordering or adding
// So, we check the flag to see if the dragDrop was initiated
// on the builder or on the fields ListView
Console.WriteLine(fromBuilder);
if (fromBuilder)
{
if (packetBuilder.HitTest(cp).Location.ToString() == "None")
{
packetBuilder.Items.Add(c);
packetBuilder.Items.Remove(i);
}
else
{
ListViewItem dragToItem = packetBuilder.GetItemAt(cp.X, cp.Y);
int dropIndex = dragToItem.Index;
packetBuilder.Items.Insert(dropIndex, c);
packetBuilder.Items.Remove(i);
}
}
else
{
if (packetBuilder.HitTest(cp).Location.ToString() == "None")
packetBuilder.Items.Add(c);
else
{
ListViewItem dragToItem = packetBuilder.GetItemAt(cp.X, cp.Y);
int dropIndex = dragToItem.Index;
packetBuilder.Items.Insert(dropIndex, c);
}
}
}
// If the sender is the fields listView, the user is trying to remove
// the item from the builder.
else
{
packetBuilder.Items.Remove(i);
}
}

Related

C# Drag and Drop in Listview doesn't work with Groups

I have a Listview with Drag and Drop codes working well.
However, after i add groups to it, the Drag and Drop codes are run, but the outcome is not what the codes used to behave.
Dropped items were only added to the tail of its group.
Why? and how to get it work properly with groups?
The Drag and Drop procedures are given herebelow:
private void lvQ_DragDrop(object sender, DragEventArgs e)
{
int targetIndex = lvQ.InsertionMark.Index;
if (targetIndex == -1)
return;
if (lvQ.InsertionMark.AppearsAfterItem)
targetIndex++;
ListViewItem draggedItem = (ListViewItem)e.Data.GetData(typeof(ListViewItem));
if (targetIndex == 0 && lvQ.Items.OfType<ListViewItem>().FirstOrDefault()?.SubItems[1].Text == "FF")
{
lvQ.InsertionMark.Index = -1;
}
else
{
lvQ.BeginUpdate();
lvQ.Items.Insert(targetIndex, (ListViewItem)draggedItem.Clone());
lvQ.Items.Remove(draggedItem);
lvQ.EndUpdate();
ShowTXFrameStr();
}
}
private void lvQ_DragEnter(object sender, DragEventArgs e)
{
e.Effect = e.AllowedEffect;
}
private void lvQ_DragLeave(object sender, EventArgs e)
{
lvQ.InsertionMark.Index = -1;
}
private void lvQ_DragOver(object sender, DragEventArgs e)
{
Point ptScreen = new(e.X, e.Y);
Point pt = lvQ.PointToClient(ptScreen);
int targetIndex = lvQ.InsertionMark.NearestIndex(pt);
if (targetIndex > -1)
{
Rectangle itemBounds = lvQ.GetItemRect(targetIndex);
lvQ.InsertionMark.AppearsAfterItem = pt.Y > itemBounds.Top + (itemBounds.Height / 2);
}
lvQ.InsertionMark.Index = targetIndex;
}
private void lvQ_ItemDrag(object sender, ItemDragEventArgs e)
{
lvQ.DoDragDrop(e.Item, DragDropEffects.Move);
}

How to create a panel with support for Drag and Drop?

Suppose we have a ListBox with the Custom elements and the blank panel . When you drag these items to the panel , they must build on a certain logic. For example, if there's nothing panel , the element is located in the middle. But if there is , then the new element is to stay near the element that is closest to it . As such it is possible to implement?
For example:
I modified this answer of working drag and drop implementation by adding some sorting logic. Placing an item in the middle visually can be done with CSS styling.
Assumption: "closest to it" means closest alphabetically.
public object lb_item = null;
private void listBox1_DragLeave(object sender, EventArgs e)
{
ListBox lb = sender as ListBox;
lb_item = lb.SelectedItem;
lb.Items.Remove(lb.SelectedItem);
}
private void listBox1_DragEnter(object sender, DragEventArgs e)
{
if (lb_item != null)
{
listBox1.Items.Add(lb_item);
lb_item = null;
// Here I added the logic:
// Sort all items added previously
// (thereby placing item in the middle).
listBox1.Sorted = true;
}
}
private void listBox1_MouseDown(object sender, MouseEventArgs e)
{
lb_item = null;
if (listBox1.Items.Count == 0)
{
return;
}
int index = listBox1.IndexFromPoint(e.X, e.Y);
string s = listBox1.Items[index].ToString();
DragDropEffects dde1 = DoDragDrop(s, DragDropEffects.All);
}
private void Form1_DragDrop(object sender, DragEventArgs e)
{
lb_item = null;
}

Unable to drag and drop text from DataGridView to TextBox C#

I have been using code that others online have supplied but for some reason it won't let me drag items from the datagridview to the textbox. I highlight a row in the dataGridView and try to drag it to the textbox but nothing happens. I have also enabled the drop property for the textBox but still no difference. Here's the code that I am using:
private void dataGridView1_CellMouseDown(object sender, DataGridViewCellMouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
DataGridView.HitTestInfo info = dataGridView1.HitTest(e.X, e.Y);
if (info.RowIndex >= 0)
{
if (info.RowIndex >= 0 && info.ColumnIndex >= 0)
{
string text = (String)
dataGridView1.Rows[info.RowIndex].Cells[info.ColumnIndex].Value;
if (text != null)
dataGridView1.DoDragDrop(text, DragDropEffects.Copy);
}
}
}
}
private void textBox1_DragDrop(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(typeof(System.String)))
{
textBox1.Text = (System.String)e.Data.GetData(typeof(System.String));
}
}
private void textBox1_DragEnter(object sender, DragEventArgs e)
{
e.Effect = DragDropEffects.Copy;
}
Here is a small sample that i have done to give you an idea on how to do this... works perfectly for me. I used WinForms here. If WPF, there may be some more events you will need to register to in order for the drag+drop to register...
Note that you will want to add more code here and there to perform what you really want to do when you drag an item from one control to the other.
public partial class Form1 : Form
{
private Rectangle dragBoxFromMouseDown;
private int rowIndexFromMouseDown;
private int rowIndexOfItemUnderMouseToDrop;
private DataGridViewRow draggedrow;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
List<StringValue> Items = new List<StringValue>() { new StringValue("1"), new StringValue("2"), new StringValue("3"), new StringValue("4"), new StringValue("5"), new StringValue("6") };
this.dataGridView1.DataSource = Items;
}
private void dataGridView1_MouseMove(object sender, MouseEventArgs e)
{
if ((e.Button & MouseButtons.Left) == MouseButtons.Left)
{
// If the mouse moves outside the rectangle, start the drag.
if (dragBoxFromMouseDown != Rectangle.Empty &&
!dragBoxFromMouseDown.Contains(e.X, e.Y))
{
// Proceed with the drag and drop, passing in the list item.
DragDropEffects dropEffect = dataGridView1.DoDragDrop(
dataGridView1.Rows[rowIndexFromMouseDown],
DragDropEffects.Move);
}
}
}
private void dataGridView1_MouseDown(object sender, MouseEventArgs e)
{
// Get the index of the item the mouse is below.
rowIndexFromMouseDown = dataGridView1.HitTest(e.X, e.Y).RowIndex;
if (rowIndexFromMouseDown != -1)
{
// Remember the point where the mouse down occurred.
// The DragSize indicates the size that the mouse can move
// before a drag event should be started.
Size dragSize = SystemInformation.DragSize;
// Create a rectangle using the DragSize, with the mouse position being
// at the center of the rectangle.
dragBoxFromMouseDown = new Rectangle(new Point(e.X - (dragSize.Width / 2),
e.Y - (dragSize.Height / 2)),
dragSize);
this.draggedrow = this.dataGridView1.CurrentRow;
}
else
// Reset the rectangle if the mouse is not over an item in the ListBox.
dragBoxFromMouseDown = Rectangle.Empty;
}
private void dataGridView1_DragOver(object sender, DragEventArgs e)
{
e.Effect = DragDropEffects.Move;
}
private void textBox1_DragEnter(object sender, DragEventArgs e)
{
e.Effect = DragDropEffects.Move;
}
private void textBox1_DragDrop(object sender, DragEventArgs e)
{
this.textBox1.Text = (string)this.draggedrow.Cells["Value"].Value;
}
}
public class StringValue
{
public StringValue(string s)
{
_value = s;
}
public string Value { get { return _value; } set { _value = value; } }
string _value;
}
can't you use DataGridViewCellMouseEventArgs e instead of hittest for getting row index in dataGridView1_CellMouseDown. below is your code modified hope this helps
private void dataGridView1_CellMouseDown(object sender, DataGridViewCellMouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
if (e.RowIndex >= 0)
{
if (e.RowIndex >= 0 && e.ColumnIndex >= 0)
{
string text = (String)
dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value;
if (text != null)
dataGridView1.DoDragDrop(text, DragDropEffects.Copy);
}
}
}
}
private void textBox1_DragDrop(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(typeof(System.String)))
{
textBox1.Text = (System.String)e.Data.GetData(typeof(System.String));
}
}
private void textBox1_DragEnter(object sender, DragEventArgs e)
{
e.Effect = DragDropEffects.Copy;
}

Visual aid in drag and drop within a ListView

Problem
I have two ListView's. One has options that are to be dragged into the other. This is the "fields" ListView. The other one is the "builder" ListView. I cannot figure out a way to visually show the user where the item will be inserted. I would like to draw a line in-between the ListViewItem's to visually aid the user.
private void builder_DragEnter(object sender, DragEventArgs e)
{
e.Effect = DragDropEffects.Move;
}
private void fields_DragEnter(object sender, DragEventArgs e)
{
e.Effect = DragDropEffects.Move;
}
private void fields_ItemDrag(object sender, ItemDragEventArgs e)
{
fromBuilder = false;
fields.DoDragDrop(e.Item, DragDropEffects.Move);
}
private void builder_ItemDrag(object sender, ItemDragEventArgs e)
{
fromBuilder = true;
builder.DoDragDrop(e.Item, DragDropEffects.Move);
}
private void builderAndFields_DragDrop(object sender, DragEventArgs e)
{
ListViewItem i = new ListViewItem();
i = e.Data.GetData(typeof(ListViewItem)) as ListViewItem;
// Since this function works for both the builder and the fields,
// we have to check to see where we are dropping, the sender
// is the ListView we are dropping onto
if (sender.Equals(builder))
{
ListViewItem c = new ListViewItem();
c = (ListViewItem)i.Clone();
Point cp = builder.PointToClient(new Point(e.X, e.Y));
Console.WriteLine("cp: " + cp);
ListViewItem dragToItem = builder.GetItemAt(cp.X, cp.Y);
Console.WriteLine("dragToItem: " + dragToItem);
int dropIndex = dragToItem.Index;
// Now, we have to check to see if we are reordering or adding
// So, we check the flag to see if the dragDrop was initiated
// on the builder or on the fields ListView
if (fromBuilder)
{
builder.Items.Insert(dropIndex, c);
builder.Items.Remove(i);
}
else
{
Console.WriteLine(dropIndex);
builder.Items.Insert(dropIndex, c);
}
}
// If the sender is the fields listView, the user is trying to remove
// the item from the builder.
else
{
builder.Items.Remove(i);
}
}
Take a look at PreviewDragEnter, PreviewDragOver, and PreviewDragLeave.
You can use that event to add an Adorner to your drop list. IF you search for "WPF DragDropHelper" you will find several detailed examples.
Better ListView supports drop highlighting and insertion marks out of the box:
I think you can also do this in a regular ListView using HitTest() method within DragOver event handler.

C# Drag & drop from listbox to treeview

I have a winform with a listbox and a treeview.
Once my listbox is filled with items, I want to drag them (multiple or single) from the listbox and drop them in a node in the treeview.
If somebody has a good example in C# that would be great.
It's been a while since I've messed with Drag/Drop so I figured I'll write a quick sample.
Basically, I have a form, with a listbox on the left, and a treeview on the right. Then I put a button on top. When the button is clicked, it just puts the date of the next ten days into the list box. It also populates the TreeView with 2 parents nodes and two child nodes. Then, you just have to handle all the subsequent drag/drop events to make it work.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.treeView1.AllowDrop = true;
this.listBox1.AllowDrop = true;
this.listBox1.MouseDown += new MouseEventHandler(listBox1_MouseDown);
this.listBox1.DragOver += new DragEventHandler(listBox1_DragOver);
this.treeView1.DragEnter += new DragEventHandler(treeView1_DragEnter);
this.treeView1.DragDrop += new DragEventHandler(treeView1_DragDrop);
}
private void button1_Click(object sender, EventArgs e)
{
this.PopulateListBox();
this.PopulateTreeView();
}
private void PopulateListBox()
{
for (int i = 0; i <= 10; i++)
{
this.listBox1.Items.Add(DateTime.Now.AddDays(i));
}
}
private void PopulateTreeView()
{
for (int i = 1; i <= 2; i++)
{
TreeNode node = new TreeNode("Node" + i);
for (int j = 1; j <= 2; j++)
{
node.Nodes.Add("SubNode" + j);
}
this.treeView1.Nodes.Add(node);
}
}
private void treeView1_DragDrop(object sender, DragEventArgs e)
{
TreeNode nodeToDropIn = this.treeView1.GetNodeAt(this.treeView1.PointToClient(new Point(e.X, e.Y)));
if (nodeToDropIn == null) { return; }
if(nodeToDropIn.Level > 0)
{
nodeToDropIn = nodeToDropIn.Parent;
}
object data = e.Data.GetData(typeof(DateTime));
if (data == null) { return; }
nodeToDropIn.Nodes.Add(data.ToString());
this.listBox1.Items.Remove(data);
}
private void listBox1_DragOver(object sender, DragEventArgs e)
{
e.Effect = DragDropEffects.Move;
}
private void treeView1_DragEnter(object sender, DragEventArgs e)
{
e.Effect = DragDropEffects.Move;
}
private void listBox1_MouseDown(object sender, MouseEventArgs e)
{
this.listBox1.DoDragDrop(this.listBox1.SelectedItem, DragDropEffects.Move);
}
}
You want to use the GetItemAt(Point point) function to translate X,Y location to the listview item.
Here's quite good article about it: Drag and Drop Using C#.
To make the item being dragged visible while dragging, you need to use COM ImageList, which is well described in the following article Custom Drag-Drop Images Using ImageLists.

Categories

Resources