C# Drag and Drop from one Picture box into Another - c#

I'm working in visual studio 2012 with C# and I need to Drag a Picture box into another picture box, basically replace the target Picturebox Image with the Dragged Picture box image.
How do I do this?
Please be specific and try to explain as simplest and as best as possible.
I'm extremely new to programming, and a bit desperate so please be patient with me.

Drag+drop is hidden on the PictureBox control. Not sure why, it works just fine. The probable guidance here is that it will not be obvious to the user that you could drop an image on the control. You'll have to do something about that, at least set the BackColor property to a non-default value so the user can see it.
Anyhoo, you'll need to implement the MouseDown event on the first picturebox so you can click it and start dragging:
private void pictureBox1_MouseDown(object sender, MouseEventArgs e) {
var img = pictureBox1.Image;
if (img == null) return;
if (DoDragDrop(img, DragDropEffects.Move) == DragDropEffects.Move) {
pictureBox1.Image = null;
}
}
I assumed you wanted to move the image, tweak if necessary if copying was intended. Then you'll have to implement the DragEnter and DragDrop events on the second picturebox. Since the properties are hidden, you should set them in the form's constructor. Like this:
public Form1() {
InitializeComponent();
pictureBox1.MouseDown += pictureBox1_MouseDown;
pictureBox2.AllowDrop = true;
pictureBox2.DragEnter += pictureBox2_DragEnter;
pictureBox2.DragDrop += pictureBox2_DragDrop;
}
void pictureBox2_DragEnter(object sender, DragEventArgs e) {
if (e.Data.GetDataPresent(DataFormats.Bitmap))
e.Effect = DragDropEffects.Move;
}
void pictureBox2_DragDrop(object sender, DragEventArgs e) {
var bmp = (Bitmap)e.Data.GetData(DataFormats.Bitmap);
pictureBox2.Image = bmp;
}
This does allow you to drag an image from another application into the box. Let's call it a feature. Use a bool flag if you want to disallow this.

Hans's answer led me to the correct solution. The problem with that answer is that putting DoDragDrop inside MouseDown will prevent MouseClick events from firing.
Here's my solution:
private void PictureBox_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
var pb = (PictureBox)sender;
if (pb.BackgroundImage != null)
{
pb.DoDragDrop(pb, DragDropEffects.Move);
}
}
}
private void PictureBox_DragEnter (object sender, DragEventArgs e)
{
e.Effect = DragDropEffects.Move;
}
private void PictureBox_DragDrop (object sender, DragEventArgs e)
{
var target = (PictureBox)sender;
if (e.Data.GetDataPresent(typeof(PictureBox)))
{
var source = (PictureBox)e.Data.GetData(typeof(PictureBox));
if (source != target)
{
// You can swap the images out, replace the target image, etc.
SwapImages(source, target);
}
}
}
Full working example on my GitHub.

You can use mouse enter and leave events to do this easily. For example you have two picture boxes pictureBox1 and pictureBox2. And you want to drag the image from picture box1 and drop it onto picture box2 do somthing like this.
private void pictureBox2_MouseUp(object sender, MouseEventArgs e)
{
if (a == 1)
{
pictureBox1.Image = pictureBox2.Image;
a = 0;
}
}
private void pictureBox1_MouseEnter(object sender, EventArgs e)
{
a = 1;
}
Where 'a' is just a lock or key which checks whether the mouse has entered the control on which we want to drop this image on. Hope it helped, worked for me.

You can't set AllowDrop on PictureBox...set it for your whole form.
Code Snippet
Form1.AllowDrop = true;
Use the Form DragEnter, DragDrop events, they will work even if you drop it over the pictureBox.
private void Form1_DragEnter(object sender, DragEventArgs e)
{
e.Effect = DragDropEffects.Move;
}
private void Form1_DragDrop(object sender, DragEventArgs e)
{
int x = this.PointToClient(new Point(e.X, e.Y)).X;
int y = this.PointToClient(new Point(e.X, e.Y)).Y;
if(x >= pictureBox1.Location.X && x <= pictureBox1.Location.X + pictureBox1.Width && y >= pictureBox1.Location.Y && y <= pictureBox1.Location.Y + pictureBox1.Height)
{
string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);
pictureBox1.Image = Image.FromFile(files[0]);
}
}

Related

How to regain focus in application after drag and drop to grid

