C# DragEnter event of the Winforms DragDrop - c#

Why do we actually need to handle DragEnter event of the drop destination?
What is its effect at the destination?
At Source
public partial class ToolBoxForm : System.Windows.Forms.Form
{
public ToolBoxForm()
{
InitializeComponent();
}
private void lbl_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
{
Label lbl = (Label)sender;
lbl.DoDragDrop(lbl.Image, DragDropEffects.Link);
}
}
At Destination:
public partial class DrawingArea : Form
{
public DrawingArea()
{
InitializeComponent();
}
private void DrawingArea_Load(object sender, System.EventArgs e)
{
ToolBoxForm toolBoxForm = new ToolBoxForm();
this.AddOwnedForm(toolBoxForm);
toolBoxForm.Show();
pictureBox1.AllowDrop = true;
}
private void picDrawingArea_DragEnter(object sender, System.Windows.Forms.DragEventArgs e)
{
if (e.Data.GetDataPresent(DataFormats.Bitmap))
{
e.Effect = DragDropEffects.Copy;
}
else
{
e.Effect = DragDropEffects.None;
}
}
private void picDrawingArea_DragDrop(object sender, System.Windows.Forms.DragEventArgs e)
{
Graphics g = pictureBox1.CreateGraphics();
g.DrawImage((Image)e.Data.GetData(DataFormats.Bitmap), new Point(e.X - this.Left - 12, e.Y - this.Top - 30));
}
}
When I am commenting out the code:
if (e.Data.GetDataPresent(DataFormats.Bitmap))
{
e.Effect = DragDropEffects.Copy;
}
else
{
e.Effect = DragDropEffects.None;
}
The image is not being dropped.

From to the DragDropEffects MSDN Page:
Member
name Description
None The drop target does not accept the data.
Copy The data from the drag source is copied to the drop target.
Move The data from the drag source is moved to the drop target.
Link The data from the drag source is linked to the drop target.
Scroll The target can be scrolled while dragging to locate a drop position that is not currently visible in the target.
All The combination of the Copy, Move, and Scroll effects.
So you've got to set it something other than None if you want to accept the drop.
However, the next quote led me to believe that it was just used for feedback:
You can use DragDropEffects to display different mouse pointers for drag-and-drop operations. For example, you can display a plus symbol for a Copy drag-and-drop operation, an arrow symbol for a Move drag-and-drop operation, or a red circle with a line through it symbol for a None drag-and-drop operation.

I really think the Drop event won't fire if DragDropEvents is left at None (which is the default). So that's why the image doesn't drop.

Related

How can I make images drag and drop-able to reorder them?

I'm building an application in which I'd like a user to be able to reorder pictures in a form in two columns. I've got a flowLayoutPanel of a set width, and pictures are added via the OpenFileDialog and scaled to half the width (minus an allowance for a scroll bar) of the flow layout panel.
This is where I'm stuck - I've tried adding the images as Labels, Buttons, and now PictureBoxes and I can't work out how to actually move them around. I gave up on labels because CanSelect is false - although I didn't know if that would have made a difference - and I moved on from buttons because I realised picture boxes existed. I'm open to switching out which controls I use but the images will always need to be in two columns.
Here's the code I currently have for the DragEnter and DragDrop events:
private void flowLayoutPanel_6_Cards_DragEnter(object sender, DragEventArgs e)
{
e.Effect = DragDropEffects.All;
}
private void flowLayoutPanel_6_Cards_DragDrop(object sender, DragEventArgs e)
{
MessageBox.Show("dropped");
}
How can I implement this? What controls should I use and what properties should I be looking at to make this possible?
So thanks to #TaW's comment I now know that you have to add a DoDragDrop call to the MouseDown event on whatever you're dragging. My now-working code is below (thanks mostly to this tutorial):
private void flowLayoutPanel_6_Cards_DragDrop(object sender, DragEventArgs e)
{
PictureBox picture = (PictureBox)e.Data.GetData(typeof(PictureBox));
FlowLayoutPanel _source = (FlowLayoutPanel)picture.Parent;
FlowLayoutPanel _destination = (FlowLayoutPanel)sender;
if (_source != _destination)
{
//where did you even get this from?
}
else
{
Point p = _destination.PointToClient(new Point(e.X, e.Y));
var item = _destination.GetChildAtPoint(p);
int index = _destination.Controls.GetChildIndex(item, false);
_destination.Controls.SetChildIndex(picture, index);
_destination.Invalidate();
}
}
private void flowLayoutPanel_6_Cards_DragEnter(object sender, DragEventArgs e)
{
e.Effect = DragDropEffects.All;
}
void p_MouseDown(object sender, MouseEventArgs e)
{
PictureBox p = (PictureBox)sender;
p.DoDragDrop(p, DragDropEffects.All);
}

