最近一直在做MVC项目,对于WEBFORM 好像快忘记了。周末无聊,顺带看看他人的笔记。再次温习下。
复习大纲:
Asp.net控件开发学习笔记整理篇 - 控件开发基础
服务器控件开发基础
当开发一个服务器控件时,首先要明白其内部的工作机理。其实在页面内部每一点由asp.net返回的HTML代码无论是简单的<span>标签,或者是button按钮,或者是复杂的gridview控件,都是由继承自System.Web.UI.Control的对象生成的。
控件的属性
控制控件的方法大多是通过控件的属性来操作的,通过控制服务器控件的属性,就可以相应的改变服务器生成的html.
下面是一个服务器控件的属性:
在Visual Studio里,当通过属性窗口来改变控件的属性时,VS会自动将属性添加到对应的aspx的HTML里,而在html内添加属性时,在属性窗口里也会对应显示更改过的属性视图比如:
<asp:Button ID="Button1" runat="server" Text="Button" CommandName="cName" />
在属性窗口里会对应显示,如下图:
当然某些控件的属性会略有不同,比如常用的Label控件:
<asp:Label ID="Label1" runat="server">这里是Text属性</asp:Label>
在开始符号和结束符号之间的内容会被设置成Text属性.
当然,最实用也是我们最常用的是通过C#以编程的方式动态的修改控件的属性.这就不说了.
控件的方法
控件通过方法来操作更加复杂的控件操作,通常在控件的方法内部会有很复杂的过程,一般包括几个内部函数和属性的组合.比如:
private void LoadDropDownList()
{
ArrayList list = new ArrayList();
list.Add("Hello");
list.Add("Goodbye");
GridView1.DataSource = list;
GridView1.Databind();
}
这样,通过调用Databind()方法,就可以讲gridview和数据源进行绑定.
控件的事件
控件通过事件来通知其它类或者客户端其内部的某个状态被改变。事件是一种灵活的机制,当控件与客户端进行交互的时候,事件会通过Http Post方法和服务器进行交互,通过自动回传机制,WEB开发中的事件表现起来就会像开发Windows FORM程序一样(当然,速度是无法和Form相比的)
在Visual Studio中,可以在属性窗口中通过黄色的闪电图标来显示和控制控件的事件,如下:
当双击相应的事件后,会在后台产生默认的处理方法,命名规则为”控件名_事件名”
WEB Page本质是一个控件树
在aspx页面的头部将Trace="true"设置到Page后,页面会显示相应的追踪信息,在Control Tree那一节,你会发现整个页面其实就是一个控件树,如图:
根控件?
OK,既然asp.net页面的本质是一个控件树,按照C#是完全面向对象的语言惯例(所有的一切都是继承于System.Object),那么所有控件共同的父类是什么?
在asp.net中,所有的控件被分布在3个主要命名空间中,分别为:
System.Web.UI
System.Web.UI.WebControls
System.Web.UI.HtmlControls
它们之间的关系如下图所示
System.Web.UI命名空间
由上图可知,System.Web.UI处于继承树顶端的,而System.Web.UI.Control是所有控件的基础,所有的控件必须强制直接或者间接的继承Control类,而直接继承Control类的是Page类,以及UserControl类。
System.Web.UI.HtmlControls命名空间
在System.Web.UI.HtmlControls命名空间中的对象,通过在html标签中加入runat=”server”属性,能够将HTML中的标签转化为服务器控件。Asp.net的引擎会将的页面中的HTML标签和System.Web.UI.HtmlControls内的对象进行匹配。System.Web.UI.HtmlControls命名空间如图:
通过查看System.Web.UI.HtmlControls命名空间,我们可以发现,很多HTML对应的标签都可以通过添加runat=”server”属性转化为服务器控件,比如<table>会转化为HtmlTable对象,但像<input >标签可以通过type属性对应不同的服务器对象。当html内的标签没有和上图中的服务器控件匹配时,所有不匹配的html标签都会通过添加runat=”server”转化为HtmlGenericControl服务器控件。下面是对应的服务器控件类与HTML标签之间的对应关系:
HTML Tag |
HTML Server Control |
<form> |
HtmlForm |
<input type="text"> |
HtmlInputText |
<input type="password"> |
HtmlInputText |
<input type="radio"> |
HtmlInputRadioButton |
<input type="checkbox"> |
HtmlInputCheckBox |
<input type="submit"> |
HtmlInputButton |
<input type="hidden"> |
HtmlInputHidden |
<input type="button"> |
HtmlInputButton |
<input type="image"> |
HtmlInputImage |
<input type="file"> |
HtmlInputFile |
<button> |
HtmlButton |
<select> |
HtmlSelect |
<textarea> |
HtmlTextArea |
<img> |
HtmlImage |
<a> |
HtmlAnchor |
<table> |
HtmlTable |
<tr> |
HtmlTableRow |
<td> |
HtmlTableCell |
其他标签 |
HtmlGenericControl |
|
Demo:动态构建html表格
通过在前台设置表格的行(x)和列(y),动态的利用System.Web.UI.HtmlControls命名空间下的控件动态的进行设置表格的大小:
前台代码如下:
<h3>HTML Controls</h3>
X
<input type="text" id="XTextBox" runat="server" /><br />
<br />
Y
<input type="text" id="YTextBox" runat="server" /><br />
<br />
<input type="submit" id="BuildTableButton" runat="server"
value="Build Table" onserverclick="BuildTableButton_ServerClick" /><br />
<br />
<span id="Span1" runat="server"></span>
</div>
后台代码如下:
protected void BuildTableButton_ServerClick(object sender, EventArgs e)
{
int xDim = Convert.ToInt32(XTextBox.Value);
int yDim = Convert.ToInt32(YTextBox.Value);
BuildTable(xDim, yDim);
}
private void BuildTable(int xDim, int yDim)
{
HtmlTable table;
HtmlTableRow row;
HtmlTableCell cell;
HtmlGenericControl content;
table = new HtmlTable();
table.Border = 1;
for (int y = 0; y < yDim; y++)
{
row = new HtmlTableRow();
for (int x = 0; x < xDim; x++)
{
cell = new HtmlTableCell();
cell.Style.Add("font", "18pt");
cell.Style.Add("background-color", "blue");
cell.Style.Add("color", "red");
content = new HtmlGenericControl("SPAN");
content.InnerHtml = "X:" + x.ToString() +
"Y:" + y.ToString();
cell.Controls.Add(content);
row.Cells.Add(cell);
}
table.Rows.Add(row);
}
Span1.Controls.Add(table);
}
这段代码通过构建HtmlTable对象,然后在其内部通过循环的方式加入tr和td.最后将结果放入<span>标签中显示。结果如下图:
注意下面几行代码:
cell = new HtmlTableCell();
cell.Style.Add("font", "18pt");
cell.Style.Add("background-color", "blue");
cell.Style.Add("color", "red");
可以通过html的style属性的add方法添加CSS的键-值对应(有点HashTable的感觉),在render(输出)到客户端的过程中会自动应用其CSS样式(注意,因为全部是string作为键和值的参数,所以要小心你的拼写J)
System.Web.UI.WebControls命名空间
在这个命名空间下封装了标准的Web控件.命名空间图示如下:
如图所示,在System.Web.UI.WebControls命名空间下的控件被分成4种类型
1. 简单控件
2. 列表控件(List)
3. 富应用控件(Rich)
4. 验证控件
1. 简单控件
简单控件有点像封装在System.Web.UI.HtmlControls命名空间里的控件,每一个控件对应一个HTML标签,TextBox除外.控件和Html标签的对应关系如下:
HTML Tag |
Simple Web Control |
<input type="text"> |
TextBox with TextMode=Single |
<input type="password"> |
TextBox with TextMode=Password |
<textarea> |
TextBox with TextMode=MultiLine |
<input type="checkbox"> |
CheckBox |
<input type="radio"> |
RadioButton |
<input type="submit"> |
Button |
<input type="image"> |
ImageButton |
<button> |
Button |
<select> |
DropDownList |
<select size=3> |
SelectList with Rows=3 |
<textarea> |
HtmlTextArea |
<img> |
Image |
<a> |
HyperLink, LinkButton |
<table> |
Table |
<tr> |
TableRow |
<td> |
TableCell |
<table> |
Panel |
<span> |
Label |
2列表控件
列表控件在简单控件的基础上,增加了数据源。从CheckBoxList控件到RadioButtonList控件,在到强大的GridView控件,提供了重复生成不同HTML代码的能力.
3富应用控件
富应用控件是那些将需要大量HTML拼接起来的东西转化为简单的一个控件,最有代表性的就是Calender控件,可以通过简单的应用就可以创造出非常复杂的效果.
4验证控件
验证控件通过提供客户端以javascript为基础的验证方式来减少与服务器的交互,从而达到减少网络流量..
System.Web.UI.WebControls?System.Web.UI.HtmlControls?
这两个命名空间内有很多控件貌似是重叠的.尤其是HTML控件和asp.net的简单控件都是以控件名称和html标签进行匹配.但Asp.net控件更加丰富,所以在不是非必要的情况下,最好使用WebControl命名空间内的控件并作为基类。
封装
在asp.net中,控件被分为两类.用户控件和自定义服务器控件。前者就是我们经常用来将一些可复用的内容封装成的.ascx文件。这里主要研究后者.
创建自定义服务器控件
创建自定义控件的第一步是选择以哪一个类作为基类来创建控件,Asp.net最常见的几个基类罗列如下:
l System.Web.UI.Control:这是所有控件的基类,所有作为控件的类都必须直接或者间接的继承此类,此类仅仅提供最少量的属性和方法。
l System.Web.UI.WebControls.WebControl:这个类继承于Control类,在实现控件最基本的属性和方法后,又额外提供了控件CSS样式相关的一系列属性。如果是UI控件,那肯定就选它了.
l System.Web.UI.WebControls.Webpart:这个不用说了,看名字就知道是提供了WebPart相关的功能.
l System.Web.UI.WebControls.CompositeControl:如果需要创建复合控件(即那些控件内部还有其他控件,比如Calender),选择这个类作为基类.
l System.Web.UI.WebControls.DatabindingControl:用于作为数据源相关控件的基类。
l System.Web.UI.WebControls.CompositeDatabindingControl:这个基类可以看做上面两个基类的结合,提供了上面两个基类的功能,GridView就是继承自这个基类.
简单控件Or复合控件
先来了解一下简单控件和复合控件的定义:
简单控件:那些直接生成(render)对应HTML的控件,比如Botton和TextBox控件.
复合控件:如何生成HTML依赖于其子控件,比如Reperater,FormView.
下面的图示会让概念更加清晰:
简单控件是那些比较简单的更加,往往是一个控件对应一个HTML标签.但缺点显而易见,就是当面对大量HTML代码片段时,就会显得更加难以维护.
复合控件在面对大量HTML代码片段时就显得游刃有余了,在遵守了面向对象抽象和封装的原则上,复合控件的维护性和易用性都不错.
Demo:创建一个简单的服务器控件:
这里我们创建一个简单的菜单自定义服务器控件。通过继承最基础的System.Web.UI.Control基类。然后覆盖Render方法来达到自定义输出的目的,代码如下:
namespace SimpleControl
{
[ToolboxData("<{0}:menucustomcontrol runat=server></{0}:menucustomcontrol>")]
public class MenuCustomControl : Control
{
protected override void Render(HtmlTextWriter writer)
{
base.Render(writer);
writer.WriteLine("<div>");
RenderMenuItem(writer, "网易", "http://www.163.com");
writer.Write(" | ");
RenderMenuItem(writer, "新浪", "http://www.sina.com");
writer.Write(" | ");
RenderMenuItem(writer, "MSDN", "http://msdn.microsoft.com");
writer.Write(" | ");
RenderMenuItem(writer, "ASP.NET", "http://asp.net");
writer.WriteLine("</div>");
}
private void RenderMenuItem(HtmlTextWriter writer, string title, string url)
{
writer.Write("<span><a href=""");
writer.Write(url);
writer.Write(""">");
writer.Write(title);
writer.WriteLine("</a><span>");
}
}
}
通过HtmlTextWriter类,我们可以在控件原有的基础上,加入我们自己想加入的内容,注意base.Render(writer);方法,通过调用父类的Render方法,我们可以再实现父类的基础上,加入我们额外的内容(很像设计模式里的装饰模式)
控件使用方法:
Ok,控件完成了.使用方法很简单,只需要在页面头部添加如下代码引入控件即可:
<%@ Register TagPrefix="sc" Namespace="SimpleControl" %>
在使用时就像使用用户控件一样,在页面注册完成后,系统会自动搜索命名空间内的直接或间接继承于Control基类的控件,在前台使用时,会自动出现智能提示:
代码如下:
<sc:MenuCustomControl runat="server"></sc:MenuCustomControl>
页面执行,效果如下:
Demo2:继承现有控件
在很多情况下,我们并不需要重新发明轮子,我们可以通过继承来利用现有控件的特性并额外添加我们需要的功能达到复用的目的.先看一下效果:
通过继承TextBox控件,并添加额外的Enable3d属性,使现有控件拥有额外的属性。前台代码摘录如下:
我是3D的:<sc:TextBox3d runat="server"></sc:TextBox3d><br />
我不是:<sc:TextBox3d runat="server" Enable3D="false"></sc:TextBox3d>
后台代码如下:
[ToolboxData("<{0}:textbox3d runat=server></{0}:textbox3d>")]
public class TextBox3d : TextBox// 继承自TextBox
{
public TextBox3d()
{
Enable3D = true;
}
public bool Enable3D
{
get
{
object enable3D = ViewState["Enable3D"];
if (enable3D == null)
return false;
else
return (bool)enable3D;
}
set
{
ViewState["Enable3D"] = value;
}
}
protected override void Render(HtmlTextWriter output)
{
if (Enable3D)
output.AddStyleAttribute("FILTER", "progid:DXImageTransform.Microsoft.dropshadow(OffX=2, OffY=2, Color='gray', Positive='true'");
base.Render(output);
}
}
标签(Attribute)
也许你已经对上面代码的[ToolboxData("<{0}:textbox3d runat=server></{0}:textbox3d>")]感到很迷惑,其实这是C#特有的一种类型。Attribute的本质是一种用于修改其他类的属性或方法的类,其实Attribute本身就是一种类,所有的Attribute都会直接或者间接的继承于System.Attribute,像接口的名称往往以大写的I开头一样,标签的结尾习惯上以Attribute结尾,这样可以增加可读性.简单的示例如下:
public class SampleAttribute : Attribute
{
}
注意,所有的标签(Attribute)都必须被声明为public.
在使用时可以像这样:
public class SampleClass
{
[SampleAttribute]
public virtual void SampleMethod()
{
//...
}
}
在应用的时候,你可以针对一个类,方法或者属性应用好几个Attribute.应用方法可以将这些都写入一个方括号中,就像这样:
[DefaultProperty("Text"), toolboxdata("<{0}:mylabel runat=server></{0}:mylabel>")]
也可以分别写在几个不同的方括号中,就像这样:
[DefaultProperty("Text")]
[ToolboxData("<{0}:mylabel runat=server></{0}:mylabel>")]
Visual Studio控件开发常用的标签(Attribute)
在利用Visual Studio进行控件开发时,利用Attribute特性可以让空间更加智能,比如当你双击控件时,默认会进入控件的哪个事件的EventHandler,或者当你从ToolBox里拽过来你开发的控件,默认在前台会生成什么样的代码片段等.这些都可以利用Attribute做到.这些常用的属性都被定义在System.ComponentModel命名空间中,下面是这个命名空间里的常用的Attribute.
Attribute |
描述 |
BindableAttribute |
Indicates whether or not a property supports two-way data binding |
BrowsableAttribute |
Indicates whether or not a property or event should be listed in a property browser |
DefaultEvent |
Specifies the name of the default event for a class |
DescriptionAttribute |
Allows the property browser to display a brief description of a property |
ToolboxData |
Specifies default values for control attributes and customizes the initial HTML content |
EditorAttribute |
Associates a UI type editor with a property |
DefaultProperty |
Specifies the name of the default property for a class
|
原文引自:http://www.cnblogs.com/CareySon/archive/2009/09/30/1576984.html