In my application, I have a form with two panels. Inside one panel is a button. Inside the other is a DevExpress Grid control. The grid is made up of 3 columns. You can drag values from one column into the other to copy it.
My problem is that whenever I do a drag-and-drop from one column to another, the focus on the application goes into an unusual state. The grid remains focused; I can mouse over the headers and see them react as normal. However the rest of the application is not focused. Mouse over the button in the other panel does not react, nor do the menus or form controls. If I click on the button, it reacts like I clicked on an unfocused application. I have to click again to actually activate the button. Same for every control except the grid.
I have tried using Activate() and Focus() on the button and form but to no avail.
namespace Company.StuffUploader
{
public partial class ComputationGrid : DevExpress.XtraEditors.XtraUserControl
{
private BindingList<ComputationLinkModel> _links = new BindingList<ComputationLinkModel>();
public List<ComputationLinkModel> ComputationLinkModels
{
get
{
return new List<ComputationLinkModel>(_links);
}
}
public ComputationGrid()
{
InitializeComponent();
}
private void ComputationGrid_Load(object sender, EventArgs e)
{
_gridControl.DataSource = _links;
}
private DragDropEffects GetDragEffect(DragEventArgs e)
{
var text = e.Data.GetData("System.String") as string;
if (text == null)
return DragDropEffects.None;
var link = GetLinkFromScreenPoint(new Point(e.X, e.Y));
if (link == null)
return DragDropEffects.None;
var tokens = text.Split('\t');
if (tokens.Count() != 2)
return DragDropEffects.None;
var dateString = link.movedate.ToString("yyyy-MM-dd");
if (link.StuffSurfaceName == tokens[0] && dateString != tokens[1])
return DragDropEffects.Move;
else
return DragDropEffects.None;
}
private ComputationLinkModel GetLinkFromScreenPoint(Point screenPt)
{
var pt = _gridControl.PointToClient(screenPt);
var hitInfo = _gridView.CalcHitInfo(pt);
return _gridView.GetRow(hitInfo.RowHandle) as ComputationLinkModel;
}
private void _gridControl_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
var hitInfo = _gridView.CalcHitInfo(e.Location);
if (hitInfo == null || !hitInfo.InRowCell)
return;
// Only allow dragging from target column
if (hitInfo.Column.AbsoluteIndex != 0)
return;
var link = _gridView.GetRow(hitInfo.RowHandle) as ComputationLinkModel;
if (link == null)
return;
var item = string.Format("{0}\t{1}", link.StuffSurfaceName, link.movedate.ToString("yyyy-MM-dd"));
DoDragDrop(item, DragDropEffects.Move);
}
}
private void _gridControl_DragOver(object sender, DragEventArgs e)
{
e.Effect = GetDragEffect(e);
}
private void _gridControl_DragDrop(object sender, DragEventArgs e)
{
}
private void _gridControl_DragEnter(object sender, DragEventArgs e)
{
e.Effect = GetDragEffect(e);
}
private void _unlinkButton_Click(object sender, EventArgs e)
{
}
}
}
I figured out my own problem. Calling DoDragDrop() from within MouseDown event does not seem to work correctly. The proper way is to call it from MouseMove(). The documentation on MSDN hints at this in its example code.
Ensure that you set the DXMouseEventArgs.Handled property to true in the GridView's Mouse~ event handlers. It guarantees that default handling of these events will be prohibited. Review this example to see how to do this.

Drag'n Drop : tell the sender when drop occurs