WPF datagrid drag and drop target indicator

I have a WPF datagrid where a user can drag and drop various rows to reorder them. However, I need an indicator that will display where the row will be inserted.
I've tried various 'hacky' ways of doing it, including detecting mouse move events and inserting a blank indicator row where the mouse is. Unfortunately, it seems that while dragging rows, none of my mouse move events are getting fired.
The UIElement class provides several events that you can use.
Those are:
DragEnter
DragOver
DragLeave
Drop
The first two are the one you can use.
<DataGrid DragOver="MyGrid_DragOver"
DragEnter="MyGrid_DragEnter"
I had to use both to get my drag and drop working.
I start the Drag operation by reacting to a move mouve event:
private void MyGrid_MouseMove(object sender, MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed)
{
var dragSource = ...;
var data = ...;
DragDrop.DoDragDrop(dragSource, data, DragDropEffects.Move);
}
}
Then you code the event handlers on the target control (your DataGrid):
private void MyGrid_DragOver(object sender, DragEventArgs e)
{
this.DragOver_DragEnter(sender, e);
}
private void MyGrid_DragEnter(object sender, DragEventArgs e)
{
this.DragOver_DragEnter(sender, e);
}
Then you can set the Effects propery to give a visual feedback to the user:
private void DragOver_DragEnter(object sender, DragEventArgs e)
{
// code here to decide whether drag target is ok
e.Effects = DragDropEffects.None;
e.Effects = DragDropEffects.Move;
e.Effects = DragDropEffects.Copy;
e.Handled = true;
return;
}
Check out this response on MSDN too: Giving drag and drop feedback using DragEventArgs.Effect

Redrawing issues when moving a control

I am trying to move some controls around on a WinForm with the mouse. I am using the code below. To see my issue start a new project in VS add the code below. Set the form BackGroundImage to any image then add any control. Set the control events for MouseUp, MouseDown, and MouseMove. Start debugging and click and move the control. The image in the form starts getting erased. I have tried several different suspend drawing classes and methods I have found on the net but nothing I have found lets me move the controls around without serious flickering or not being able to see the move. Any help would be appreciated.
P.S. If you set the same events to the up, move, and down events of the form, it moves fine with out any flickering.
private bool _mouseDown;
private Point _startPoint;
private void Event_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
_mouseDown = true;
_startPoint = new Point(e.X, e.Y);
}
}
private void Event_MouseUp(object sender, MouseEventArgs e)
{
_mouseDown = false;
}
private void Event_MouseMove(object sender, MouseEventArgs e)
{
if (_mouseDown)
{
Control s = sender as Control;
s.Location = new Point(e.X + s.Left - _startPoint.X, e.Y + s.Top - _startPoint.Y);
}
}

C# Moving own controls around and make them droppable

