第4回 为控件添加属性
上一回中我们制作了一个稍微复杂一些的控件,但这个控件存在着很多毛病,第一是导航条的标题栏名称被写死为“我的导航控件”,如果想把它改为其他的名称如“我的链接”就无能为力了。另外它完全依赖于xml文件“linksList.xml”,如果给xml文件改个名字就玩完了。有什么办法可以解决呢?当然是添加属性了,属性大家都很熟了,Visual Studio里专门有一个属性窗口来对属性进行设置。好,说做就做,首先打开控件源文件“linksList.cs”并在其中修改代码如下:
例4-1代码1:linksList.cs代码
using
System;
using
System.Web.UI;
using
System.Data;
using
System.Data.OleDb;
[assembly:TagPrefix(
"
MyControl
"
,
"
CG
"
)]
namespace
MyControl
{
public
class
LinksControl:Control
{
//
这里添加了两个用于属性的私有成员变量
private
string
_titleText
=
""
;
private
string
_xmlFileName
=
""
;
//
下面添加了两个属性
public
virtual
string
TitleText
{
get
{
return
_titleText; }
set
{ _titleText
=
value; }
}
public
virtual
string
XmlFileName
{
get
{
return
_xmlFileName; }
set
{ _xmlFileName
=
value; }
}
protected
override
void
Render(HtmlTextWriter writer)
{
writer.WriteLine(
"
<ul>
"
);
//
这里先判断标题名称是否为空然后考虑是否添加标题
if
(_titleText
!=
""
)
{
writer.WriteLine(
"
<li id='caption'>
"
+
_titleText
+
"
</li>
"
);
}
string
s;
//
判断xml文件是否存在
if
(_xmlFileName
!=
""
)
{
DataSet ds
=
new
DataSet();
ds.ReadXml(Page.Server.MapPath(_xmlFileName));
foreach
(DataRow row
in
ds.Tables[
"
link
"
].Rows)
{
s
=
"
<li><a href='
"
;
s
+=
row[
"
url
"
].ToString();
s
+=
"
'target='_blank'>
"
;
s
+=
row[
"
name
"
].ToString();
s
+=
"
</a></li>
"
;
writer.WriteLine(s);
}
}
writer.WriteLine(
"
</ul>
"
);
}
}
}
关于属性,如果有不明白的地方请参考:http://www.enet.com.cn/eschool/video/c/18.shtml 。这里需要注意的是,属性使用了virtual关键字,使这个属性变是虚拟属性,这样做可以使继承你的控件来写新控件的人可以重写这个属性。然后使用属性所指向的成员变量来代替代码中的硬编码部分:
writer.WriteLine("<li id='caption'>"+_titleText+"</li>");
和
ds.ReadXml(Page.Server.MapPath(_xmlFileName));
当然,新程序对两个属性值如果为空做了处理,但还没处理干净,比如xml文件的后缀名不对或文件不存在等等没有做进一步判断。为了简化代码,这些先暂不考虑。
下面更改aspx文件以使用新添加的属性,打开linkslist.aspx文件,更改代码如下:
例4-1代码2:linkslist.aspx代码
<%
@Register TagPrefix
=
"
CG
"
Namespace
=
"
MyControl
"
%>
<
html
>
<
head
>
<
title
>
Chapter 5: Background Images
</
title
>
<
link
rel
='Stylesheet'
media
="screen"
type
='text/css'
href
='linkslist.css'
/>
</
head
>
<
body
>
<
CG:LinksControl
TitleText
="我的链接"
XmlFileName
="linksList.xml"
runat
="server"
/>
</
body
>
</
html
>
这里我们在声明控件时加上了(TitleText="我的链接" XmlFileName="linksList.xml")来设置控件的属性。保存并在浏览器中运行linkslist.aspx文件,看看是否和以前效果一样。为了验证属性的作用,更改TitleText属性看看会有什么效果。再更改xml文件的名称,然后相应地更改XmlFileName属性,看看能否运行成功?
好,现在这个控件貌似已经很不错,但你想在Visual Studio的属性窗口里直接设置属性,现在把控件装到Visual Studio里会在属性窗口里显示这两个新添加的属性吗?当然不行,不过要实现它很简单,只需添加一些特性就行了。打开控件源文件linksList.cs,更改代码如下:
例4-2代码1:linksList.cs代码
using
System;
using
System.Web;
using
System.Web.UI;
using
System.Data;
using
System.Data.OleDb;
using
System.ComponentModel;
[assembly:TagPrefix(
"
MyControl
"
,
"
CG
"
)]
namespace
MyControl
{
[DefaultPropertyAttribute(
"
TitleText
"
)]
[ToolboxData(
"
<{0}:LinksControl
"
+
"
TitleText='我的链接'
"
+
"
XmlFileName='linksList.xml'
"
+
"
runat='server'></{0}:LinksControl>
"
)]
public
class
LinksControl:Control
{
//
这里添加了两个用于属性的私有成员变量
private
string
_titleText
=
"
我的链接
"
;
private
string
_xmlFileName
=
""
;
//
下面添加了两个属性
[BrowsableAttribute(
true
)]
[DescriptionAttribute(
"
设置标题栏的名称
"
)]
[DefaultValueAttribute(
"
我的链接
"
)]
[CategoryAttribute(
"
外观
"
)]
public
virtual
string
TitleText
{
get
{
return
_titleText; }
set
{ _titleText
=
value; }
}
[BrowsableAttribute(
true
)]
[DescriptionAttribute(
"
存放链接的xml文件名
"
)]
[DefaultValueAttribute(
""
)]
[CategoryAttribute(
"
数据
"
)]
public
virtual
string
XmlFileName
{
get
{
return
_xmlFileName; }
set
{ _xmlFileName
=
value; }
}
protected
override
void
Render(HtmlTextWriter writer)
{
writer.WriteLine(
"
<ul>
"
);
//
这里先判断标题名称是否为空然后考虑是否添加标题
if
(_titleText
!=
""
)
{
writer.WriteLine(
"
<li id='caption'>
"
+
_titleText
+
"
</li>
"
);
}
string
s;
//
判断xml文件是否存在
if
(_xmlFileName
!=
""
)
{
DataSet ds
=
new
DataSet();
ds.ReadXml(Page.Server.MapPath(_xmlFileName));
foreach
(DataRow row
in
ds.Tables[
"
link
"
].Rows)
{
s
=
"
<li><a href='
"
;
s
+=
row[
"
url
"
].ToString();
s
+=
"
'target='_blank'>
"
;
s
+=
row[
"
name
"
].ToString();
s
+=
"
</a></li>
"
;
writer.WriteLine(s);
}
}
writer.WriteLine(
"
</ul>
"
);
}
}
}
然后保存文件,并把文件剪切到虚拟目录下,然后新建一CompilelinksList.bat文件,用记事本打开,输入代码如下:
例4-2代码2:CompilelinksList.bat代码
set indir
=
H:\ASP\linksList.cs
set outdir
=
H:\ASP\bin\linksList.dll
csc
/
t:library
/
out:
%
outdir
%
%
indir
%
pause
记住,indir和outdir这两个路径根据你自己的实际情况进行更改。在虚拟目录下新建一bin文件夹,双击CompilelinksList.bat文件编译程序集。然后查看bin文件夹下是否生成linksList.dll文件,如果成功,接着下面步骤。
打开Visual Studio,新建一个ASP.NET Web应用程序,在工具箱内把以前我们加上去的控件删掉(在控件上点右键删除),再把我们新做的控件加上去。加完后把它拖到设计窗体,看到了什么?晕了吧,出错!如图4-1所示:
不要慌张,这只是设计期的错误,无关大局。怎么样在设计期访问xml及显示正确的东西我现在还没搞清楚,学到后面应该就知道了吧!哪位大侠知道的话麻烦告诉我一声,哈哈!好,继续工作。在【解决方案资源管理器】中右键选中项目,选中【添加】|【现有项】把linkslist.css和linksList.xml这两个文件加进来,然后拖动linkslist.css文件到设计窗体。好运行程序看看效果如何!是不是和前面的一样?好,下面就来讲解代码。
代码所更改的地方是增加了一些特性,所以需要引入如下命名空间:
using System.ComponentModel;
先来看第一个增加的特性:
[DefaultPropertyAttribute("TitleText")]
从名字就可以猜出它的作用,“默认属性”,也就是说,用它来指定在属性窗口中默认高亮显示的属性是哪个。再看下一个:
[ToolboxData("<{0}:LinksControl "+
"TitleText='我的链接' "+
"XmlFileName='linksList.xml' "+
"runat='server'></{0}:LinksControl>")]
这个也很好理解,如果刚才做的例子没有关的话,看看源代码,注意控件声明的地方:
<CG:LinksControl ID="LinksControl1" runat="server" TitleText="我的链接"
XmlFileName="linksList.xml">
</CG:LinksControl>
跟上面对比一下,很相似吧!只是{0}这个参数被CG所替代。这个特性的作用就是当拖动控件到设计窗体时,定制声明这个控件的代码。
[BrowsableAttribute(true)]
指定一个属性 (Property) 或事件是否应显示在“属性”窗口中。它在哪个属性前面使用就指的是这个属性。
[DescriptionAttribute("设置标题栏的名称")]
属性的描述,当一个属性处于选中状态时,属性窗口最下方会显示有关这个属性的描述,这个特性就是设置这个描述信息的。
[DefaultValueAttribute("")]
属性的默认值,也就是第一次拖动控件到设计窗体时,属性窗口中这个属性所显示的值是什么。
[CategoryAttribute("外观")]
当属性窗口分类显示时,里面有好几个栏,你希望把这个属性放到哪个栏里呢?想放哪就放哪,设置这个特性值就OK了。
好,喝茶时间到,还有什么问题下一回再解决。