I'm using c# 3.5 / winforms
On my form, I have 2 picturebox PB1 and PB2 (and lots of others controls), in a panel.
The user can drag PB1 to PB2. But he can also cancel the drop by release the left button anywhere on the form or outside the form.
PB1 can be dragged a fixed number of times. When the drag start, I decrease a variable in PB1 and if it reach 0, the PB became invisible.
But if the user cancel the drag, PB1 must know that to increase the variable and set the visibility of PB1.
My problem is : how PB1 can know when a drag is canceled (or actually, dropped, even on a valid control) ? Remember that the user can release the drag outside of the form, so I can't use the Drop event on the form. I try the GiveFeedback and the QueryContinueDrag events, but they are fired as long as the drag continue, but not when it stop.
Some code :
class COPGOJetonImage
{
private PictureBox PB1;
public COPGOJetonImage()
{
PB1 = new PictureBox();
//here I initialize PB1
((Control)PB1).AllowDrop = true; //in case of
PB1.MouseDown += OnMouseDown;
}
public void OnMouseDown(object sender, MouseEventArgs ev)
{
PB1.DoDragDrop(PB1.Image, DragDropEffects.Copy);
}
}
"there are 1 to 4 valid targets."
In this example we are dragging pictureBox1, and pictureBox2 thru pictureBox5 are the valid drop targets. We create a DataObject with a custom name to encapsulate pictureBox1 during the drag/drop operation. In the drop targets, we only allow a drop if the custom name is present in the thing being dragged. This ensures we only get a DragDrop event from pictureBox1 itself, and we know it's safe to decrement our drop counter. We can retrieve pictureBox1 back from the DataObject and change its state so that it can no longer be dropped:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private int DropsLeft = 5;
private string DataFormatName = "YourUniqueDataFormatNameHere";
private void Form1_Load(object sender, EventArgs e)
{
pictureBox1.MouseMove += PictureBox1_MouseMove;
PictureBox[] pbs = new PictureBox[] { pictureBox2, pictureBox3, pictureBox4, pictureBox5 };
foreach (PictureBox pb in pbs)
{
pb.AllowDrop = true;
pb.DragEnter += Pb_DragEnter;
pb.DragDrop += Pb_DragDrop;
}
}
private void PictureBox1_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
DataObject data = new DataObject(DataFormatName, pictureBox1);
pictureBox1.DoDragDrop(data, DragDropEffects.Copy);
}
}
private void Pb_DragEnter(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(DataFormatName))
{
e.Effect = DragDropEffects.All;
}
else
{
e.Effect = DragDropEffects.None;
}
}
private void Pb_DragDrop(object sender, DragEventArgs e)
{
DropsLeft--;
// retrieve the data
PictureBox pb = (PictureBox)e.Data.GetData(DataFormatName);
if (DropsLeft == 0)
{
MessageBox.Show("No more drops left!");
pb.Enabled = false;
pb.BackColor = Color.Red; // for visual effect
}
}
}

C# Drag and Drop - Muliple Pictures Box to Panel or Flow layout panel

I'm currently implementing drag & drop function in C# Window Forms. I've created multiple pictures box on left navigation, so user can drag and drop to right side panel.
But it does look like pictures box can not drop to the panel directly.
When i compile, it runs. But, when I drag and drop it makes following error:
"unable to cast object of type 'System.Windows.Forms.Panel' to type 'System.Windows.Forms.PictureBox'."
Please suggest how can i make drag and drop "picutre 1, 2, 3" to the panel accordingly.?
private void Form3_Load(object sender, EventArgs e)
{
pictureBox4.DragEnter += new DragEventHandler(pictureBox4_DragEnter);
pictureBox4.DragDrop += new DragEventHandler(pictureBox4_DragDrop);
pictureBox4.MouseDown += new MouseEventHandler(pictureBox4_MouseDown);
panel2.AllowDrop = true;
}
private void pictureBox4_DragDrop(object sender, DragEventArgs e)
{
PictureBox pb = (PictureBox)sender;
pb.Image = (Image)e.Data.GetData(DataFormats.Bitmap);
}
private void pictureBox4_MouseDown(object sender, MouseEventArgs e)
{
PictureBox pb = (PictureBox)sender;
pb.Select();
pb.DoDragDrop(pb.Image, DragDropEffects.Copy);
panel1.Show();
}
private void panel2_DragDrop(object sender, DragEventArgs e)
{
PictureBox pb = (PictureBox)sender;
pb.Image = (Image)e.Data.GetData(DataFormats.Bitmap);
}
private void panel2_DragEnter(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(DataFormats.Bitmap))
{
e.Effect = DragDropEffects.Copy;
}
else
{
e.Effect = DragDropEffects.None;
}
}
I suppose in this code your sender is actually a Panel. Check it's type in the debugger:
private void panel2_DragDrop(object sender, DragEventArgs e)
{
PictureBox pb = (PictureBox)sender;
pb.Image = (Image)e.Data.GetData(DataFormats.Bitmap);
}
As a good principle always do typecasting like this:
PictureBox pb = sender as PictureBox; // will give you null if it can't be cast to PictureBox
if(pb != null)
{
// do something...
}

Cancel dragging if the destination picturebox already has an image

