.NET Compact Framework1.0下自定义控件的编写3-小经验与小技巧

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

l         对库的调试在将“属性->配置属性->调试->调试模式”改为“程序”后,需点击“应用”按钮才可以配置“启动应用程序”等文本框。注意“命令行参数”中的路径是字符串,需要用引号括起。

l         将某个项目(比如库)设置为启动项目只要右击某项目,即可直接选中。

l         System.Diagnostics.Debug.WriteLine

l         ComponentModel命名空间提供了编写自定义控件时需要的整套特性,比如可以帮助修改组件在属性浏览器中Category(如“行为”、“外观”)的特性,控制属性在属性浏览器中可见/不可见的特性,等等等等。

l         DefaultProperty/DefaultEvent特性指定的默认属性/事件,如果将属性或事件拼写错误,则会使用基类的默认属性/事件。

l         如何屏蔽基类的属性和事件?

将基类属性重载后加上相应特性即可(如希望在属性浏览器中不可见则加上“Browable”特性,如希望在智能感知时不可见加“EditBrowable”特性)。

l         “宿主窗体集成”一节的意思是:对HostingForm属性,在设计期,设计器肯定会调用它的Getter,故可以利用这次机会,获得只能在设计期获得的宿主引用,保存后即可在运行期使用了。注意对于这种方法,调试时可能需要重新配置控件。

l         一旦窗体添加了一个实现了ISupportInitialize接口的组件,则窗体的InitializeComponent方法中将在首尾自动加入对该组件实现的ISupportInitialize接口中的BeginInitEndInit方法的调用。(很可惜CF不支持ISupportInitialize接口)

l         自定义属性,怎么会出现了只能看不能编辑的情况?

原因可能是在CanConvertFrom函数中将sourceType错判string外的其他类型。sourceType应该为string类型。

l         OnPaintAdornments只在设计期被调用。

l         Custom tool属性即选中某个文件后下方的属性浏览器中的“高级->自定义工具”。

l         如果自定义控件的某个属性是一个实现了ICollection接口的类型的实例,则使用该控件时,属性浏览器显示这个属性时自动就有Collection对话框。注意Collection类的item对应的类型一定要实现一个默认ctor.。且如果要使该属性支持窗体设计器的自动代码生成,则必须为该属性添加 DesignerSerializationVisibility(DesignerSerializationVisibility.Content) 特性。

另外,如果是一个数组,则也会自动显示一个类似的对话框。

l         EditorBrowable特性,用于控制智能感知时该属性是否可见。

Browable特性,用于控制属性在属性浏览器中是否可见。

RefreshProperties特性,用于控制当属性的值改变时属性浏览器的行为,例如当属性值改变时引起属性浏览器刷新等等。

Localizable特性,用于指定属性是否本地化,当为组件生成代码时,该标记为true的属性及其值将保存在资源文件中。(?什么意思,没用过,还不是很明白!

注意在完整版控件编写中EditorBrowable特性和Browable特性经常同时使用,用于屏蔽基类中不需要的属性,使它在属性浏览器和智能感知时都不可见。但在CF中编写控件中,要达到同样的效果,往往是将他们分开使用,即将Browable特性施加于控件的设计期版本中的属性,而EditorBrowable特性施加于控件的运行期版本中相应属性。

l         如何屏蔽掉基类中的属性或事件?

要屏蔽基类属性或事件,只要override该属性,然后为其加上相应特性(EditorBrowable特性、Browable特性)即可。

另外,有时可能是希望使用一个与基类属性同名,但却有完全不同行为的新属性,这时的不是使用override,而是使用new

l         若多个程序集中定义了相同的类C(类名相同、命名空间相同),而某个程序集A同时引用了这几个程序集并且要使用类C,则A使用哪个程序集中的类C以添加引用时这几个程序集的添加顺序为准,将使用先添加的那个程序集中的类C。(注意引用的多个程序集含有相同的类会引起编译器警告,如需要消除警告,“项目属性页->配置属性->生成->取消显示特定警告”,填入1595)。

l         Control.PointToClient:将点的屏幕坐标转化为客户区坐标

Control.PointToScreen:将点的客户区坐标转换为屏幕坐标

l         如何创建一个类似于GroupBox这样的容器控件:

使控件的设计器继承自ParentControlDesigner即可。

l         FillRectanglerect), rect=(0, 0, width,height)的效果:

即对于rect,只Fill图中的红色部分,不包括rect的右边和下边。例如,(0, 0, 1,10)rect,如果DrawRectangle,则是相等于一条粗为2的竖线,如果FillRectangle,则是一条粗为1的竖线。

l         精简版.NET下不支持ISupportInitialize接口,而有时对属性Setter的调用次序又必须人为控制,如何解决这个问题?

