转自:http://www.cnblogs.com/ticc/archive/2009/12/15/1624217.html
控件的设计时(design-time)支持是开发自定义控件的一个重要内容,也是开发的难点。那么什么是控件的设计时支持呢?
控件的设计时是指控件运行在开发环境的可视化设计器中的这一段时间,在这段时间内开发者使用它们在VS2005开发环境中设计用户界面以及设定控件的属性。与之相对的是控件的运行时,运行时是指应用程序编译生成后,控件随应用程序启动并运行的这一阶段。控件最终的是随应用程序发布并运行在程序的目标环境中的,为什么会有设计时这一概念呢?一般来说,开发者可能仅仅注意到控件必然有运行时的概念,因此也仅仅实现了控件在运行时的外观和功能逻辑。然而,控件还有一个重要的功能,那就是开发者需要使用它们来进行用户界面的可视化设计。在这一过程中,控件事实上也是一个运行在开发环境中的对象,这个对象由开发环境构造并销毁,开发者通过开发环境的可视化设计器来改变控件的属性。显然,控件对象在运行时的外观和逻辑是不可能和在开发环境中进行可视化设计时是完全一样的,一个最明显的例子就是,开发者在PC机器上的VS2005开发环境下开发WinCE应用程序,但该应用程序最终是部署在WinCE设备上运行的,因此用于开发WinCE设备应用程序的控件的设计时和运行时必然是有区别的。
了解了控件的设计时,那么控件的设计时支持即是指控件在处于设计时的时候应该表现出来的形态和功能逻辑,以及向开发环境的可视化设计器提供有价值的信息的功能。从上述定义可以看出,设计时支持包含两个方面的内容:一是可视化设计器需要的控件中的属性(Attributes),一是控件在运行时和设计时的不同形态和功能逻辑。下面一一介绍它们。
1. 控件中的属性(Attributes)
先来看个例子。下图所示是WinCETools中BarcodeTextBox控件的属性面板。
如图中所示的控件属性(Property)的分类和描述信息等对控件的运行时没有任何价值,但却给开发者使用控件带来了很大的帮助。如何让自己的控件提供这些信息呢?.NET提供的C#属性(Attributes)就是解决这个问题的办法。
在前面如何:开发简单的 Windows 窗体控件的例子中你可能注意到了下面一段代码:
[
Category("Alignment"),
Description("Specifies the alignment of text.")
]
publicContentAlignment TextAlignment
{
get
{
return alignmentValue;
}
set
{
alignmentValue =value;
// The Invalidate method invokes the OnPaint method described
// in step 3.
Invalidate();
}
}
这段代码中Category("Alignment")正是说明控件的TextAlignment属性属于Alignment类别,而Description("Specifies the alignment of text.")说明TextAlignment属性的描述信息为Specifies the alignment of text.。
.NET为控件的设计时提供了很多属性(Attributes),MSDNWindows 窗体控件中的属性列出了大部分常用的属性,其中下列属性(Attributes)及其用法应该最先掌握。
Ø BrowsableAttribute
Ø CategoryAttribute
Ø DefaultValueAttribute
Ø DescriptionAttribute
Ø DefaultEventAttribute
Ø DefaultPropertyAttribute
Ø ToolboxBitmapAttribute
在了解上述属性(Attributes)的过程中你可能会发现,这些属性都是.NET Framework完整版支持的类,而在.NET Compact Framework中不支持。那么如何为.NET Compact Framework的控件提供设计时属性呢?VS2005为开发者提供了另外一种解决办法,使用“设计时属性文件”。如下图:
设计时属性文件是一个XML格式的文件,它为设备程序集提供设计时信息。先来看看下面的设计时属性文件。
<?xmlversion="1.0"encoding="utf-16"?>
<Classesxmlns="http://schemas.microsoft.com/VisualStudio/2004/03/SmartDevices/XMTA.xsd">
<ClassName="WinCETools.Scan.BarcodeTextBox">
<DesktopCompatible>true</DesktopCompatible>
<DefaultEvent>DataArrived</DefaultEvent>
<PropertyName="IsDefault">
<Category>WinCETools</Category>
<DefaultValue>
<Type>System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</Type>
<Value>False</Value>
</DefaultValue>
<Description>获取和设置控件是否作为窗体中的默认扫描接收控件</Description>
<Browsable>false</Browsable>
</Property>
<EventName="DataArrived">
<Category>WinCETools</Category>
<Description>当条码扫描完成时触发的事件。</Description>
</Event>
</Class>
</Classes>
设计时属性文件中Classes节点是XML文件的根节点,其中每个Class节点都用于描述一个控件的设计时属性。比如上面的文件就是对WinCETools.Scan.BarcodeTextBox这个控件的设计时属性描述。仔细对比文件中的节点名称和之前列出的设计时属性(Attributes)类,我们很容易发现它们之间的对应关系。事实上,它们本身就是实现控件设计时属性的不同方式而已。
在编译WinCE智能设备项目的时候,VS2005首先生成项目的运行时程序集,当VS2005发现项目为该程序集提供了设计时属性文件时,VS2005为程序集中的每一个类在设计时文件中查找对应的设计时属性,然后重新为它们编译生成一个带有设计时属性的可在开发环境中运行的设计时程序集。例如为WinCETools.Client.dll生成文件名为WinCETools.Client.PocketPC.asmmeta.dll或者WinCETools.Client.WindowsCE.asmmeta.dll的程序集,文件名中WinCETools.Client是原程序集的名称,asmmeta是设计时程序集固有的后缀,而PocketPC和WindowsCE则分别对应项目的目标平台。你应该为你的控件准备各种智能设备目标平台的设计时程序集。
2. 控件的设计时逻辑
一般来说,控件在设计时改变属性值等过程中需要实现的逻辑仅仅是通知可视化设计器更新与该控件相关的代码需要改动,而并不需要完全按照控件运行时应该处理的改变属性的逻辑在开发环境中执行这些逻辑。有些更为特殊的逻辑甚至在开发环境中根本无法执行,比如WinCETools中的BarcodeTextBox控件的IsDefault属性,设置IsDefault属性为true时控件在运行时的逻辑应该是打开扫描头,这个逻辑显然在设计时执行会遇到困难。
鉴于上面提到的问题,控件的运行逻辑也可能分为设计时和运行时,我们在开发控件的时候也应该加以区别。那么如何让控件在设计时执行设计时的逻辑,而又不影响控件在运行时的功能呢?常用的办法是在实现控件时判断控件当前的运行环境,然后使控件执行相应的逻辑。有两种常见方法可以区别控件当前的运行形态:
Ø Control.Site属性的DesignMode
控件都有一个Site属性,Site属性是一个ISite接口的对象,该接口的DesignMode表明控件当前的运行形态,为true则表示控件处于设计时,否则处于运行时。
if (this.Site !=null&&this.Site.DesignMode)
{
// 设计时逻辑
}
else
{
// 运行时逻辑
}
Control.Site属性不被.NET Compact Framework 1.0支持,因此通过Control.Site的DesignMode来判断控件的设计时只能在开发非CF1.0的控件时可以采用。
Ø 判断System.Environment.OSVersion.Platform
在开发WinCE设备控件的时候,通过判断控件当前运行环境的操作系统平台来判断控件的设计时是一个简单且有效的办法。如下代码:
if (System.Environment.OSVersion.Platform ==PlatformID.WinCE)
{
// 运行时逻辑
}
else
{
// 设计时逻辑
}