通过重载ISite属性可以获得设计期服务:GetService
在设计期,一个控件的完整生命过程分为两种情况,一是当用户从工具栏中拖出一个控件时,一是当解决方案在关闭后被重新打开时,两种情况下的生命过程分别为:
1) 当用户从工具栏中拖出一个控件时,首先该控件的ctor.被调用——ctor.中包含对控件的所有成员变量的初始化代码,这些初始化代码将该控件的成员变量设置默认值;然后控件的OnPaint函数被调用,完成控件的绘制。
2)当设计期窗体在关闭后被重新打开时,窗体上的所有控件都会被重新构造,这个过程是:
2.1)首先该控件的ctor.被调用,ctor.中包含对控件的所有成员变量的初始化代码,这些初始化代码将该控件的成员变量设置默认值;
2.2)然后窗体设计器读取该控件对应的资源文件(资源文件保存了窗体上一次关闭前各个属性的值),以重新将控件的各个属性设置为上一次解决方案关闭时的值,即,如果某个属性在资源文件中有值(当属性被设置为与DefaultValue特性中指定的值不同的值时,其值就会记录在资源文件中),则窗体设计器就用这个值去调用该控件相应属性的Setter,之后接着调用Getter将这个属性的属性值显示在属性浏览器中,如果属性在资源文件中没有相应值,说明它仍保持默认值,那么窗体设计器将直接调用它的Getter以在属性浏览器中显示这个默认值;以上调用过程以属性的字母表顺序为序;
2.3)最后控件的OnPaint被调用,控件在窗体中显示。
另外,在设计期,当控件所在窗体被关闭时(这个关闭不是指点击窗体的关闭按钮,而只是关闭窗体文件),窗体上各个控件的Dispose函数会被调用,注意在Dispose中回收控件用到的资源,否则可能会有一些不可预期的行为(在运行期可能没有相应行为)。
在运行期,控件的生命过程嵌套在其父窗体的生命过程中,具体为:
1)首先,控件父窗体的InitializeComponent函数被调用。在这个函数中,首先会对窗体上所有的控件执行new操作,之后设置控件各属性(仅针对属性值不为DefaultValue的属性),最后还要将控件添加到窗体的Controls集合中。故控件的生命过程为:当被new时,控件的ctor.被调用,ctor.中包含对控件的所有成员变量的初始化代码,这些初始化代码将该控件的成员变量设置默认值;当调用属性Setter时,将相应属性设置为与设计期一致的值,由于InitializeComponent中的属性设置代码是以属性的字母序排列的,故控件各属性的Setter调用次序依字母序。
2)控件父窗体的InitializeComponent执行完后,它开始绘制自己,在这个过程中,其上所有控件的OnPaint函数将会被调用。
综上,一个控件在运行期的生命过程是:首先,它的ctor.被调用,这个ctor.中包含对控件的所有成员变量的初始化代码,将该控件的成员变量设置默认值;然后,控件各个属性的Setter被依字母序调用,将相应属性设置为与设计期一致的值;最后,控件的OnPaint被调用,控件得以绘制。
由于控件各属性的Setter安装字母顺序调用,这就带来一个问题:如果属性值之间存在相互依赖关系,字母序在前的属性值依赖于字母序在后的属性值,那么就可能造成控件在设计期和运行期的行为不一致:即,在设计期,字母序在后的属性已经有有意义的值,那么依赖于字母序在前的属性就可以被正确的设置;但到了运行期,字母序在前的属性的Setter先被调用,而此时其依赖的字母序在后属性还没有被设置,从而引发不可预期的行为。
解决方案代码框架如下:
public class XXX : System.Windows.Forms.Control
{
private bool initializing = false ;
private int derivedProperty1 ;// derived properties
public XXX()
{
//
// TODO: 在此处添加构造函数逻辑
//
}
private int property1 ;
public int Property1
{
get {return property1;}
set
{
property1 = value ;
if (!initializing)
{
// do property1's own job
Property1Updated() ;
}
}
}
protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
{
if (initializing)
{
initializing = false ;
CalculateDerivedProperties() ;
}
// do some painting job
base.OnPaint (e);
}
private void Property1Updated()
{
// update properties that refer to property1
// update derived properties that refer to property1
}
private void CalculateDerivedProperties()
{
// calculate derived properties like derivedProperty1
// normal properties like Property1 are not allowed to calculated here
}
}
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/yejun8214/archive/2008/03/24/2214761.aspx