Hello I have a problem with my code. I added 44 Labels on form and try to make 2 event handlers for each Label in this way:
/// <summary>
/// Adds event handler methods to all Label controls on current form using foreach loop,
/// these handlers handle MouseDown and MouseMove events
/// </summary>
public void AddEventToLabels()
{
foreach (Control c in this.Controls)
{
if (c.GetType() == typeof(Label))
{
c.MouseDown = new MouseEventHandler(this.Label_MouseDown);
c.MouseMove = new MouseEventHandler(this.Label_MouseMove);
}
}
}
/// <summary>
/// Executes when button of mouse is pressed by user and cursor is over the control
/// </summary>
/// <param name="sender">The source of the event</param>
/// <param name="e">Provides data for the MouseUp, MouseDown, and MouseMove events</param>
public void Label_MouseDown(object sender, MouseEventArgs e)
{
md.StoreMouseLocation(e); //Just a method to store location of cursor
}
/// <summary>
/// Executes when user moves mouse and cursos is over the control
/// </summary>
/// <param name="sender">The source of the event</param>
/// <param name="e">Provides data for the MouseUp, MouseDown, and MouseMove events</param>
public void Label_MouseMove(object sender, MouseEventArgs e)
{
var label = sender as Label; //Casts sender object to control on current form
md.MoveControl(e, label); //Moves label with cursor
}
But these handlers don't work and I can't understand why. Well, how can I get it working right?
CodePudding user response:
The problem is about parent of control. I need to iterate all these controls in specified container because it is parent for all needed controls. So I use foreach (Control c in this.<ParentName>.Controls)
instead of foreach (Control c in this.Controls)
CodePudding user response:
Every Control
(Form, UserControl, but also buttons, textboxes etc) has zero or more sub controls. They can be accessed via property Control.Controls
You want to subscribe to events MouseDown and MouseMove for all Labels in your Form.
Of course you want to work according to proper object oriented ideas, so you Separate your Concerns. Among other things, you do this by making small methods that will have only one task. This way your methods will be easier to understand, better to reuse, easier to maintain, change and unit test.
So you give your Form several properties:
public IEnumerable<Control> SubControls => this.Controls.Cast<Control>();
IEnumerable<Lable> Labels => this.SubControls.OfType<Label>();
For efficiency you could change the last one in:
IEnumerable<Lable> Labels => this.Controls.OfType<Label>();
But I assume you won't be calling that method ten times per second, so I wouldn't bother: maintainability is the key here.
It seems to me that you want to implement drag & drop a label.
- on mouse down: Start dragging the label: save the label that must be moved; Save the mousedown location
- on mouse move: if we have are dragging a label, position the label at the mouse position
- on mouse up: stop dragging the label.
The position of the label during the drag is not the mouse position, but the position of the mouse the offset during mousedown.
Size DragLabelOffset {get; set;} = Size.Empty;
At start of dragging, DragLabelOffset will be the difference between the Location of the Label that is to be dragged and the mouse position at start of the drag. During dragging, the Location of the label is the current mouse position DragLableOffset.
void StartDragDropLabel(Label label, Position mouseDownPosition)
{
this.DraggedLabelOffset = new Size(mouseDownPosition.X - label.Location.X,
mouseDownPosition.Y - label.Location.Y);
}
void DragLabel(Label label, Position mousePosition)
{
label.Location = mousePosition this.DraggedLabelOffset;
}
void StopDragLabel(Label label, Position mousePosition)
{
// not sure if this is needed: set final drag position
this.DragLabel(label, mousePosition);
this.DragLabelOffset = Size.Empty; // indicate: no drag is active
}
The event handlers:
void Label_MouseDown(object sender, MouseEventArgs e)
{
Label label = (Label)sender;
this.StartDragDropLabel(label, e.Location);
}
void Label_MoveMove(object sender, MouseEventArgs e)
{
Label label = (Label)sender;
this.DragLabel(label, e.Location);
}
void Label_MouseUp(object sender, MouseEventArgs e)
{
Label label = (Label)sender;
this.StopDragLabel(label, e.Location);
}
Subscribe to Mouse Events:
void SubscribeLabelsToMouseEvents()
{
foreach (Label label in this.Labels)
{
label.MouseDown = this.Label_MouseDown;
label.MouseMove = this.Label_MouseMove;
label.MouseUp = this.Label_MouseUp
}
Although older code used to create new EventHandler(...)
, there is no need for this, modern compiler will understand this without an EventHandler.