【问题标题】:Custom Control Inherited event not firing Up自定义控件继承事件未触发
【发布时间】:2013-06-28 13:02:28
【问题描述】:

我有一个继承自Control 并由我自己使用图形对象绘制的用户控件。

public class Line : Control
{
    public Point start { get; set; }
    public Point end { get; set; }
    public Pen pen = new Pen(Color.Red);
}

这是主窗体

public partial class Form1 : Form
{
    public Line line = new Line() { start = new Point(50, 50), end = new Point(100, 100) };
    public Form1()
    {
        InitializeComponent();
        Controls.Add(line);
        line.MouseEnter += new EventHandler(line_MouseEnter);
    }

    void line_MouseEnter(object sender, EventArgs e)
    {
        MessageBox.Show("Hello World");
    }

    private void Form1_Paint(object sender, PaintEventArgs e)
    {
        using (Graphics g = this.CreateGraphics())
        {
            g.DrawLine(line.pen, line.start, line.end);
        }
    }
}

现在,只要鼠标滑过控件,消息框就会弹出,但它没有。我尝试过调试,似乎该事件永远不会被调用。这里有什么问题

【问题讨论】:

  • 该行在 Form1 上是否可见?
  • 您可能不想要 Form 的 Paint 事件,尝试覆盖 Line 控件中的 OnPaint 方法,并使用 e.Graphics 而不是 CreateGraphics。至于 MouseEnter 事件,尚不清楚您的控件在“哪里”。尝试设置控件的位置和大小属性。
  • @LarsTech 是的,那是我犯的错误,我花了 15 分钟挠头才最终弄明白。谢谢

标签: c# .net winforms gdi+


【解决方案1】:

事实上,您的控件是可见的,但有 Size of Empty。您看到的线不是在控件上绘制的线,而是在您的表单上绘制的,这就是您认为您的线可见的原因。您想创建具有任意方向的线。我认为这有点难,你必须根据你的线方向和水平线所形成的角度来计算你的线的Rectangle(其中一侧是你的线粗细)。如果您可以计算出Rectangle,则必须使用Region 属性来使您的线控件完全适合其Rectangle。像yourLine.Region = new Region(calculatedRectangle); 这样的东西。对于这种复杂性,许多 UI 库只支持Horizontal lineVertical line,因为我们可以轻松计算它们的Rectangle,并且它们比其他类型的行更频繁地使用。这是水平线的代码,我没有时间根据您的需要深入编写全功能线,但您可能想自己尝试:

public class Line : Control
{    
  Color lineColor = Color.Red;
  public Color LineColor {
      get { return lineColor;}
      set {
          lineColor = value;
          BackColor = value;
      }
  }
  public Line(){
     Height = 1;//Default thickness
     Width = 100;//Default length
     BackColor = lineColor;
  }
  //for the case you want to draw yourself, add code in this method
  protected override void OnPaint(PaintEventArgs e){
       base.OnPaint(e);
       //your code
  }
}
//use it
Line line = new Line(){Left = 50, Top = 50};
line.MouseEnter += new EventHandler(line_MouseEnter);

如果你想在你的表格上画线,我认为你的线实际上是一个存储线信息(粗细、长度、起点、终点)的结构。所以你不需要它来继承Control,并且要注册MouseEnter,你必须为你的表单添加MouseMove事件处理程序,而不是你的行。但是,您的线路 Rectangle 会有所帮助。同样,您仍然需要计算您的行Rectangle,这正如我之前所说的那样并不容易。为了演示它,我只是用一种简单的方式计算你的行的Rectangle(将起点和终点的X都增加1):

//Your control has Size of Empty in this example, it just stores information of your line and is used to register the MouseMove event handler with the Form when its Parent is changed (to Form).
public class Line : Control
{
  public Point start { get; set; }
  public Point end { get; set; }
  public Pen pen = new Pen(Color.Red);
  protected override void OnParentChanged(EventArgs e){
    if(Parent != null){
        Parent.MouseMove -= MouseMoveParent;
        Parent.MouseMove += MouseMoveParent;
    }
  }
  private void MouseMoveParent(object sender, MouseEventArgs e){
     //the line Rectangle is specified by 4 points
     //I said that this is just for demonstrative purpose because to calculate
     //the exact 4 points (of the line Rectangle), you have to add much more code.
     Point p1 = start;
     Point p2 = new Point(p1.X + 1, p1.Y);
     Point p3 = new Point(end.X + 1, end.Y);
     Point p4 = end;
     System.Drawing.Drawing2D.GraphicsPath gp = new System.Drawing.Drawing2D.GraphicsPath();
     gp.AddPolygon(new Point[]{p1,p2,p3,p4});
     Region lineRegion = new Region(gp);
     if(lineRegion.IsVisible(e.Location)){
         MessageBox.Show("Hello World");
     }
  }
}
public partial class Form1 : Form
{
  public Line line = new Line() { start = new Point(50, 50), end = new Point(100, 100) };
  public Form1()
  {
    InitializeComponent();
    Controls.Add(line);
  }     
  private void Form1_Paint(object sender, PaintEventArgs e)
  {        
    e.Graphics.DrawLine(line.pen, line.start, line.end);        
  }
}

【讨论】:

  • 我覆盖了 Line 中的 OnPaint 方法,并使用我的 Line 类中的起点和终点使用 PaintEventArgs 创建了一条线。 MyEvent Handler 没有启动,因为我是从控件而不是 Panel 或 UserControl 继承的。反正我的问题已经解决了。感谢您在答案中付出的巨大努力,这对我来说是有用的,因为它可以作为我的 Line 中进一步功能的起点。
  • 不,您的控件大小尚未初始化,这就是您的鼠标从未进入其区域的原因。我已经测试了初始化它的大小,例如 (100,50) 并且 MouseEnter 被触发。我有足够的经验来确定它。 PanelControl 在这种情况下不是问题。从PanelUserControl 继承有效,因为PanelUserControl 的默认大小不是空的。如果您不相信,请尝试在您的 Line 构造函数中添加这一行:Size = new Size(100,50); 并尝试将鼠标移到表单的左上角。
  • 好吧,我从来没有说过你错了。事实上,你是绝对正确的,因为每当我进入一个矩形区域时,我的代码中的事件就会触发,而不是仅仅在对角线上触发,这表明存在默认面板大小。事实上,现在我正在尝试想出一些方法来使事件仅在鼠标移过线条而不是整个面板时触发。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-10-05
  • 2019-09-09
  • 1970-01-01
  • 2012-12-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多