你好,我的代码有问题。我在表单上添加了44个标签,并尝试以这种方式为每个标签创建2个事件处理程序:
/// <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
}
但是这些处理程序不起作用,我不明白为什么。那我怎么才能让它正常工作呢?
每个Control
(表单,UserControl,还有按钮,文本框等)都有零个或多个子控件。可以通过property Control访问它们。控制
你想订阅事件MouseDown和MouseMove的所有标签在你的表单。
当然你想要根据正确的面向对象的思想工作,所以你把你的关注点分开。除此之外,您可以通过创建只有一个任务的小方法来实现这一点。这样,您的方法将更容易理解,更好地重用,更容易维护,更改和单元测试。
所以你给你的表单几个属性:
public IEnumerable<Control> SubControls => this.Controls.Cast<Control>();
IEnumerable<Lable> Labels => this.SubControls.OfType<Label>();
为了提高效率,你可以把最后一个改成:
IEnumerable<Lable> Labels => this.Controls.OfType<Label>();
但是我假设你不会每秒调用这个方法十次,所以我就不麻烦了:可维护性是这里的关键。
在我看来,你想实现拖拽&删除标签
- 按下鼠标:开始拖动标签:保存必须移动的标签;保存鼠标按下位置
- 鼠标移动:如果我们正在拖动标签,将标签放置在鼠标位置
- 鼠标向上:停止拖动标签。
标签在拖动过程中的位置不是鼠标的位置,而是鼠标的位置+鼠标下移时的偏移量。
Size DragLabelOffset {get; set;} = Size.Empty;
在拖动开始时,DragLabelOffset将是要拖动的标签位置与拖动开始时鼠标位置之间的差值。在拖动过程中,标签的位置为当前鼠标位置+ 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
}
事件处理程序:
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);
}
订阅鼠标事件:
void SubscribeLabelsToMouseEvents()
{
foreach (Label label in this.Labels)
{
label.MouseDown += this.Label_MouseDown;
label.MouseMove += this.Label_MouseMove;
label.MouseUp += this.Label_MouseUp
}
虽然旧的代码用来创建new EventHandler(...)
,但没有必要这样做,现代编译器不需要EventHandler也能理解。
问题是关于父控件。我需要在指定的容器中迭代所有这些控件,因为它是所有需要的控件的父。所以我用foreach (Control c in this.<ParentName>.Controls)
代替foreach (Control c in this.Controls)