Why is the dragdrop event never entered?
private void textBox1_DragDrop(object sender, DragEventArgs e)
{
Array a = (Array)e.Data.GetData(DataFormats.FileDrop);
e.Effect = DragDropEffects.All;
Debug.WriteLine("were in dragdrop");
}
private void textBox1_DragEnter(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(DataFormats.FileDrop, false) == true)
{
e.Effect = DragDropEffects.All;
}
}
Change the e.Effect assignment to DragDropEffects.Copy. Double-check that the event assignment is still there, click the lightning bolt icon in the Properties window. Sample code is available in this thread. Note that you can cast to string[] directly.
Related
I am doing a simple drag and drop operation in windows forms. Whenever I start the operation the cursor changes shape. I know this is directly related to the DragDropEffects and I can't find an option that results in the default cursor. Can anybody help? Here is the code:
a.MouseDown += new MouseEventHandler(ButtonDown);
a.DragEnter += new DragEventHandler(ButtonDragEnter);
a.AllowDrop = true;
and here are the functions:
private void ButtonDown(object sender, EventArgs e)
{
PictureBox p = (PictureBox)sender;
ButtonClick(sender, e);
p.DoDragDrop(p.BackColor, DragDropEffects.All);
}
private void ButtonDragEnter(object sender, DragEventArgs e)
{
e.Data.GetFormats();
e.Effect = DragDropEffects.None;
Color c = new Color();
c = (Color) e.Data.GetData(c.GetType());
ButtonClick(sender, e,c);
}
Ok answered my own question here:
You first need to add an event to giveFeedBack:
a.GiveFeedback += new GiveFeedbackEventHandler(DragSource_GiveFeedback);
and here is the feedback function:
private void DragSource_GiveFeedback(object sender, GiveFeedbackEventArgs e)
{
e.UseDefaultCursors = false;
}
I'm having a bit of trouble making drag and drop a button in a panel and panel to recognize it and display Message with buttons name
So far I managed the part of dragging and dropping and recognizing however I'm missing the visual style of dragging, when I press with mouse it will just sit on the same place, it won't follow cursor. How do I make it follow the mouse?
public Form1()
{
InitializeComponent();
panel1.AllowDrop = true;
panel1.DragEnter += panel_DragEnter;
panel1.DragDrop += panel_DragDrop;
button1.MouseDown += button1_MouseDown;
}
private void button1_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
{
button1.DoDragDrop(button1.Text, DragDropEffects.Copy | DragDropEffects.Move);
button1.Location= new Point(e.X, e.Y);
}
private void panel_DragEnter(object sender, System.Windows.Forms.DragEventArgs e)
{
e.Effect = DragDropEffects.Move;
if (e.Data.GetDataPresent(DataFormats.Text))
e.Effect = DragDropEffects.Copy;
else
e.Effect = DragDropEffects.None;
}
private void panel_DragDrop(object sender, System.Windows.Forms.DragEventArgs e)
{
MessageBox.Show(e.Data.GetData(DataFormats.Text).ToString());
}
You'll have to keep in mind that the DoDragDrop method doesn't return the Position you dropped the object. The DragDrop event handles that.
To move the control while you're dragging you use the DragOver event of the panel. In the implementation you need to compensate for the fact that the X and Y coordinates in the EventArgs are Screen based while you need Clientbased coordinates to correctly position the control. The PointToClient is instrumental in that:
private void panel_DragOver(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(typeof(Button).FullName))
{
var draggedButton = (Button)e.Data.GetData(typeof(Button).FullName);
var screenpos = new Point(e.X, e.Y);
var clientPos = panel1.PointToClient(screenpos);
// calc offset
draggedButton.Location = new Point(
clientPos.X + panel1.Left,
clientPos.Y + panel1.Top);
}
}
Notice that your Data now contains the actual Button, instead of only the text. This makes that you can dragdrop multiple buttons, not only button1.
Your DragDrop event should now look like this:
private void panel_DragDrop(object sender, System.Windows.Forms.DragEventArgs e)
{
if (e.Data.GetDataPresent(typeof(Button).FullName))
{
var draggedButton = (Button)e.Data.GetData(typeof(Button).FullName);
MessageBox.Show(draggedButton.Text);
var screenpos = new Point(e.X, e.Y);
var clientPos = panel1.PointToClient(screenpos);
draggedButton.Location = new Point(
clientPos.X + panel1.Left,
clientPos.Y + panel1.Top);
}
}
And DragEnter only slightly changed so it could handle the Button control instead of the text:
private void panel_DragEnter(object sender, System.Windows.Forms.DragEventArgs e)
{
e.Effect = DragDropEffects.Move;
if (e.Data.GetDataPresent(typeof(Button).FullName)) // button
e.Effect = DragDropEffects.Copy;
else
e.Effect = DragDropEffects.None;
}
And finally to get it all started and wired up the constructor code and the MouseDown implementation of the button:
public Form1()
{
InitializeComponent();
panel1.AllowDrop = true;
panel1.DragEnter += panel_DragEnter;
panel1.DragDrop += panel_DragDrop;
panel1.DragOver += panel_DragOver;
button1.MouseDown += button1_MouseDown;
}
private void button1_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
{
button1.DoDragDrop(button1, DragDropEffects.Copy | DragDropEffects.Move);
}
Im trying to open a new form when a label is double clicked. Im able to drag and drop the label .Im trying to open a new form on double click of label now.
private void control_MouseDown(object sender, MouseEventArgs e)
{
var control = sender as Control;
this.DoDragDrop(control.Name, DragDropEffects.Move);
}
private void control_DoubleClick(object sender, EventArgs e)
{
frm = new Frm();
frm.ShowDialog();
frm.Dispose();
}
EDIT 1:
I have tried both possible answers below, and they have not worked for me?
A more cleaner way is (note I changed Frm to Form1):
private void control_DoubleClick(object sender, EventArgs e)
{
using (Form1 frm = new Form1())
{
frm.ShowDialog();
}
}
You can't add DragDrop on MouseDown and then DoubleClick. That won't work.
I don't think there's an easy way to get around that, but once a control is being dragged, it won't respond to double click messages.
I've made some quick tests, and there's a "hacky" way. It'll make your dragging look weird (since it'll start after some time, instead of immediately after you press the mouse button), but here it goes:
private bool _willDrag = false;
private bool control_MouseUp(object sender, MouseEventArgs e)
{
// disable dragging if we release the mouse button
_willDrag = false;
}
private bool control_DoubleClick(object sender, EventArgs e)
{
// disable dragging also if we double-click
_willDrag = false;
// .. the rest of your doubleclick event ...
}
private void control_MouseDown(object sender, MouseEventArgs e)
{
var control = sender as Control;
if (control == null)
return;
_willDrag = true;
var t = new System.Threading.Timer(s =>
{
var callingControl = s as Control;
if (callingControl == null)
return;
// if we released the mouse button or double-clicked, don't drag
if(!_willDrag)
return;
_willDrag = false;
Action x = () => DoDragDrop(callingControl.Name, DragDropEffects.Move);
if (control.InvokeRequired)
control.Invoke(x);
else
x();
}, control, SystemInformation.DoubleClickTime, Timeout.Infinite);
}
In the form.Designer right click on your label then properties, in the properties window click in events (the thunder icon), in the double_Click event dropdown select the event handler (control_DoubleClick) this method must have two parameters an object and a eventArgs
This is tricky as the DoDragDrop will eat up any further mouse events, and MSDN posting a rather stupid example doesn't help much.
Solution: Do not start the D&D in the MouseDown if you want to still receive click or double click events but use the MouseMove instead:
Replace this
private void control_MouseDown(object sender, MouseEventArgs e)
{
var control = sender as Control;
this.DoDragDrop(control.Name, DragDropEffects.Move);
}
by this:
private void control_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Left)
DoDragDrop((sender as Control), DragDropEffects.Move);
}
Don't forget to hook up the new event!
I have a range of drag drop activities all working fine on my quiz. (From answering questions to selecting an avatar)
There is a lot of repetition of the code and I am thinking it would be better implemented from a class and call the method each time that I use a drag drop.
Firstly can this be done? and secondly would I need a new method for the dragging and dropping?
Any thoughts or rough ideas would be great.
private void pictureBox2_MouseDown(object sender, MouseEventArgs e)
{
pictureBox2.DoDragDrop(pictureBox2.Image, DragDropEffects.Copy);
}
private void panel1_DragEnter(object sender, DragEventArgs e)
{
e.Effect = DragDropEffects.Copy;
}
private void panel1_DragDrop(object sender, DragEventArgs e)
{
//Set background image of panel to selected avatar'
panel1.BackgroundImage = (Image)e.Data.GetData(DataFormats.Bitmap);
}
If all you want is to avoid duplicating the same events of several controls you should use common events:
private void commonPBox_MouseDown(object sender, MouseEventArgs e)
{
PictureBox PB = sender as PictureBox;
if (PB == null) return; //or throw an exception
PB.DoDragDrop(PB.Image, DragDropEffects.Copy);
}
private void commonPanel_DragEnter(object sender, DragEventArgs e)
{
e.Effect = DragDropEffects.Copy;
}
private void commonPanel_DragDrop(object sender, DragEventArgs e)
{
Panel Pan = sender as Panel;
if (Pan == null) return; //or throw an exception
//Set background image of panel to selected avatar
Pan.BackgroundImage = (Image)e.Data.GetData(DataFormats.Bitmap);
}
Select the respective controls and enter the event names into the respective event name slots in the event pane of the properties tab.
Note how I cast the sender param of the event to get a types reference to the control that triggers the event. If the cast goes wrong the reference is set to null.
If you want more control and more flexibilty you may consider creating a DragAndDropcontroller class..:
static class DnDCtl
{
static List<Control> Targets = new List<Control>();
static List<Control> Sources = new List<Control>();
static public void RegisterSource(Control ctl)
{
if (!Sources.Contains(ctl) )
{
Sources.Add(ctl);
ctl.MouseDown += ctl_MouseDown;
}
}
static public void UnregisterSource(Control ctl)
{
if (Sources.Contains(ctl))
{
Sources.Remove(ctl);
}
}
static public void RegisterTarget(Control ctl)
{
if (!Targets.Contains(ctl))
{
Targets.Add(ctl);
ctl.DragEnter += ctl_DragEnter;
ctl.DragDrop += ctl_DragDrop;
ctl.AllowDrop = true;
}
}
static public void UnregisterTarget(Control ctl)
{
if (Targets.Contains(ctl))
{
Targets.Remove(ctl);
ctl.DragEnter -= ctl_DragEnter;
ctl.DragDrop -= ctl_DragDrop;
}
}
static void ctl_MouseDown(object sender, MouseEventArgs e)
{
PictureBox PB = sender as PictureBox;
if (PB != null) PB.DoDragDrop(PB.Image, DragDropEffects.Copy);
Panel Pan = sender as Panel;
if (Pan != null) Pan.DoDragDrop(Pan.BackgroundImage, DragDropEffects.Copy);
}
static void ctl_DragEnter(object sender, DragEventArgs e)
{
e.Effect = DragDropEffects.Copy;
}
static void ctl_DragDrop(object sender, DragEventArgs e)
{
Panel Pan = sender as Panel;
if (Pan != null) Pan.BackgroundImage = (Image)e.Data.GetData(DataFormats.Bitmap);
PictureBox PB = sender as PictureBox;
if (PB != null) PB.BackgroundImage = (Image)e.Data.GetData(DataFormats.Bitmap);
}
}
Notes:
I have coded symmetric actions for Panels and PictureBoxes to show how you can handle different controls.
I have created but not used Lists of sources and targets. For more complex projects you will find them useful.
I have coded both Register and Unregister methods. You can register after some condition and unregister when it no longer applies
Such a Controller is good for dynamically alowing or disallowing Drag&Drop for controls, esp. when you create them dynamically.
You could also pass around delegates to decouple the dragdrop action from the controller.
Also note that some folks sometimes do prefer to use the MouseMove event over MouseDown esp. as it won't so easily interfere with making a selection.
ListView has a dedicated event instead, ListView.ItemDrag, which obviously should be used when registering!
I want to drag panels from one tableLayoutPanel to another. I also want the panels to be copied, not moved; that is, I want them to be copied (from tableLayoutPanel1 to tableLayoutPanel2), leaving the item in tableLayoutPanel1.
Can I do this? If you can give me an idea, it will be great. Thank you
public Form1()
{
InitializeComponent();
panel1.AllowDrop = true;
panel2.AllowDrop = true;
panel3.AllowDrop = true;
panel1.DragEnter += panel_DragEnter;
panel2.DragEnter += panel_DragEnter;
panel1.DragDrop += panel_DragDrop;
panel2.DragDrop += panel_DragDrop;
}
private void panel3_MouseDown(object sender, MouseEventArgs e)
{
DoDragDrop(panel3, DragDropEffects.Copy);
}
private void panel3_MouseMove(object sender, MouseEventArgs e)
{
DoDragDrop(panel3, DragDropEffects.Copy);
}
private void panel_DragEnter(object sender, DragEventArgs e)
{
e.Effect = DragDropEffects.Copy;
}
private void panel_DragDrop(object sender, DragEventArgs e)
{
((Panel)e. Data . GetData(typeof(Panel))).Parent = (Panel)sender;
}
private void Form1_Load(object sender, EventArgs e)
{
}
}
}
You need to create a new panel in the MouseDown handler, set its properties like those of the original, add it to the form and use DoDragDrop with this new panel.