页面显示了公司所在城市姓名性别和职务信息这些内容是定义服务器控件呈现的结果其中公司所在城市由简单属性City设置姓名性别和职务由复杂属性Employee设置其中包括子属性NameSex和Title设置下面列举了示例应用程序的Defaultaspx文件源代码
<%@ Page Language=C# AutoEventWireup=true CodeFile=Defaultaspxcs Inherits=_Default %>
<%@ Register Namespace=WebControlLibrary Assembly=WebControlLibrary TagPrefix=Cp %>
<!DOCTYPE html PUBLIC //WC//DTD XHTML Transitional//EN transitionaldtd>
<html xmlns=>
<head runat=server>
<title>实现连字符形式复杂属性</title>
</head>
<body>
<form id=form runat=server>
<div>
<Cp:Company ID=demo runat=server City=重庆 EmployeeName=小李 EmployeeSex=男 EmployeeTitle=销售经理 />
</div>
</form>
</body>
</html>
如上代码所示主要设置了@ Register指令和自定义服务器控件Company前者用于为页面引入自定义服务器控件Company从而实现控件在页面中的应用在自定义服务器控件Company中主要设置了CityEmployeeNameEmployeeSex和EmployeeTitle同时在开发人员编码过程中将会发现以上个属性均为Visual Studio 的智能感知功能所支持
另外读者还可以以另一种非连字符形式设置Company控件属性具体代码如下所示
<Cp:Company ID=Company runat=server City=重庆>
<Employee Name=小李 Sex=男 Title=销售经理>
</Employee>
</Cp:Company>
实际上以上设置Company控件属性的方法与前文利用连字符设置属性的方法是完全一致的对于所有连字符形式属性可以任意使用二者之一如果是基于代码可读性的角度而言后者比前者的可读性更强一些
using System;
using SystemCollectionsGeneric;
using SystemComponentModel;
using SystemText;
using SystemWeb;
using SystemWebUI;
using SystemWebUIWebControls;
namespace WebControlLibrary{
[DefaultProperty(Text)]
[ToolboxData(<{}:Company runat=server></{}:Company>)]
public class Company : WebControl {
private Employee employee; //实现属性City
[ Bindable(true) Category(Appearance) DefaultValue() Description(公司所在城市) ]
public string City {
get {
string _city = (String)ViewState[City];
return ((_city == null)?StringEmpty:_city);
}
set { ViewState[City] = value; }
} //实现属性Employee
[ Bindable(true) Category(Appearance) Description(员工信息) DesignerSerializationVisibility( DesignerSerializationVisibilityContent) NotifyParentProperty(true) ]
public Employee Employee {
get {
if (employee == null) {
employee = new Employee();
}
return employee;
}
} // 重写RenderContents方法自定义实现控件呈现
protected override void RenderContents(HtmlTextWriter output) {
outputWrite(公司所在城市);
outputWrite(City);
outputWriteBreak();
outputWrite(姓名);
outputWrite(EmployeeNameToString());
outputWriteBreak();
outputWrite(性别);
outputWrite(EmployeeSexToString());
outputWriteBreak();
outputWrite(职务);
outputWrite(EmployeeTitleToString());
}
}
}
实现方法
上一小节中的Defaultaspx页面所包含的Company控件具有个连字符形式复杂属性它们是如何实现的呢?实际上实现这种形式的复杂属性关键是在自定义服务器控件实现过程中对复杂属性及其子属性设置特定的设计时元数据
对于复杂属性而言主要在该属性实现前设置两个设计时元数据DesignerSerializationVisibility和 NotifyParentPropertyDesignerSerializationVisibility用于指定在设计时序列化组件上的属性时所使用的持久性类型NotifyParentProperty可使得属性浏览器中对子属性的修改通知一直上传到对象模型并在被修改了子属性的控件中产生修改通知对于子属性的设计时元数据设置比较简单只需在子属性实现前设置一个NotifyParentProperty即可
实现自定义服务器控件Company涉及两个文件Companycs和Employeecs前者是自定义服务器控件的实现主体其中包括各种属性设置控件呈现方法RenderContents等等后者用于实现复杂属性Employee下面首先列举了Companycs文件源代码
以上代码显示了自定义服务器控件Company的实现其中主要包括了一些属性和RenderContents方法的内容具体属性包括个一个是简单属性City另一个是复杂属性Employee简单属性City的实现使用了视图状态ViewState复杂属性Employee则有些特别其类型是一个类Employee同时该属性还设置了两个元数据属性DesignerSerializationVisibility (DesignerSerializationVisibilityContent)和NotifyParentProperty(true)前者可用于指定序列化程序应该序列化属性的内容即子属性后者则可使得属性浏览器中对子属性的修改通知一直上传到对象模型并在被修改了子属性的控件中产生修改通知以上两个设计时元数据属性的设置是实现连字符形式复杂属性的关键之一另一个关键之处在于为在实现复杂属性的子属性时未其设置元数据属性
下面列举了具体实现复杂属性Employee的Employeecs文件源代码
using System;
using SystemCollections;
using SystemComponentModel;
using SystemGlobalization;
using SystemWebUI;
namespace WebControlLibrary{
public class Employee {
private string _name;
private string _sex;
private string _title; //实现构造函数
public Employee() { } //实现构造函数
public Employee(String Name String Sex String Title) {
_name = Name; _sex = Sex; _title = Title;
} //实现属性Name
[ Bindable(true) Category(Appearance) DefaultValue() Description(员工姓名) NotifyParentProperty(true) ]
public String Name {
get { return _name; }
set { _name = value; }
} //实现属性Sex
[ Bindable(true) Category(Appearance) DefaultValue() Description(员工性别) NotifyParentProperty(true) ]
public String Sex {
get { return _sex; }
set { _sex = value; }
} //实现属性Title
[ Bindable(true) Category(Appearance) DefaultValue() Description(员工职务) NotifyParentProperty(true) ]
public String Title {
get { return _title; }
set { _title = value; }
}
}
}
以上代码实现了Employee类其中包括构造函数和属性NameSex和Title读者需要注意为了实现连字符形式复杂属性以上个属性都必须设置元数据属性NotifyParentProperty(true)这样当子属性发生修改时NET框架将自动产生修改通知并且通知到父属性 Employee
小结
本文通过一个典型示例介绍了创建连字符形式复杂属性的实现方法对于其他形式的复杂属性例如内部嵌套形式复杂属性内部嵌套形式默认复杂属性等本文将不再做更多解释实际上实现复杂属性是有其自身规律可循的只要读者能够按照规定的方法实现基本上都不会出现太大的问题