为控件添加一个initializing私有变量,指示当前过程是否正在初始化。在每个属性的Setter中,将那些与其他属性(成员变量)的取值相关的代码放在(!initializing)中,的确与其他属性(成员变量)取值无关的代码才直接放在Setter中。然后在适当的地方,比如OnPaint中,添加一段(initializing)代码,在其中完成所有存在取值依赖的属性(成员变量)的值的设置,在这段代码的末尾将initializing设为false,标志初始化完成。

l         如何提供一个与基类属性同名,却有完全不同行为(即不是通过重载)的属性?

做法如下(以BackColor为例):在设计期控件中,使用new关键字定义一个BackColor属性,然后重载ShouldSerializeBackColor方法,最后在控件的ctor中为BackColor设置一个默认值;在运行期控件中,在ctor中将BackColor设置为相同的默认值。

以上做法可行的原因:在设计期,父窗体的BackColor如果改变,窗体设计器会检查窗体上的所有子控件,如果控件的BackColor与之一致,说明它应该具有环境变量的行为,这时窗体设计器就会引起控件BackColorSetter被调用;如果子控件的BackColor与父窗体不一致,说明控件已经有了自己的BackColor,不应该再像环境变量一样处理它了,所以此时BackColorSetter不会再被调用了。但要注意的是一定要重载BackColorShouldSerialize函数,因为窗体设计器看到的始终是基类的BackColor,而由于控件new掉了基类的BackColor,故窗体设计器看到的基类的BackColor始终与父窗体一致,所以它就不会为改变了的BackColor生成代码,而这样的话,在运行期,将只能看到ctor中设置的BackColor的默认值。设计期和运行期行为不一致。

l         如何使圆角后的背景颜色与父窗体一致?

使用父窗体的背景颜色填充控件的客户区(FillRectangle(this.Parent.BackColor, ClientRectangle)),然后在利用控件自己的BackColor完成剩余的圆角内的填充。

l         CF下如何填充一个Pie

利用Graphics对象的Clip属性,而CF支持FillEllipse,可以使用这个函数但将Clip属性属性只设置为FillEllipseFillEllipse外接Rectangle的一部分,这样就只看到Ellipse的一部分,即一个Pie

l         如何混淆控件库?(即Dotfuscator的使用):

1.  运行Dotfuscator,“选择项目类型”选择“创建新项目”,“确定”

2.  选择“触发器”属性页,“浏览”到目标程序集。

3.  选择“重命名->排除”属性页,排除(即将其选中)所有类名、类中所有的ResetXxxShouldSerializeXxx函数、枚举的所有枚举值。

4.  选择“生成”属性页,指定目标目录,单击“生成”

l         如何对控件库加密(加壳)?

首先用VC6写一个Dll,提供加密(加壳)核心函数;然后在控件库工程之设计期库中通过DllImport特性,将这个Dll提供的加密(加壳)函数导入

[DllImport(@”D:/Shellxxx.dll”)

public static extern bool DateShell();

并将这些函数封装到一个专门提供加密(加壳)功能的类(不可继承,不可实例化的类)中供需要加密(加壳)的类调用。

这样的做法使破解者即使反编译了控件库的源代码,发现了加壳机制,但由于加壳功能的核心实现是在VC6写的Dll中,所以最后他还必须去破解这个Dll,而这个Dll由于是原生Win32程序,有许多现成的加密(加壳)工具可以使用。

l         如何制作库的安装文件?

首先创建一个.NET安装项目,然后右击“目标计算机上的文件系统->添加特殊文件夹”,选择相应的文件夹添加,在文件夹下加入需要安装的文件即可。

各文件夹的意义如下:

Program Files文件夹:即c:/ Program Files

System文件夹:即c:/ winnt/System32

Windows文件夹:即c:/ winnt

GAC文件夹:目标计算机的GAC文件夹

自定义文件夹:在“用户界面”视图中添加一个“文本框”,改动“文本框”的Edit1Property属性,取一个有意义的名字,将这个名字赋给“自定义文件夹”的Property属性。这样就可以将“自定义文件夹”中添加的文件拷贝到安装程序运行时客户在“文本框”中输入的路径下了。

注意“文本框”的Edit1Value属性是安装程序运行时“文本框”显示的初始路径,故最好将其设置为一个有意义的路径;另外不要改动“自定义文件夹”的DefaultLocation属性。

l         编程小技巧、小经验:

1.  如果要将控件的客户区等分为若干等份,但由于WidthHeight属性都是整型变量,存在无法整除的情况,这样就无法做得精确的等分了。如果必须保证等分的每一份相同,一个可行发方案如下:

Width = Width / Cols * Cols ;

Height = Height / Rows * Rows ;

  这样就可以保证WidthHeight一定是ColsRows的整倍数了。但注意一般不直接操作WidthHeight这样的属性,而是将它们的值保存到某个局部变量中,然后去操作这些局部变量。

2.  控件的SizeWidthHeight,注意此时如另它的坐上角坐标(00),则它的右下角坐标是(Width1Height1),而不是(WidthHeight

l         遗留的问题:

1.在CF中不知是否能提供UITypeEditor,如何提供?

2.是否能获得GDI+的效果,如何获得?