Drag and drop using a class method - c#

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!

Related

Keep the cursor at default shape during drag and drop operation in windows forms c#

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;
}

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;
}

Double Click on label open Form C#

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!

Drag & Drop from Windows Explorer into my application’s TextBox

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.

Auto highlight text in a textbox control

How do you auto highlight text in a textbox control when the control gains focus.
In Windows Forms and WPF:
textbox.SelectionStart = 0;
textbox.SelectionLength = textbox.Text.Length;
If you want to do it for your whole WPF application you can do the following:
- In the file App.xaml.cs
protected override void OnStartup(StartupEventArgs e)
{
//works for tab into textbox
EventManager.RegisterClassHandler(typeof(TextBox),
TextBox.GotFocusEvent,
new RoutedEventHandler(TextBox_GotFocus));
//works for click textbox
EventManager.RegisterClassHandler(typeof(Window),
Window.GotMouseCaptureEvent,
new RoutedEventHandler(Window_MouseCapture));
base.OnStartup(e);
}
private void TextBox_GotFocus(object sender, RoutedEventArgs e)
{
(sender as TextBox).SelectAll();
}
private void Window_MouseCapture(object sender, RoutedEventArgs e)
{
var textBox = e.OriginalSource as TextBox;
if (textBox != null)
textBox.SelectAll();
}
In ASP.NET:
textbox.Attributes.Add("onfocus","this.select();");
It is very easy to achieve with built in method SelectAll
Simply cou can write this:
txtTextBox.Focus();
txtTextBox.SelectAll();
And everything in textBox will be selected :)
If your intention is to get the text in the textbox highlighted on a mouse click you can make it simple by adding:
this.textBox1.Click += new System.EventHandler(textBox1_Click);
in:
partial class Form1
{
private void InitializeComponent()
{
}
}
where textBox1 is the name of the relevant textbox located in Form1
And then create the method definition:
void textBox1_Click(object sender, System.EventArgs e)
{
textBox1.SelectAll();
}
in:
public partial class Form1 : Form
{
}
I think the easiest way is using TextBox.SelectAll like in an Enter event:
private void TextBox_Enter(object sender, EventArgs e)
{
((TextBox)sender).SelectAll();
}
Here's the code I've been using. It requires adding the attached property to each textbox you wish to auto select. Seeing as I don't want every textbox in my application to do this, this was the best solution to me.
public class AutoSelectAll
{
public static bool GetIsEnabled(DependencyObject obj)
{
return (bool)obj.GetValue(IsEnabledProperty);
}
public static void SetIsEnabled(DependencyObject obj, bool value)
{
obj.SetValue(IsEnabledProperty, value);
}
static void ue_Loaded(object sender, RoutedEventArgs e)
{
var ue = sender as FrameworkElement;
if (ue == null)
return;
ue.GotFocus += ue_GotFocus;
ue.GotMouseCapture += ue_GotMouseCapture;
}
private static void ue_Unloaded(object sender, RoutedEventArgs e)
{
var ue = sender as FrameworkElement;
if (ue == null)
return;
//ue.Unloaded -= ue_Unloaded;
ue.GotFocus -= ue_GotFocus;
ue.GotMouseCapture -= ue_GotMouseCapture;
}
static void ue_GotFocus(object sender, RoutedEventArgs e)
{
if (sender is TextBox)
{
(sender as TextBox).SelectAll();
}
e.Handled = true;
}
static void ue_GotMouseCapture(object sender, MouseEventArgs e)
{
if (sender is TextBox)
{
(sender as TextBox).SelectAll();
}
e.Handled = true;
}
public static readonly DependencyProperty IsEnabledProperty = DependencyProperty.RegisterAttached("IsEnabled", typeof(bool),
typeof(AutoSelectAll), new UIPropertyMetadata(false, IsEnabledChanged));
static void IsEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var ue = d as FrameworkElement;
if (ue == null)
return;
if ((bool)e.NewValue)
{
ue.Unloaded += ue_Unloaded;
ue.Loaded += ue_Loaded;
}
}
}
The main change I made here was adding a loaded event to many of the examples I've seen. This allows the code to continue working after it's unloaded (ie. a tab is changed). Also I included code to make sure the text gets selected if you click on the textbox with the mouse, and not just keyboard focus it. Note: If you actually click on the text in the textbox, the cursor is inserted between the letters as it should.
You can use this by including the following tag in your xaml.
<TextBox
Text="{Binding Property}"
Library:AutoSelectAll.IsEnabled="True" />
If you need to do this for a large number of textboxes (in Silverlight or WPF), then you can use the technique used in the blog post: http://dnchannel.blogspot.com/2010/01/silverlight-3-auto-select-text-in.html. It uses Attached Properties and Routed Events.
You can use this, pithy. :D
TextBox1.Focus();
TextBox1.Select(0, TextBox1.Text.Length);
If you wanted to only select all the text when the user first clicks in the box, and then let them click in the middle of the text if they want, this is the code I ended up using.
Just handling the FocusEnter event doesn't work, because the Click event comes afterwards, and overrides the selection if you SelectAll() in the Focus event.
private bool isFirstTimeEntering;
private void textBox_Enter(object sender, EventArgs e)
{
isFirstTimeEntering = true;
}
private void textBox_Click(object sender, EventArgs e)
{
switch (isFirstTimeEntering)
{
case true:
isFirstTimeEntering = false;
break;
case false:
return;
}
textBox.SelectAll();
textBox.SelectionStart = 0;
textBox.SelectionLength = textBox.Text.Length;
}
if you want to select all on "On_Enter Event" this won't Help you achieving your goal.
Try using "On_Click Event"
private void textBox_Click(object sender, EventArgs e)
{
textBox.Focus();
textBox.SelectAll();
}
On events "Enter" (for example: press Tab key) or "First Click" all text will be selected. dotNET 4.0
public static class TbHelper
{
// Method for use
public static void SelectAllTextOnEnter(TextBox Tb)
{
Tb.Enter += new EventHandler(Tb_Enter);
Tb.Click += new EventHandler(Tb_Click);
}
private static TextBox LastTb;
private static void Tb_Enter(object sender, EventArgs e)
{
var Tb = (TextBox)sender;
Tb.SelectAll();
LastTb = Tb;
}
private static void Tb_Click(object sender, EventArgs e)
{
var Tb = (TextBox)sender;
if (LastTb == Tb)
{
Tb.SelectAll();
LastTb = null;
}
}
}
I don't know why nobody mentioned that but you can also do this, it works for me
textbox.Select(0, textbox.Text.Length)
textBoxX1.Focus();
this.ActiveControl = textBoxX1;
textBoxX1.SelectAll();
In window form c#. If you use Enter event it will not work. try to use MouseUp event
bool FlagEntered;
private void textBox1_MouseUp(object sender, MouseEventArgs e)
{
if ((sender as TextBox).SelectedText == "" && !FlagEntered)
{
(sender as TextBox).SelectAll();
FlagEntered = true;
}
}
private void textBox1_Leave(object sender, EventArgs e)
{
FlagEntered = false;
}
textbox.Focus();
textbox.SelectionStart = 0;
textbox.SelectionLength = textbox.Text.Length;

Categories

Resources