ASP.NET控件开发学习笔记--第4回 为控件添加属性
第4回 为控件添加属性
上一回中我们制作了一个稍微复杂一些的控件,但这个控件存在着很多毛病,第一是导航条的标题栏名称被写死为“我的导航控件”,如果想把它改为其他的名称如“我的链接”就无能为力了。另外它完全依赖于xml文件“linksList.xml”,如果给xml文件改个名字就玩完了。有什么办法可以解决呢?当然是添加属性了,属性大家都很熟了,Visual Studio里专门有一个属性窗口来对属性进行设置。好,说做就做,首先打开控件源文件“linksList.cs”并在其中修改代码如下:
例4-1代码1:linksList.cs代码
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代码
<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.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 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了。
好,喝茶时间到,还有什么问题下一回再解决。