C# Winforms控件添加到窗体时是否引发事件

C# Winforms控件添加到窗体时是否引发事件,c#,winforms,events,custom-controls,C#,Winforms,Events,Custom Controls,我正在处理一些自定义的控件类,需要对它们进行一些初始化,这取决于它们是否被添加到表单中。发生这种情况时是否有触发的事件 我认为这个示例应该足以说明我正在尝试做什么: public interface IMyForm { ISomeObject SomeObject {get; set; } } class MyForm : IMyForm { //eg InitializeComponent() as well as several others called at later

我正在处理一些自定义的
控件
类,需要对它们进行一些初始化,这取决于它们是否被添加到表单中。发生这种情况时是否有触发的事件

我认为这个示例应该足以说明我正在尝试做什么:

public interface IMyForm
{
    ISomeObject SomeObject {get; set; }
}

class MyForm : IMyForm
{
    //eg InitializeComponent() as well as several others called at later points
    private MethodThatAddsAControl()  
    {
        MyControl newControl = new MyControl();
        //other initialization as needed

        //does this raise an event in MyControl I can use to call
        //InitializationAfterBeingAddedToForm()?
        this.Controls.Add(newControl);   
    }
}


class MyControl : Control
{
    InitializationAfterBeingAddedToForm()
    {
        //can't be done in the constructor because at that point FindForm() will return null
        (FindForm() as IMyForm).SomeObject.AnEvent += new EventHandler(SomeObject_AnEvent);
    }
}
事实证明,这比我最初意识到的要困难得多,我想我必须结合博鲁和迈克·杜尔的建议。问题在于,当一些
MyControl
s直接添加到表单中时,Bolu的解决方案可以完美地工作。其他内容将添加到面板中,而不是直接添加到表单中。我想我已经拼凑了一个解决方案,涉及到Bolu针对前一个案例的解决方案,并进行了一些修改,以处理由添加的面板而不是其中的
MyControl
引发事件的情况,和Mikes来处理构造函数完成运行后将
MyControl
s添加到面板的情况。明天早上,我必须对它进行更多的测试,然后才能确信它能起作用

当我尝试在设计器中使用Bolu的建议时,Bolu请求的错误消息:

未能创建组件“MyControl”。错误消息如下:
'System.MissingMethodException:找不到类型'MyNamespace.MyControl'的构造函数。
位于System.RuntimeType.CreateInstanceImpl(BindingFlags bindingAttr、Binder Binder、Object[]args、CultureInfo区域性、Object[]ActivationAttribute)
在System.Activator.CreateInstance(类型类型、BindingFlags bindingAttr、Binder Binder、对象[]参数、CultureInfo区域性、对象[]ActivationAttribute)
位于System.ComponentModel.Design.DesignSurface.CreateInstance(类型)
位于Microsoft.VisualStudio.Design.VSDesignSurface.CreateInstance(类型)
位于System.ComponentModel.Design.DesignerHost.System.ComponentModel.Design.IDesignerHost.CreateComponent(类型componentType,字符串名称)
位于System.ComponentModel.Design.DesignerHost.System.ComponentModel.Design.IDesignerHost.CreateComponent(类型componentType)
位于System.Drawing.Design.ToolboxItem.CreateComponentsCore(IDesignerHost主机)
位于System.Drawing.Design.ToolboxItem.CreateComponentsCore(IDesignerHost主机,IDictionary默认值)
...'
当我发现错误时,构造器就就位了

public MyControl(Form parent)
{
    _parent = parent as IMyForm;
    parent.ControlAdded += new ControlEventHandler(parent_ControlAdded);
    Initialize();  //does rest of initialization
}

public TimelineControl(Form parent, Panel container)
{
    _parent = parent as IMyForm;
    container.ControlAdded += new ControlEventHandler(parent_ControlAdded);
    Initialize();  //does rest of initialization
}

尝试
ParentChanged
事件。

