一、属性在页面及源码中的表示方式
认真地看看页面中声明控件的代码,你会发现控件属性在页面中的表示千变万化。我们看看下面这些:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="控件属性在页面源码中的表达方式.aspx.cs"
Inherits="CustomServerControlTest.控件属性在页面源码中的表达方式" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>控件属性在页面源码中的表达方式</title>
</head>
<body>
<form id="form1" runat="server">
<div id="divOperation">
当前页面所在程序集:
<%
1: =System.Reflection.Assembly.GetExecutingAssembly().Location
%>
</div>
<!-- ------------------------------------------------------------分割线------------------------------------------------------------ -->
<div id="divDemo">
<asp:Label ID="Label1" runat="server" Text="Hello Label!"></asp:Label>
<asp:Label ID="Label2" runat="server">Hello Label!</asp:Label>
<asp:Label ID="Label3" runat="server" Text="Hello Label!" Font-Bold="true" Font-Size="14"></asp:Label>
<asp:TextBox ID="TextBox1" runat="server">Hello TextBox!</asp:TextBox>
<asp:Panel ID="Panel1" runat="server">Hello Panel!</asp:Panel>
<asp:DropDownList ID="ddlGender" runat="server">
<asp:ListItem Value="1">男</asp:ListItem>
<asp:ListItem Value="0">女</asp:ListItem>
</asp:DropDownList>
<asp:GridView ID="Gridview1" runat="server" AutoGenerateColumns="False" EnableModelValidation="True">
<Columns>
<asp:BoundField HeaderText="HeaderText1" />
<asp:CheckBoxField HeaderText="HeaderText2" />
</Columns>
<EditRowStyle BackColor="Red" />
</asp:GridView>
</div>
<!-- ------------------------------------------------------------分割线------------------------------------------------------------ -->
</form>
</body>
</html>
再看看这些属性在源码中的表示:
using CustomServerControlTest;
using System;
using System.Diagnostics;
using System.Drawing;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Web;
using System.Web.Profile;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
namespace ASP
{
[CompilerGlobalScope]
public class 控件属性在页面源码中的表达方式_aspx : 控件属性在页面源码中的表达方式, IRequiresSessionState, IHttpHandler
{
private static bool __initialized;
private static object __fileDependencies;
protected DefaultProfile Profile
{
get
{
return (DefaultProfile)this.Context.Profile;
}
}
protected HttpApplication ApplicationInstance
{
get
{
return this.Context.ApplicationInstance;
}
}
[DebuggerNonUserCode]
public 控件属性在页面源码中的表达方式_aspx()
{
base.AppRelativeVirtualPath = "~/控件属性在页面源码中的表达方式.aspx";
if (!控件属性在页面源码中的表达方式_aspx.__initialized)
{
控件属性在页面源码中的表达方式_aspx.__fileDependencies = base.GetWrappedFileDependencies(new string[]
{
"~/控件属性在页面源码中的表达方式.aspx"
});
控件属性在页面源码中的表达方式_aspx.__initialized = true;
}
base.Server.ScriptTimeout = 30000000;
}
[DebuggerNonUserCode]
private HtmlTitle __BuildControl__control3()
{
return new HtmlTitle();
}
[DebuggerNonUserCode]
private HtmlHead __BuildControl__control2()
{
HtmlHead __ctrl = new HtmlHead("head");
HtmlTitle __ctrl2 = this.__BuildControl__control3();
IParserAccessor __parser = __ctrl;
__parser.AddParsedSubObject(__ctrl2);
return __ctrl;
}
//--------------------------------------------------------------分割线--------------------------------------------------------------
[DebuggerNonUserCode]
private Label __BuildControlLabel1()
{
Label __ctrl = new Label();
this.Label1 = __ctrl;
__ctrl.ApplyStyleSheetSkin(this);
__ctrl.ID = "Label1";
__ctrl.Text = "Hello Label!";
return __ctrl;
}
[DebuggerNonUserCode]
private Label __BuildControlLabel2()
{
Label __ctrl = new Label();
this.Label2 = __ctrl;
__ctrl.ApplyStyleSheetSkin(this);
__ctrl.ID = "Label2";
IParserAccessor __parser = __ctrl;
__parser.AddParsedSubObject(new LiteralControl("Hello Label!"));
return __ctrl;
}
[DebuggerNonUserCode]
private Label __BuildControlLabel3()
{
Label __ctrl = new Label();
this.Label3 = __ctrl;
__ctrl.ApplyStyleSheetSkin(this);
__ctrl.ID = "Label3";
__ctrl.Text = "Hello Label!";
__ctrl.Font.Bold = true;
__ctrl.Font.Size = new FontUnit(new Unit(14.0, UnitType.Point));
return __ctrl;
}
[DebuggerNonUserCode]
private TextBox __BuildControlTextBox1()
{
TextBox __ctrl = new TextBox();
this.TextBox1 = __ctrl;
__ctrl.ApplyStyleSheetSkin(this);
__ctrl.ID = "TextBox1";
__ctrl.Text = "Hello TextBox!";
return __ctrl;
}
[DebuggerNonUserCode]
private Panel __BuildControlPanel1()
{
Panel __ctrl = new Panel();
this.Panel1 = __ctrl;
__ctrl.ApplyStyleSheetSkin(this);
__ctrl.ID = "Panel1";
IParserAccessor __parser = __ctrl;
__parser.AddParsedSubObject(new LiteralControl("Hello Panel!"));
return __ctrl;
}
[DebuggerNonUserCode]
private ListItem __BuildControl__control5()
{
return new ListItem
{
Value = "1",
Text = "男"
};
}
[DebuggerNonUserCode]
private ListItem __BuildControl__control6()
{
return new ListItem
{
Value = "0",
Text = "女"
};
}
[DebuggerNonUserCode]
private void __BuildControl__control4(ListItemCollection __ctrl)
{
ListItem __ctrl2 = this.__BuildControl__control5();
__ctrl.Add(__ctrl2);
ListItem __ctrl3 = this.__BuildControl__control6();
__ctrl.Add(__ctrl3);
}
[DebuggerNonUserCode]
private DropDownList __BuildControlddlGender()
{
DropDownList __ctrl = new DropDownList();
this.ddlGender = __ctrl;
__ctrl.ApplyStyleSheetSkin(this);
__ctrl.ID = "ddlGender";
this.__BuildControl__control4(__ctrl.Items);
return __ctrl;
}
[DebuggerNonUserCode]
private BoundField __BuildControl__control8()
{
return new BoundField
{
HeaderText = "HeaderText1"
};
}
[DebuggerNonUserCode]
private CheckBoxField __BuildControl__control9()
{
return new CheckBoxField
{
HeaderText = "HeaderText2"
};
}
[DebuggerNonUserCode]
private void __BuildControl__control7(DataControlFieldCollection __ctrl)
{
BoundField __ctrl2 = this.__BuildControl__control8();
__ctrl.Add(__ctrl2);
CheckBoxField __ctrl3 = this.__BuildControl__control9();
__ctrl.Add(__ctrl3);
}
[DebuggerNonUserCode]
private void __BuildControl__control10(TableItemStyle __ctrl)
{
__ctrl.BackColor = Color.Red;
}
[DebuggerNonUserCode]
private GridView __BuildControlGridview1()
{
GridView __ctrl = new GridView();
this.Gridview1 = __ctrl;
__ctrl.ApplyStyleSheetSkin(this);
__ctrl.ID = "Gridview1";
__ctrl.AutoGenerateColumns = false;
__ctrl.EnableModelValidation = true;
this.__BuildControl__control7(__ctrl.Columns);
this.__BuildControl__control10(__ctrl.EditRowStyle);
return __ctrl;
}
//--------------------------------------------------------------分割线--------------------------------------------------------------
[DebuggerNonUserCode]
private HtmlForm __BuildControlform1()
{
HtmlForm __ctrl = new HtmlForm();
this.form1 = __ctrl;
__ctrl.ID = "form1";
Label __ctrl2 = this.__BuildControlLabel1();
IParserAccessor __parser = __ctrl;
__parser.AddParsedSubObject(__ctrl2);
Label __ctrl3 = this.__BuildControlLabel2();
__parser.AddParsedSubObject(__ctrl3);
Label __ctrl4 = this.__BuildControlLabel3();
__parser.AddParsedSubObject(__ctrl4);
TextBox __ctrl5 = this.__BuildControlTextBox1();
__parser.AddParsedSubObject(__ctrl5);
Panel __ctrl6 = this.__BuildControlPanel1();
__parser.AddParsedSubObject(__ctrl6);
DropDownList __ctrl7 = this.__BuildControlddlGender();
__parser.AddParsedSubObject(__ctrl7);
GridView __ctrl8 = this.__BuildControlGridview1();
__parser.AddParsedSubObject(__ctrl8);
__ctrl.SetRenderMethodDelegate(new RenderMethod(this.__Renderform1));
return __ctrl;
}
private void __Renderform1(HtmlTextWriter __w, Control parameterContainer)
{
__w.Write("
<div id="divOperation">
当前页面所在程序集:
");
__w.Write(Assembly.GetExecutingAssembly().Location);
__w.Write("
</div>
<div id="divDemo">
");
parameterContainer.Controls[0].RenderControl(__w);
__w.Write("
");
parameterContainer.Controls[1].RenderControl(__w);
__w.Write("
");
parameterContainer.Controls[2].RenderControl(__w);
__w.Write("
");
parameterContainer.Controls[3].RenderControl(__w);
__w.Write("
");
parameterContainer.Controls[4].RenderControl(__w);
__w.Write("
");
parameterContainer.Controls[5].RenderControl(__w);
__w.Write("
");
parameterContainer.Controls[6].RenderControl(__w);
__w.Write("
</div>
");
}
[DebuggerNonUserCode]
private void __BuildControlTree(控件属性在页面源码中的表达方式_aspx __ctrl)
{
this.InitializeCulture();
((IParserAccessor)__ctrl).AddParsedSubObject(new LiteralControl(" <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> "));
HtmlHead __ctrl2 = this.__BuildControl__control2();
((IParserAccessor)__ctrl).AddParsedSubObject(__ctrl2);
((IParserAccessor)__ctrl).AddParsedSubObject(new LiteralControl(" <body> "));
HtmlForm __ctrl3 = this.__BuildControlform1();
((IParserAccessor)__ctrl).AddParsedSubObject(__ctrl3);
((IParserAccessor)__ctrl).AddParsedSubObject(new LiteralControl(" </body> </html> "));
}
[DebuggerNonUserCode]
protected override void FrameworkInitialize()
{
base.FrameworkInitialize();
this.__BuildControlTree(this);
base.AddWrappedFileDependencies(控件属性在页面源码中的表达方式_aspx.__fileDependencies);
base.Request.ValidateInput();
}
[DebuggerNonUserCode]
public override int GetTypeHashCode()
{
return -1997224554;
}
[DebuggerNonUserCode]
public override void ProcessRequest(HttpContext context)
{
base.ProcessRequest(context);
}
}
}
哦,顺便也看看父类的一部分,看看继承了什么?
//------------------------------------------------------------------------------
// <自动生成>
// 此代码由工具生成。
//
// 对此文件的更改可能会导致不正确的行为,并且如果
// 重新生成代码,这些更改将会丢失。
// </自动生成>
//------------------------------------------------------------------------------
namespace CustomServerControlTest
{
public partial class 控件属性在页面源码中的表达方式
{
/// <summary>
/// form1 控件。
/// </summary>
/// <remarks>
/// 自动生成的字段。
/// 若要进行修改,请将字段声明从设计器文件移到代码隐藏文件。
/// </remarks>
protected global::System.Web.UI.HtmlControls.HtmlForm form1;
/// <summary>
/// Label1 控件。
/// </summary>
/// <remarks>
/// 自动生成的字段。
/// 若要进行修改,请将字段声明从设计器文件移到代码隐藏文件。
/// </remarks>
protected global::System.Web.UI.WebControls.Label Label1;
/// <summary>
/// Label2 控件。
/// </summary>
/// <remarks>
/// 自动生成的字段。
/// 若要进行修改,请将字段声明从设计器文件移到代码隐藏文件。
/// </remarks>
protected global::System.Web.UI.WebControls.Label Label2;
/// <summary>
/// Label3 控件。
/// </summary>
/// <remarks>
/// 自动生成的字段。
/// 若要进行修改,请将字段声明从设计器文件移到代码隐藏文件。
/// </remarks>
protected global::System.Web.UI.WebControls.Label Label3;
/// <summary>
/// TextBox1 控件。
/// </summary>
/// <remarks>
/// 自动生成的字段。
/// 若要进行修改,请将字段声明从设计器文件移到代码隐藏文件。
/// </remarks>
protected global::System.Web.UI.WebControls.TextBox TextBox1;
/// <summary>
/// Panel1 控件。
/// </summary>
/// <remarks>
/// 自动生成的字段。
/// 若要进行修改,请将字段声明从设计器文件移到代码隐藏文件。
/// </remarks>
protected global::System.Web.UI.WebControls.Panel Panel1;
/// <summary>
/// ddlGender 控件。
/// </summary>
/// <remarks>
/// 自动生成的字段。
/// 若要进行修改,请将字段声明从设计器文件移到代码隐藏文件。
/// </remarks>
protected global::System.Web.UI.WebControls.DropDownList ddlGender;
/// <summary>
/// Gridview1 控件。
/// </summary>
/// <remarks>
/// 自动生成的字段。
/// 若要进行修改,请将字段声明从设计器文件移到代码隐藏文件。
/// </remarks>
protected global::System.Web.UI.WebControls.GridView Gridview1;
}
}
我们做个对应表好了:
序号 |
页面中的表示方式 |
源码中的表示方式 |
① |
<asp:Label ID="Label1" runat="server" Text="Hello Label!"></asp:Label> |
Label1.ID = "Label1";
Label1.Text = "Hello Label!";
|
② |
<asp:Label ID="Label2" runat="server">Hello Label!</asp:Label> |
Label2.ID = "Label2";
Label2.Controls.Add(new LiteralControl("Hello Label!")); |
③ |
<asp:Label ID="Label3" runat="server" Text="Hello Label!" Font-Bold="true" Font-Size="14"></asp:Label> |
Label3.ID = "Label3";
Label3..Text = "Hello Label!";
Label3.Font.Bold = true;
Label3.Font.Size = new FontUnit(new Unit(14.0, UnitType.Point)); |
④ |
<asp:TextBox ID="TextBox1" runat="server">Hello TextBox!</asp:TextBox> |
TextBox1.ID = "TextBox1";
TextBox1.Text = "Hello TextBox!";
|
⑤ |
<asp:Panel ID="Panel1" runat="server">Hello Panel!</asp:Panel> |
Panel1.ID = "Panel1";
Panel1.Controls.Add(new LiteralControl("Hello Panel!")); |
⑥ |
<asp:DropDownList ID="ddlGender" runat="server"> <asp:ListItem Value="1">男</asp:ListItem> <asp:ListItem Value="0">女</asp:ListItem> </asp:DropDownList> |
ddlGender.ID = "ddlGender";
ddlGender.Items.Add( new ListItem{Value = "1",Text = "男"}); ddlGender.Items.Add( new ListItem{Value = "0",Text = "女"}); |
⑦ |
<asp:GridView ID="Gridview1" runat="server" AutoGenerateColumns="False" EnableModelValidation="True"> <Columns> <asp:BoundField HeaderText="HeaderText1" /> <asp:CheckBoxField HeaderText="HeaderText2" /> </Columns> <EditRowStyle BackColor="Red" /> </asp:GridView> |
Gridview1.ID = "Gridview1";
Gridview1.AutoGenerateColumns = false;
Gridview1.EnableModelValidation = true;
Gridview1.Columns.Add(new BoundField{HeaderText = "HeaderText1"}); Gridview1.Columns.Add(new CheckBoxField{HeaderText = "HeaderText2"}); Gridview1.EditRowStyle .BackColor = Color.Red; |
二、处理嵌套内容
开始之前,先看一下概念,什么是嵌套内容?嵌套内容是指服务器起始标签与服务器结束标签间的元素集。
我们对比对应表中②、④发现同样是嵌套内容,有的被解析成了属性,有的被解析成了子控件。这种对服务器控件标记中嵌套内容的解析行为是怎么控制的呢?
1、ParseChildrenAttribute登场:
ParseChildrenAttribute:是一个类级别的属性。使用 ParseChildrenAttribute 类指示页分析器应如何处理页上声明的服务器控件标记中的嵌套内容。
命名空间:System.Web.UI
程序集:System.Web(在 system.web.dll 中)
ParseChildrenAttribute类的构造函数有以下四个重载版本:
名称 | 说明 |
ParseChildrenAttribute () | 初始化 ParseChildrenAttribute 类的新实例。ChildrenAsProperties 属性默认为false。 |
ParseChildrenAttribute (Boolean) | 使用 ChildrenAsProperties 属性初始化 ParseChildrenAttribute 类的新实例,以确定服务器控件标记中的嵌套内容是否被分析为服务器控件的属性。 |
ParseChildrenAttribute (Type) | 使用 ChildControlType 属性初始化 ParseChildrenAttribute 类的新实例,以确定服务器控件标记中的嵌套内容哪些元素将被分析为控件。 |
ParseChildrenAttribute (Boolean, String) | 使用 childrenAsProperties 和 defaultProperty 参数初始化 ParseChildrenAttribute 类的新实例。 defaultProperty 用于指定服务器控件标记中的嵌套内容解析成哪个属性的值。 |
Lable因为装饰了[ParseChildren(false)]而将其嵌套内容解析为子控件:
[ParseChildren(false)]
public class Label : WebControl, ITextControl
{
//... ...
}
TextBox因为装饰了[ParseChildren(true, "Text")]而将其嵌套内容解析成属性值,并赋值给Text属性:
[ParseChildren(true, "Text")]
public class TextBox : WebControl, IPostBackDataHandler, IEditableTextControl, ITextControl
{
//... ...
}
2、PersistChildrenAttribute登场:
PersistChildrenAttribute:是一个类级别的属性,使用 PersistChildrenAttribute类指示设计器应如何处理页上声明的服务器控件标记中的嵌套内容。
命名空间:System.Web.UI
程序集:System.Web(在 system.web.dll 中)
名称 | 说明 |
PersistChildrenAttribute(Boolean) | 使用persist属性初始化PersistChildrenAttribute类的新实例,以告知设计服务器控件标记中的嵌套内容是否仍是控件。 |
PersistChildrenAttribute(Boolean, Boolean) | 用persist属性和UsesCustomPersistence属性初始化 PersistChildrenAttribute 类的新实例。 persist属性指示是否将嵌套内容作为嵌套控件保持,UsesCustomPersistence属性指示是否使用自定义的保持方法。 |
注:ParseChildrenAttribute和PersistChildrenAttribute常同时出现,ParseChildrenAttribute将对控件标签内嵌套内容的解析行为告知页分析器;PersistChildrenAttribute将对控件标签内嵌套内容的解析行为告知设计器,但两者构造函数的参数的意义不同。ParseChildrenAttribute的参数为ChildrenAsProperties ,表示是否解析为属性;PersistChildrenAttribute的参数为persist,表示是否将嵌套内容作为嵌套控件保持。所以控件上如果出现[ParseChildren(false)]就会出现[PersistChildren(true)],反之亦然。
[ParseChildren(false), PersistChildren(true)]
public class Panel : WebControl
{
//... ...
}
3、PersistenceModeAttribute登场:
PersistenceModeAttribute:是一个元素级别的属性。用于指定控件属性的保存(持久化)方式,它接受一个枚举类型参数:PersistenceMode,其枚举值及意义如下表:
名称 | 说明 |
Attribute | 指定属性或事件保持为特性。 |
EncodedInnerDefaultProperty | 指定属性保存为控件的唯一嵌套内容。当属性为字符串且是HTML编码时,只能对该属性做这种指定。 |
InnerDefaultProperty | 指定属性保存为控件的唯一嵌套内容。 |
InnerProperty | 指定属性在 ASP.NET 服务器控件中保持为嵌套标记。 这通常用于复杂对象,它们具有自己的持久性属性。 |
①EncodedInnerDefaultProperty:
我们上面说到TextBox因为装饰了[ParseChildren(true, "Text")]而将其嵌套内容解析成Text属性的属性值,相应的TextBox的Text属性也被修饰上了[PersistenceMode(PersistenceMode.EncodedInnerDefaultProperty)],使得Text成为TextBox唯一嵌套内容,而且如果嵌套内容中存在标签格式的文本,解析器页不会把这些标签进行进一步解析。
[ParseChildren(true, "Text")]
public class TextBox : WebControl, IPostBackDataHandler, IEditableTextControl, ITextControl
{
//... ...
[PersistenceMode(PersistenceMode.EncodedInnerDefaultProperty)]
public virtual string Text
{
//... ...
}
//... ...
}
②InnerDefaultProperty:
我们再看DropDownList的父类ListControl。它装饰了[ParseChildren(true, "Items")]而将其嵌套内容解析成Items属性的属性值,相应的ListControl的Text属性也被修饰上了[PersistenceMode(PersistenceMode.InnerDefaultProperty)],使得Items成为ListControl唯一嵌套内容。
[ParseChildren(true, "Items")]
public abstract class ListControl : DataBoundControl, IEditableTextControl, ITextControl
{
//... ...
[PersistenceMode(PersistenceMode.InnerDefaultProperty)]
public virtual ListItemCollection Items
{
//... ...
}
//... ...
}
也正因为Items是ListControl唯一的嵌套内容,所以对应表⑥中才可以省略Items标签,直接设置Items的值。
<asp:DropDownList ID="ddlGender" runat="server">
<Items> <!-- 可省略Items标签 -->
<asp:ListItem Value="1">男</asp:ListItem> <!-- 直接设置Items值,就可以了...-->
<asp:ListItem Value="0">女</asp:ListItem>
</Items>
</asp:DropDownList>
③InnerProperty:
复杂的控件通常有多个属性需要持久化在嵌套内容里。这些属性会被装饰上[PersistenceMode(PersistenceMode.InnerProperty)],比如GridView。
[ParseChildren(true)] //在GridView实现代码中没有装饰[ParseChildren(true)],该特性继承自WebControl。
public class GridView : CompositeDataBoundControl, IPostBackContainer, IPostBackEventHandler, ICallbackContainer, ICallbackEventHandler, IPersistedSelector
{
//... ...
[PersistenceMode(PersistenceMode.InnerProperty)]
public virtual DataControlFieldCollection Columns
{
//... ...
}
[PersistenceMode(PersistenceMode.InnerProperty)]
public TableItemStyle EditRowStyle
{
//... ...
}
//... ...
//... ...
}
三、源代码视图控件
实现代码:
using System.Web.UI;
using System.Text.RegularExpressions;
using System.Web;
namespace CustomServerControl
{
[ParseChildren(true,"Text"),PersistChildren(false)]
public class SourceView:Control
{
//清除源代码前多余的换行符所用的正则表达式
static Regex _regTrimBeginCarriageReturn = new Regex(@"^( )+", RegexOptions.Compiled | RegexOptions.Multiline);
//清除源代码后多余的换行符所用的正则表达式
static Regex _regTrimEndCarriageReturn = new Regex(@"( )+$", RegexOptions.Compiled);
[PersistenceMode(PersistenceMode.EncodedInnerDefaultProperty)]
public string Text
{
set
{
this.ViewState["Text"] = value;
}
get
{
object obj = this.ViewState["Text"];
if (null == obj)
{
return string.Empty;
}
return (string)obj;
}
}
protected override void Render(HtmlTextWriter writer)
{
string sourceCode = _regTrimBeginCarriageReturn.Replace(this.Text, string.Empty);
sourceCode = _regTrimEndCarriageReturn.Replace(sourceCode, string.Empty);
sourceCode = HttpUtility.HtmlEncode(sourceCode); //Html编码
sourceCode = sourceCode.Replace(" ", " ").Replace(" ", "<br/>");
writer.Write(sourceCode);
}
}
}
测试代码:
<%@ page language="C#" autoeventwireup="true" codebehind="SourceViewTest.aspx.cs"
inherits="CustomServerControlTest.SourceViewTest" %>
<%@ register assembly="CustomServerControl" namespace="CustomServerControl" tagprefix="csc" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<csc:sourceview id="SourceView1" runat="server">
<html>
<head>
<title>Hello SourceView!</title>
</head>
<body>
<form>
<h1>SourceView Test</h1>
</form>
</body>
</html>
</csc:sourceview>
</div>
</form>
</body>
</html>
测试截图:
四、总结
1、嵌套内容是指服务器起始标签与服务器结束标签间的元素集。
2、嵌套内容可以解析成了属性(集合),也可以解析成子控件(集合)。这需要ParseChildrenAttribute告知页分析器,PersistChildrenAttribute告知设计器。
3、简单控件嵌套内容中通常用来持久化最重要的一个属性,复杂控件嵌套内容中通常用来持久化控件中不易于用标签属性表达的复杂属性。需要持久化到嵌套内容的属性需装饰PersistenceModeAttribute。