A good morning to you all!
Yesterday I ran into a problem while trying to implement a custom DragDrop for my own controls in a WinForms application.
I have a form which can dynamically create instances of two of my own controls. These controls consist of some controls themselves, such as buttons, labels and listboxes/treeviews. The controls serve as a representation for a certain dataset. Now, we all know the class diagrams in VS. There you have these boxes representing classes. You can move the boxes around on the canvas by doing - what I would call - dragging them around, much like you would drag around files. To accomplish this with my own controls I have done the following:
public partial class MyControl: UserControl
{
private Control activeControl;
private void GeneralMouseDown(MouseEventArgs e)
{
activeControl = this;
previousLocation = e.Location;
Cursor = Cursors.Hand;
}
private void GeneralMouseMove(Control sender, MouseEventArgs e)
{
if (activeControl == null || activeControl != sender)
return;
var location = activeControl.Location;
location.Offset(e.Location.X - previousLocation.X, e.Location.Y - previousLocation.Y);
activeControl.Location = location;
}
private void GeneralMouseUp()
{
activeControl = null;
Cursor = Cursors.Default;
}
}
The controls on my control which I want to "grab" for dragging MyControl have their MouseDown-, MouseMove- and MouseUp-events pointing to these three methods. As a result I can move my control about on the form freely, just as I want to.
Here comes the tricky bit:
The datasets I have controls for can be in hierarchical dependencies, which means, one control represents detailling of a component of the other, which is why my controls have Listboxes or TreeViews. To establish such a hierarchical dependency I would very much like to DragDrop the lower-order-control on the listbox of my higher-order-control, causing data to be transfered.
I know how to set up my DragEnter and DragDrop methods for the listbox, as I have done so previously with files. Just for completeness:
private void lst_MyControl_DragEnter(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(typeof(MyControl)))
e.Effect = DragDropEffects.Move;
else e.Effect = DragDropEffects.None;
}
Here's the problem: As I am moving my control about (which gets repainted at every position, giving a very much wanted effect!), when I "drag" it over the target-listbox, the DragEnter-event does not get fired. I thought I could work around this problem by telling Windows "Hey, I'm, Dragging'n'Dropping here!", thus adding to my GeneralMouseDown-method:
this.DoDragDrop(this, DragDropEffects.Move);
This, on the one hand, gets the DragEnter-event to fire => Yeah! On the other hand is the moving-around-part only working after I release the mouse, causing the control to hang on the mousepointer forever => Anti-Yeah!
Here's the question: Is there a way, to have both actions at the same time? So that I can move my control around, seing it at every position as I do now and fire the DragEnter-event when I get to that area of the other control?
Moving your Control around interferes with the automatic DragDrop handling.
I'd recommend to staying with the normal DragDrop procedures, that is leaving all visuals to the system: It will display a cursor that indicates when a valid target is entered, then change to one that indicates the operation.
You need just 3 lines, no hassle and the user won't seen bulky controls moving around.
Here is a version where I drag a PictureBox onto a ListBox:
private void listBox1_DragEnter(object sender, DragEventArgs e)
{
e.Effect = DragDropEffects.Copy;
}
private void listBox1_DragDrop(object sender, DragEventArgs e)
{
listBox1.Items.Add( e.Data.GetData(DataFormats.Text));
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Left)
pictureBox1.DoDragDrop(pictureBox1.ImageLocation, DragDropEffects.Copy);
}
Obviously you will set up and receive your data in your own ways..
Edit:
Now, if on the other hand you need to move controls around to rearrange them, maybe you should give up on Drag&Drop to handle the additional data transfers and code this portion on your own as well. You could use the MouseEnter event of a receiving control..
After a bit of fiddeling I did it. I switched the level on which the dragging is handled.
First I need just the MouseDown-event
public Point GrabPoint;
private void GeneralMouseDown(MouseEventArgs e)
{
GrabPoint = e.Location;
this.DoDragDrop(this, DragDropEffects.Move);
}
I set the point where I grab the control and initiate a DragDrop. On my form I handle all the dragging:
private void frmMain_DragEnter(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(typeof(MyControl1)) || e.Data.GetDataPresent(typeof(MyControl2)) || e.Data.GetDataPresent(typeof(MyControl3)))
e.Effect = DragDropEffects.Move;
else e.Effect = DragDropEffects.None;
}
private void frmMain_DragOver(object sender, DragEventArgs e)
{
Point DragTarget = new Point(e.X, e.Y);
Point GrabPoint = new Point(0, 0);
if (e.Data.GetDataPresent(typeof(MyControl1)))
GrabPoint = ((MyControl1)e.Data.GetData(typeof(MyControl1))).GrabPoint;
else if (e.Data.GetDataPresent(typeof(MyControl2)))
GrabPoint = ((MyControl2)e.Data.GetData(typeof(MyControl2))).GrabPoint;
else if (e.Data.GetDataPresent(typeof(MyControl3)))
GrabPoint = ((MyControl3)e.Data.GetData(typeof(MyControl3))).GrabPoint;
DragTarget.X -= GrabPoint.X;
DragTarget.Y -= GrabPoint.Y;
DragTarget = this.PointToClient(DragTarget);
if (e.Data.GetDataPresent(typeof(MyControl1)))
((MyControl1)e.Data.GetData(typeof(MyControl1))).Location = DragTarget;
else if (e.Data.GetDataPresent(typeof(MyControl2)))
((MyControl2)e.Data.GetData(typeof(MyControl2))).Location = DragTarget;
else if (e.Data.GetDataPresent(typeof(MyControl3)))
((MyControl3)e.Data.GetData(typeof(MyControl3))).Location = DragTarget;
}
At the moment I don't need the DragDrop-event, since nothing should happen when any control is dropped on the form. This way I always paint my control while it is being dragged => Yeah!
The next part is easy: Since I am really dragging the control, this bit of code does DragDrop-handling on my listbox Edit: ListView:
private void lst_SubControls_DragEnter(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(typeof(MyControl2)))
e.Effect = DragDropEffects.Move;
else e.Effect = DragDropEffects.None;
}
private void lst_SubControls_DragDrop(object sender, DragEventArgs e)
{
lst_SubControls.Items.Add(((MyControl2)e.Data.GetData(typeof(MyControl2))).SpecificDrive);
((MyControl2)e.Data.GetData(typeof(MyControl2))).DeleteThisControl();
}
This results in an entry added to the list and deletion of the dragged control. At this point there could be a check, wether the ctrl-key is pressed to copy the contents and not to delete the control.