I am making a drapandrop and it's working nice. But I want it to give a message whenever I try to drag an image into a picture that already contains one, that won't work... When I click on an image and drag it to the same picturebox where it came from (like I click on picturebox1 and drop it on picturebox1 it just gets blank), it just disappears.public partial class Form1 : Form
public Form1()
{
InitializeComponent();
pictureBox1.AllowDrop = true;
pictureBox2.AllowDrop = true;
pictureBox3.AllowDrop = true;
pictureBox4.AllowDrop = true;
pictureBox5.AllowDrop = true;
pictureBox6.AllowDrop = true;
}
void pictureBox_MouseDown(object sender, MouseEventArgs e)
{
DoDragDrop(sender, DragDropEffects.Move);
}
void pictureBox_DragEnter(object sender, DragEventArgs e)
{
e.Effect = DragDropEffects.Move;
}
void pictureBox_DragDrop(object sender, DragEventArgs e)
{
PictureBox pb = e.Data.GetData(typeof(PictureBox)) as PictureBox;
if (pb.Image != null)
{
((PictureBox)sender).Image = pb.Image;
pb.Image = null;
}
else
{
MessageBox.Show("The picturebox already contains an image.");
}
}
}
}
pb is a reference to the PictureBox that is being dragged. since you are droping on the same PictureBox you are dragging, pb and senrder are both referencing the same PictureBox, so the pb.Image = null; code line is clearing the image in the PictureBox. you need to add to your condition a check that pb is different then sender, like this:
if (pb.Image != null && !pb.Equals(sender))
edit
Basically, You should use the DragEnter Event for that. If the PictureBox already contains an Image, you can set the e.Effect to DragDropEffects.None. that will also provide a better solition to the problem you described in the first place.

knowing if the left button of mouse is released on the same list box

I have two list boxes, one for Avaiable Items and one for Selected items, so the user can move items between these two by either drag-drop or double-click.
It is not a perfect code and most of the logic is written in MouseMove event where I can have X and Y of the mouse location also...I am looking for this scenario to Prevent it: user holds left mouse button on the left list box and select an item BUT he releases the mouse button again on the same list box, so I need a way to know if it is still on the same list box then do not do the drag drop...so is there some method can tell me the boundaries of the list box that I can use? or any other better thoughts that you have?
private void lstAvailable_MouseMove(Object eventSender, MouseEventArgs eventArgs)
{
//*************** FUNCTION DETAILS ***************
//User moves mouse in the Available list
//***************** INSTRUCTIONS *****************
MouseButtons Button = eventArgs.Button;
int Shift = (int)Control.ModifierKeys / 0x10000;
float X = (float)VB6.PixelsToTwipsX(eventArgs.X);
float Y = (float)VB6.PixelsToTwipsY(eventArgs.Y);
moDualListBox.List1_MouseMove(Button, Shift, X, Y);
if (eventArgs.Button == MouseButtons.Left )
{
if (!mbClickProcessed) // it is a DragDrop
{
this.lstAvailable.DoDragDrop(this.lstAvailable.SelectedItems, DragDropEffects.Move);
mbClickProcessed = true;
}
if (mbClickProcessed) // it is a DoubleClick
{
MoveClick();
MoveLostFocus();
mbClickProcessed = true;
}
}
}
Sample for drag-drop (no error checking):
private ListBox _DraggingListBox = null;
private void listBox1_DragDrop(object sender, DragEventArgs e)
{
if (_DraggingListBox != listBox1)
MoveItem(listBox2, listBox1, (int)e.Data.GetData(typeof(int)));
}
private void listBox1_MouseDown(object sender, MouseEventArgs e)
{
_DraggingListBox = listBox1;
listBox1.DoDragDrop(listBox1.IndexFromPoint(e.X,e.Y), DragDropEffects.Move);
}
private void listBox1_DragOver(object sender, DragEventArgs e)
{
e.Effect = DragDropEffects.Move;
}
private void listBox2_DragDrop(object sender, DragEventArgs e)
{
if (_DraggingListBox != listBox2)
MoveItem(listBox1, listBox2, (int)e.Data.GetData(typeof(int)));
}
private void listBox2_DragOver(object sender, DragEventArgs e)
{
e.Effect = DragDropEffects.Move;
}
private void listBox2_MouseDown(object sender, MouseEventArgs e)
{
_DraggingListBox = listBox2;
listBox2.DoDragDrop(listBox2.IndexFromPoint(e.X,e.Y), DragDropEffects.Move);
}
private void MoveItem(ListBox fromLB, ListBox toLB, int index)
{
toLB.Items.Add(fromLB.Items[index]);
fromLB.Items.RemoveAt(index);
}
If you catch DragDrop event you have th sender of drag-drop operation.
So you can easily discard the operation (or do nothing) if sender is same as destination control...
If you want to know if mouse is leaving a control (and set a variable according to this) you can catch MouseLeave event, while MouseEnter event is handy to know when mouse enters a control from another one.

Categories