2010-11-23 107 views
8

我正在处理一些自定义的Control类,并且需要对它们进行初始化,而这些初始化依赖于它们被添加到表单中。发生这种情况时会发生事件吗?当Winforms控件被添加到表单时,Winforms控件是否引发事件

我觉得这个样本就足够了,以显示我想要做的事:

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被直接添加到表单,在这种情况下Bolu的解决方案完美地工作。其他人被添加到面板,而不是直接添加到表单。我想我已经拼凑了一个包含Bolu解决方案的前一种解决方案,并对其进行了一些修改,以处理事件由正在添加的面板而不是其中的MyControl引发的情况,而Mikes则负责处理MyControl s在构造函数完成运行后被添加到面板中。我必须在明天早上进行更多测试,然后才能确信它已经奏效。通过波鲁请求时,我尝试用他的建议在设计

错误消息:

Failed to create component 'MyControl'. The error message follows: 
'System.MissingMethodException: Constructor on type 'MyNamespace.MyControl' not found. 
    at System.RuntimeType.CreateInstanceImpl(BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes) 
    at System.Activator.CreateInstance(Type type, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes) 
    at System.ComponentModel.Design.DesignSurface.CreateInstance(Type type) 
    at Microsoft.VisualStudio.Design.VSDesignSurface.CreateInstance(Type type) 
    at System.ComponentModel.Design.DesignerHost.System.ComponentModel.Design.IDesignerHost.CreateComponent(Type componentType, String name) 
    at System.ComponentModel.Design.DesignerHost.System.ComponentModel.Design.IDesignerHost.CreateComponent(Type componentType) 
    at System.Drawing.Design.ToolboxItem.CreateComponentsCore(IDesignerHost host) 
    at System.Drawing.Design.ToolboxItem.CreateComponentsCore(IDesignerHost host, IDictionary defaultValues) 
...' 

和到位的构造函数时,我得到了错误。

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 
} 
+0

编辑我的回答 – Bolu 2010-11-24 09:54:10

回答

9

尝试ParentChanged事件。

+1

,因为它的设计增加了面板控件添加面板之前,形成了自己对这一事件是不适合的。这导致ParentChanged在可能遵循Parent属性到表单对象之前触发。 – 2010-11-23 19:52:39

+1

当父对象被设置时,你可以走上当前的父链并沿途绑定每个父对象的`ParentChanged`事件。这样,你会知道父母何时更改任何祖先。当父母改变时,解除所有'ParentChanged`处理程序(为此,必须在上一步中将所有挂钩的控件存储在列表中),然后再次执行祖先步行。 – 2010-11-23 21:57:33

+1

我能够得到这个工作。由于我没有做任何会导致ParentChanged每次控制触发多于一次的事情,所以如果它不是我正在查找的Form对象,那么只需将相同的代码挂接到Parent链中最顶端的控件即可。 – 2010-11-24 18:57:06

1
  1. MyControl

    MyForm pForm;

  2. 添加新MyForm对象传递一个MyForm参照MyControl时创建它:

    MyControl newControl = new MyControl(this);

  3. 然后注册您的MyForm对象的ControlAdded事件

    pForm.ControlAdded+=new ControlEventHandler(pForm_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你想添加到平底锅EL,只是通过面板的参考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); 
     } 

    }