Drag and Drop one control to another control in winform

am doing something very very simple.
I have a listbox whose events are set like this :
public Form1()
{
InitializeComponent();
this.listBox1.AllowDrop = true;
this.listBox1.DragEnter += new DragEventHandler(listBox1_DragEnter);
this.listBox1.DragDrop += new DragEventHandler(listBox1_DragDrop);
}
void listBox1_DragDrop(object sender, DragEventArgs e)
{
//code to add labelText to Items of ListBox
}
void listBox1_DragEnter(object sender, DragEventArgs e)
{
//set DragDropEffects;
}
now I have a label, code for which is as follows:
private void label1_MouseDown(object sender, MouseEventArgs e)
{
DoDragDrop((sender as Label).Text, DragDropEffects.Copy);
//this.label1.DoDragDrop((sender as Label).Text, DragDropEffects.Copy);
//used one of them at a time.
}
but nothing happens. listbox DragEnter event never fires up. in fact, drag never happens.
whenever i try to drag label (text), not allowed windows cursor appears, instead of 'DragDropEffects.Copy's cursor
Drag and Drop doesn't take place..
when I modify the listbox (and the associated code) to accept files to be dropped on it from any other window, that works perfectly.
so..am unable to perform drag from a control kept on the form to another control kept on the same form.
am I missing something? am running windows XP.
I went through this and through this
please help...
Your code does work actually.
You just have to set the right drag effects in your event handlers.
void listBox1_DragDrop(object sender, DragEventArgs e)
{
e.Effect = DragDropEffects.Copy;
}
void listBox1_DragEnter(object sender, DragEventArgs e)
{
e.Effect = DragDropEffects.Copy;
}
Check if ListBox.AllowDrop is set to TRUE or not
The following is an example of what you need, with all the code (adding it here for whoever finds this post).
#region Initial Values
//Constructor:
public Form1() {
InitializeComponent();
}
private void Form1_Load( object sender, EventArgs e ) {
InitialValues();
}
private void InitialValues() {
PrepareDragAndDrop();
}
#endregion Initial Values
#region Drag & Drop
private void PrepareDragAndDrop() {
//For the object that receives the other dragged element:
TheSamplListBox.AllowDrop = true;
TheSamplListBox.DragEnter += TheSamplListBox_DragEnter;
TheSamplListBox.DragLeave += TheSamplListBox_DragLeave;
TheSamplListBox.DragDrop += TheSamplListBox_DragDrop;
//For the object that will be dragged:
TheSampleLabel.MouseDown += ( sender, args ) => DoDragDrop( TheSampleLabel.Text, DragDropEffects.Copy );
}
private void TheSamplListBox_DragEnter( object theReceiver, DragEventArgs theEventData ) {
theEventData.Effect = DragDropEffects.Copy;
//Only the code above is strictly for the Drag & Drop. The following is for user feedback:
//You can use [TheSamplListBox] but this approach allows for multiple receivers of the same type:
var theReceiverListBox = (ListBox) theReceiver;
theReceiverListBox.BackColor = Color.LightSteelBlue;
}
private void TheSamplListBox_DragLeave( object theReceiver, EventArgs theEventData ) {
//No code here for the Drag & Drop. The following is for user feedback:
//You can use [TheSamplListBox] but this approach allows for multiple receivers of the same type:
var theReceiverListBox = (ListBox) theReceiver;
theReceiverListBox.BackColor = Color.White;
}
private void TheSamplListBox_DragDrop( object theReceiver, DragEventArgs theEventData ) {
//You can use [TheSamplListBox] but this approach allows for multiple receivers of the same type:
var theReceiverListBox = (ListBox) theReceiver;
//Get the data being dropped. In this case, a string:
var theStringBeingDropped = theEventData.Data.GetData( "System.String" );
//Add the string to the ListBox:
theReceiverListBox.Items.Add( theStringBeingDropped );
//Only the code above is strictly for the Drag & Drop. The following is for user feedback:
theReceiverListBox.BackColor = Color.White;
}
#endregion Drag & Drop
.

Categories