Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Many drag and drop targets, but no way to 'handle' them efficiently?

Status
Not open for further replies.

Amesville

Programmer
Oct 10, 2011
93
US
New Question: The C# 2008 app I'm working on needs to be a drag and drop interface where the contents of any textbox should be able to be copied / moved to any other textbox on the form. I have the basic code to do this and it is working fine. The problem I have is that there are over 100 textboxes on the form, and writing the specific statements required to cover all of them one at a time will surely cause an out of memory error. (Kidding of course but it's a lot of repeated code and I'd like to find a way to reduce the number of lines way down.

If I were working in Visual Basic I would simply use a Handles statement to have one set of code work for all of the textboxes on the form. But this is C# and there is no Handles statement. How would I do something like this in C# without that?

If it helps I can break up the text boxes into seven different groups of like items. Might be easier for readability and seven groups may be better than one huge group, and certainly better than over 100 individual objects being handled the same way.

Thanks for any help you can offer!

Craig
 
Well, I managed to figure out the answer for myself - amazingly in nearly all the posts I read on the subject no one managed to convey how to do this in a clear fashion. Allow me to try:

In lieu of the Handles clause in VB.NET, it is actually simple to create a single procedure that "Handles" the events for several like controls (like text boxes). What you do is create a generic routine almost exactly like the routine you would write for each individual control, but just once. Then you include a statement like this:

TextBox txt = (TextBox)sender;

...At the beginning of the routine. Where you would normally include the name of the individual control you simply use tst instead and use the dot operator and properties / methods as you normally would.

Then you assign events on each textbox and link them to the generic routine by clicking on each control and then opening the Events area of the Properties window. For Drag and Drop, you create the routines below and then in the DragDrop, DragEnter and MouseDown events you select the appropriate routine name to link it to. You can link as many controls to the routines as you want and because you are referencing the Sender the common routine will work for ALL the controls linked to it.

Hope this helps someone. Seems like something incredibly useful that isn't explained clearly almost anywhere. I got luck after hours of searching and found an undocumented piece of code that showed me the way.

Craig


Code:
        private void TextBox_MouseDown(object sender, MouseEventArgs e)
        {
            TextBox txt = (TextBox)sender;
            if (txt.Text != "")
            {
                if ((txt.BackColor == Color.LightGreen) || (txt.BackColor == Color.LightGray))
                    return;
                DragDropEffects ddRtn = DoDragDrop(txt.Text, DragDropEffects.Copy);
                if (ddRtn == DragDropEffects.Copy)
                {
                    txt.BackColor = Color.LightGray;
                }
            }
        }

        private void TextBox_DragEnter(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.Text))
                e.Effect = DragDropEffects.Copy;
            else
                e.Effect = DragDropEffects.None;
        }

        private void TextBox_DragDrop(object sender, DragEventArgs e)
        {
            TextBox txt = (TextBox)sender;
            if (txt.BackColor == Color.LightGreen)
                return;
            txt.Text = (string)e.Data.GetData(DataFormats.Text);
            txt.BackColor = Color.LightGreen;
        }
 
For this type of scenerio I prefer to explicitly link the controls in the (non-Designer) code rather than at design time. That way the multiple-link intent is more up-front than hidden away in the Designer code. You could also pair-up this technique with your recent question on finding controls on a form.

Code:
public Form1()
{
    InitializeComponent();

    foreach (var control in this.Controls)
    {
        if (control is TextBox)
        {
            var tb = (TextBox)control;
            tb.MouseDown += TextBox_MouseDown;
            tb.DragEnter += TextBox_DragEnter;
            tb.DragDrop += TextBox_DragDrop;
        }
    }

}


 
Dave, thanks. That definitely looks like a better method. I'll include it!
 
As an afterthought, you could also do a check and link only those text boxes that are drop enabled and also use Rhys technique to examine nested controls.

Code:
public Form1()
{
    InitializeComponent();

    WireUpAllDropEnabledTextBoxes(this);

}

private void WireUpAllDropEnabledTextBoxes(Control baseControl)
{
    foreach (Control control in baseControl.Controls)
    {
        WireUpAllDropEnabledTextBoxes(control);

        if (control is TextBox && (control as TextBox).AllowDrop)
        {
            var tb = (TextBox)control;
            tb.MouseDown += TextBox_MouseDown;
            tb.DragEnter += TextBox_DragEnter;
            tb.DragDrop += TextBox_DragDrop;
        }

    }
}
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top