Hi Megidolaon,
Based on my understanding, you want to select multiple controls which likes selecting multiple cells in the excel. For example, when you pressed the Ctrl key and click several cells, all the cells would be selected. Another case is selecting a region. When you click and hold on the mouse, then drag the mouse, it would draw a rectangle and all the cells in the rectangle would be selected. If I misunderstood you, please feel free to tell me.
These are the main ideas of my solution:
1. Handle the MouseDown event of each control to handle the control select. If the Control key is pressed, we only need to select the new control. Otherwise, we need to unselect all the controls and then select the new control.
2. Handle the MouseDown event of the form or our user control to unselect all the controls.
3. Handle the KeyDown and KeyUp events of each control and the form to update the Control key state. We need to know if the Control key is pressed when we handle the control selecting.
4. Create a transparent form to draw the select rectangle.
5. Create a event to trace the select rectangle changing and handle the control selecting. If a control is in the select rectangle, select it; otherwise, unselect it.
This is my code snippet:
Form:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
//Initial the control collection
for (int i = 0; i < 10; i++)
{
Button bt = new Button();
bt.Name = i.ToString();
bt.Text = i.ToString();
bt.Location = new Point(100, i * (bt.Height + 2) + 20);
_controls.Add(bt);
this.Controls.Add(bt);
}
//Set the event handlers of the controls.
foreach (Control ctrl in _controls)
{
ctrl.MouseDown += new MouseEventHandler(ctrl_MouseDown);
ctrl.KeyDown += new KeyEventHandler(ctrl_KeyDown);
ctrl.KeyUp += new KeyEventHandler(ctrl_KeyUp);
}
//Set the event handlers of the form.
this.KeyDown += new KeyEventHandler(ctrl_KeyDown);
this.KeyUp += new KeyEventHandler(ctrl_KeyUp);
this.MouseDown += new MouseEventHandler(Form1_MouseDown);
//Set the event handlers of the RectangleDrawer.
RectangleDrawer.Move += new EventHandler<MoveArgs>(RectangleDrawer_Move);
}
//Handle the select rectangle changing event.
private void RectangleDrawer_Move(object sender, MoveArgs e)
{
//Check each control, if it is in the rectangle, select; otherwise, unselect it.
foreach (Control ctrl in _controls)
{
if (e.SelectRect.IntersectsWith(ctrl.RectangleToScreen(ctrl.DisplayRectangle)))
this.SelectControl(ctrl);
else
this.UnselectControl(ctrl);
}
}
//Update the state to indicate the Control key is not pressed.
private void ctrl_KeyUp(object sender, KeyEventArgs e)
{
if (e.Control)
_isControlPressed = false;
}
//Update the state to indicate the Control key is pressed.
private void ctrl_KeyDown(object sender, KeyEventArgs e)
{
if (e.Control)
_isControlPressed = true;
}
//Only select the control which the mouse clicks on.
private void ctrl_MouseDown(object sender, MouseEventArgs e)
{
if(_isControlPressed == false)
this.UnselectAll();
this.SelectControl((sender as Control));
}
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
//Start the select rectange drawing.
RectangleDrawer.Draw(this);
}
private void SelectControl(Control ctrl)
{
ctrl.BackColor = SELECT_BACK_COLOR;
}
private void UnselectControl(Control ctrl)
{
ctrl.BackColor = DEFAULT_BACK_COLOR;
}
private void UnselectAll()
{
foreach (Control ctrl in _controls)
{
ctrl.BackColor = DEFAULT_BACK_COLOR;
}
}
private static readonly Color SELECT_BACK_COLOR = SystemColors.ActiveCaption;
private static readonly Color DEFAULT_BACK_COLOR = SystemColors.Control;
private bool _isControlPressed = false;
private List<Control> _controls = new List<Control>();
}
Select rectangle drawing class:
public static class RectangleDrawer
{
private static Form mMask;
private static Point mPos;
public static Rectangle Draw(Form parent)
{
// Record the start point
mPos = parent.PointToClient(Control.MousePosition);
// Create a transparent form on top of <frm>
mMask = new Form();
mMask.FormBorderStyle = FormBorderStyle.None;
mMask.BackColor = Color.Magenta;
mMask.TransparencyKey = mMask.BackColor;
mMask.ShowInTaskbar = false;
mMask.StartPosition = FormStartPosition.Manual;
mMask.Size = parent.ClientSize;
mMask.Location = parent.PointToScreen(Point.Empty);
mMask.MouseMove += MouseMove;
mMask.MouseUp += MouseUp;
mMask.Paint += PaintRectangle;
mMask.Load += DoCapture;
// Display the overlay
mMask.ShowDialog(parent);
// Clean-up and calculate return value
mMask.Dispose();
mMask = null;
Point pos = parent.PointToClient(Control.MousePosition);
int x = Math.Min(mPos.X, pos.X);
int y = Math.Min(mPos.Y, pos.Y);
int w = Math.Abs(mPos.X - pos.X);
int h = Math.Abs(mPos.Y - pos.Y);
return new Rectangle(x, y, w, h);
}
//Rectangle changing event.
public static event EventHandler<MoveArgs> Move;
private static void DoCapture(object sender, EventArgs e)
{
// Grab the mouse
mMask.Capture = true;
}
private static void MouseMove(object sender, MouseEventArgs e)
{
// Repaint the rectangle
mMask.Invalidate();
if (Move != null && mMask != null && mMask.Visible)
{
//Fire the rectangle changing event.
Rectangle rect = Rectangle.Empty;
Point start = Point.Empty;
if (e.X > start.X && e.Y > start.Y)
rect = Rectangle.FromLTRB(mPos.X,mPos.Y,e.X,e.Y);
else if (e.X < start.X && e.Y < start.Y)
rect = Rectangle.FromLTRB(e.X, e.Y, mPos.X, mPos.Y);
if (rect != Rectangle.Empty) rect = mMask.RectangleToScreen(rect);
Move(null, new MoveArgs { SelectRect = rect });
}
}
private static void MouseUp(object sender, MouseEventArgs e)
{
// Done, close mask
mMask.Close();
}
private static void PaintRectangle(object sender, PaintEventArgs e)
{
// Draw the current rectangle
Point pos = mMask.PointToClient(Control.MousePosition);
using (Pen pen = new Pen(Brushes.Black))
{
pen.DashStyle = DashStyle.Dot;
e.Graphics.DrawLine(pen, mPos.X, mPos.Y, pos.X, mPos.Y);
e.Graphics.DrawLine(pen, pos.X, mPos.Y, pos.X, pos.Y);
e.Graphics.DrawLine(pen, pos.X, pos.Y, mPos.X, pos.Y);
e.Graphics.DrawLine(pen, mPos.X, pos.Y, mPos.X, mPos.Y);
}
}
}
//Select rectangle move arguments.
public class MoveArgs : EventArgs
{
public Rectangle SelectRect { set; get; }
}
You can get the old link about RectangleDrawer class from
http://social.msdn.microsoft.com/forums/en-US/winforms/thread/3087655c-bd50-4408-9c55-dd179e442675/.
Let me know if this helps.
Aland Li
Please mark the replies as answers if they help and unmark if they don't. This can be beneficial to other community members reading the thread.