.NET Compact Framework1.0下自定义控件的编写2-论CF的设计期与运行期

来源:互联网 发布:阿里云iaas平台特点 编辑:程序博客网 时间:2024/05/22 05:05

通过重载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

         }

     }