为什么不在MyControl中实现自定义事件

本文介绍了该方法:

  • MyControl

    myformpform

  • 创建时将
    MyForm
    引用传递给
    MyControl

    MyControl newControl=新的MyControl(此)

  • 然后注册
    ControlAdded
    对象的
    MyForm
    事件

    pForm.ControlAdded+=新的ControlEventHandler(pForm\u ControlAdded)

  • 根据您的代码,它应该类似于:

    class MyForm : IMyForm
    {
        private MethodThatAddsAControl()  //includes includes InitializeComponent as well as several others called at later
        {
            MyControl newControl = new MyControl(this);
            //other initialization as needed
            this.Controls.Add(newControl);   //this will raise MyControl ::pForm_ControlAdded
        }
    }
    
    
    class MyControl : Control
    {
        Myform pForm;
        public MyControl(MyForm ff)
        {
          InitializeComponent();
          pForm=ff;
          pForm.ControlAdded+=new ControlEventHandler(pForm_ControlAdded);
        }
    
    }
    
    编辑: 对于要添加到面板的MyControl,只需将面板的引用传递给MyControl:

    class MyForm : IMyForm
            {
                private MethodThatAddsAControl()  //includes includes InitializeComponent as well as several others called at later
                {
                 //create a MyControl object and add it to MyForm
                   MyControl newControl = new MyControl(this);
                 //other initialization as needed
                  this.Controls.Add(newControl);   //this will raise MyControl::pForm_ControlAdded
    
                    //create a MyControl object and add it to MyPanel1
                    MyControl newControl = new MyControl(MyPanel1); //pass panel reference            
                    MyPanel1.Controls.Add(newControl);   //this will raise MyControl::pPanel_ControlAdded
                }
            }
    
    
        class MyControl : Control
        {
    
            //// for control added to Form
             Myform pForm;
             public MyControl(MyForm ff)
             {
               InitializeComponent();
               pForm=ff;
               pForm.ControlAdded+=new ControlEventHandler(pForm_ControlAdded);
             }
    
       ///now for control added to panel
            MyPanel pPanel;
            public MyControl(MyPanel pp)
            {
              InitializeComponent();
              pPanel=pp;
              pPanel.ControlAdded+=new ControlEventHandler(pPanel_ControlAdded);
            }
    
        }
    

    如果我这样做了,设计师是否足够聪明,可以自动将其传递给构造函数?我认为您的编辑不会起作用。我需要IMyForm,因为VS设计器在调用pPanel_ControlAdded时将面板添加到窗体之前会将控件添加到面板中,所以我没有办法获取窗体。实际上,如果我修改它以传递面板和将添加到的窗体,则会。设计师正在轰炸,错误似乎是它需要一个无参数构造函数,除非我遗漏了什么,否则会扼杀你的想法。那么你的MyControl构造函数是什么?您是否按照我上面的建议重写它以获取Mypanel和Myform引用?我无法重现错误。不管怎样,很高兴你从Mike那里得到了答案。此事件不适合,因为它需要设计师在添加面板之前将控件添加到面板中,然后再添加面板以形成其外观。这会导致ParentChanged在可以跟随父属性到表单对象之前触发。当父对象被设置时,您可以沿着当前父链,并沿途钩住每个父对象的
    ParentChanged
    事件。这样,您就可以知道任何祖先的父代何时发生更改。当父对象发生更改时,将所有您的
    ParentChanged
    处理程序(要执行此操作,您必须在上一步的列表中存储所有钩住的控件),然后再次执行祖先漫游。我能够让它工作。因为我没有做任何会导致ParentChanged对每个控件触发多次的操作,所以如果不是我要查找的表单对象,我只会将相同的代码挂接到父链中最顶端的控件上。这很有意义。很高兴我能帮忙。因为已经有这样的活动了,请看公认的答案。哦,好吧,这是3年前的事了!