Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to select multiple controls by mouse-dragging over them

I want to be able to drag over a bunch of controls and select those of a certain type (TextBoxes).

Once the dragging action has been completed, I want to display an inputbox (yes, I'll have to reference/use the VB .dll) prompting the user for the value that will be entered in each selected TextBox.

Can this be done? (of course, but how?)

Or is there another way to accomplish the same thing (allow the user to quickly select multiple controls and then perform an action on all of them at once)?

Updated:

I've got this sort of working - the "caveat" or "gotcha" being that I have to pop up a MessageBox.Show() to the user for it to work. Essentially, I:

Set a boolean to true on the container's (FlowLayoutPanel, in my case) MouseDown event, if the right mouse button was selected.

Set that same boolean to false on the container's MouseUp event, if the right mouse button was selected.

I then have a shared MouseHover event handler for all of the TextBoxes on that form that, if the boolean is true, changes the BackColor (to Gainsboro, in my case, from Window).

In the container's MouseUp event, I also use an InputBox (referencing/importing/using the VB .dll) requesting the user enter the value that will be common for the "highlighted" TextBoxes. I then loop through them, looking for those with that BackColor, and assing the user-supplied value to their Text properties.

Voila!

Unfortunately, the TextBoxes' Modified property does not seem to be altered when you assign it values this way, so I had to work around that (explicitly setting the "Save" button to enabled), and I had to add more code to duplicate my KeyPressed code which limits the values entered by the user.

So, it is, of course, possible, albeit a little kludgy. I haven't decided if the MessageBox.Show() is a "bug" or a feature, though...

A related post is: Why does MouseHover event only get called if a messagebox.show() or breakpoint occurs before it?

like image 316
B. Clay Shannon-B. Crow Raven Avatar asked Dec 21 '22 22:12

B. Clay Shannon-B. Crow Raven


1 Answers

This is actually very simple. I assume by drag you mean that you want to 'select' controls, like you would 'select' some pixels in a paint program for example. Here is an example I wrote you that does just this and only selects TextBox controls. It ignores other controls.

namespace WindowsFormsApplication5
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    using System.Drawing.Drawing2D;

    /// <summary>
    /// Main application form
    /// </summary>
    public partial class Form1 : Form
    {
        /// <summary>
        /// Initializes a new instance of the WindowsFormsApplication5.Form1 class
        /// </summary>
        public Form1() {
            InitializeComponent();
            DoubleBuffered = true;
        }

        private Point selectionStart;
        private Point selectionEnd;
        private Rectangle selection;
        private bool mouseDown;

        private void GetSelectedTextBoxes() {
            List<TextBox> selected = new List<TextBox>();

            foreach (Control c in Controls) {
                if (c is TextBox) {
                    if (selection.IntersectsWith(c.Bounds)) {
                        selected.Add((TextBox)c);
                    }
                }
            }

            // Replace with your input box
            MessageBox.Show("You selected " + selected.Count + " textbox controls.");
        }

        protected override void OnMouseDown(MouseEventArgs e) {
            selectionStart = PointToClient(MousePosition);
            mouseDown = true;
        }

        protected override void OnMouseUp(MouseEventArgs e) {
            mouseDown = false;

            SetSelectionRect();
            Invalidate();

            GetSelectedTextBoxes();
        }

        protected override void OnMouseMove(MouseEventArgs e) {
            if (!mouseDown) {
                return;
            }

            selectionEnd = PointToClient(MousePosition);
            SetSelectionRect();

            Invalidate();
        }

        protected override void OnPaint(PaintEventArgs e) {
            base.OnPaint(e);

            if (mouseDown) {
                using (Pen pen = new Pen(Color.Black, 1F)) {
                    pen.DashStyle = DashStyle.Dash;
                    e.Graphics.DrawRectangle(pen, selection);
                }
            }
        }

        private void SetSelectionRect() {
            int x, y;
            int width, height;

            x = selectionStart.X > selectionEnd.X ? selectionEnd.X : selectionStart.X;
            y = selectionStart.Y > selectionEnd.Y ? selectionEnd.Y : selectionStart.Y;

            width = selectionStart.X > selectionEnd.X ? selectionStart.X - selectionEnd.X : selectionEnd.X - selectionStart.X;
            height = selectionStart.Y > selectionEnd.Y ? selectionStart.Y - selectionEnd.Y : selectionEnd.Y - selectionStart.Y;

            selection = new Rectangle(x, y, width, height);
        }
    }
}

Now there are limitations with this currently. The obvious is that this will not select a TextBox within a nested container control (eg. a panel on your form containing a TextBox). If that were the case the selection would be drawn underneath the panel, and the TextBox would not be selected because the code I wrote does not check nested containers.

You can easily update the code to do all of this however, but this should give you a solid start.

like image 141
David Anderson Avatar answered Dec 28 '22 06:12

David Anderson