using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Security.Permissions;
namespace ServerControl
{
/// <summary>
/// 如果用户名出现在用户浏览器发送的标题中,WelcomeLabel 就会将用户名追加到该文本字符串。
/// </summary>
//[AspNetHostingPermission(SecurityAction.Demand,Level=AspNetHostingPermissionLevel.Minimal)]
//[AspNetHostingPermission(SecurityAction.InheritanceDemand,Level=AspNetHostingPermissionLevel.Minimal)]
[ParseChildren(true,"Text")]
[DefaultProperty("Text")]
[ToolboxData("<{0}:ServerControlXin runat=\"server\"></{0}:ServerControlXin>")]
public class ServerControlXin : WebControl
{
[Bindable(true)]
[Category("Appearance")]
[DefaultValue("第一个控件")]
[Description("服务器控件")]
[Localizable(true)]
public string Text
{
get
{
string s = (String)ViewState["Text"];
return ((s == null) ? string.Empty : s);
}
set
{
ViewState["Text"] = value;
}
}
protected override void RenderContents(HtmlTextWriter writer)
{
// 对Text经行编码
writer.WriteEncodedText(Text);
// 用HemlTextWriter中的Write方法将内容写入流
writer.Write("欣,忘不了的,是你眸光如水,浅溺着我一世的欢悲。。。");
writer.Write(Text);
}
}
}
Tip:
1. [ParseChildren(true,"Text")]和ToolboxData标记需配合使用,不然即使在ToolboxData中定义了默认样式,也不能显示为双标记。
2.在将生成的dll文件添加到Bin和工具箱之后,如果从新生成了项目,则需要重新引用添加工具箱中,不然又是单标记,原因不知道。
3.[ParseChildren(false,"Text")]为false时,标记之间的文本不显示
ViewState:
工作原理:当处理请求后,页面框架会收集所有空间树的状态并创建一个对象图,ViewState字典也在其中,然后把对象图序列化为一个字符串作为
一个隐含变量发到客户端,当浏览器将网页回传给服务器时,页面框架读取隐藏信息并进行并行化,然后再一一对应的写入控件中的ViewState字典中。
可以存储的类型:ViewState中可以存储Int32,Boolean,String,Unit和Color,还为Arrary和ArraryList和以上类型的HashTable的对象而优化。如果不是
以上类型,则通过类型转换器进行转换成一个字符串,如果没有转换器,.net框架会用二进制进行转化,但代价很昂贵。
简单属性:可以很容易的转换为文本型(字符串)表达式的属性。
复杂属性:非数值类型和非字符串的引用类型和集合类型。
声明持久性:声明性语法。
Control中的Rendering方法:
Control中按顺序调用三个方法:
每个页面都有一个控件树,为了生成控件树,页面将建一个HtmlText类的实例,这个实例中封装了一个响应流,然后将这个对象传递给RenderControl方法,
这个方法将验证控件的Visible的值,来判断是否要显示,要显示的话,则继续按顺序调用其他两个方法,以递归的方式创建所有Visible为true的控件。
public void RenderControl(HtmlTextWriter writer)
{
if (Visible)
{
Render(writer);
}
}
protected virtual void Render(HtmlTextWriter writer)
{
RenderChildren(writer);
}
protected virtual void RenderChildren(HtmlTextWriter writer)
{
foreach (Control c in Controls)
{
c.RenderControl();
}
}
控件的生命周期:个人理解,当服务器控件在提交后,会回到初始状态,在服务器回发之后再进行恢复
1.实例化:页面或另一个控件通过调用它的构造器将它实例化,页面根据.aspx页面的声明语法建造了控件树,后续的步骤只有在控件加入到这个控件树中才会发生。
2.初始化:控件树中的页面和所有控件通过默认方式来调用OnInit方法。
3.开始跟踪视图状态:此阶段发生在初始化的末尾,页面自动调用控件的TrackViewState方法,该方法确保在这个生命周期结束的时候,使用ViewState保存的属性
会保存在控件的视图状态中。
4.加载视图状态(仅用于回传过程):在该阶段,页面框架自动加载ViewState字段,一般情况下不必在这里实现逻辑。
5.加载回传数据选项(仅用于回传过程,可选项):只有控件实现了IPostBackDataHandler接口参与了回传数据时,才会发生。对应方法LoadPostData。
6.加载:在此阶段以前,控件已经回到了上一个生命周期的最后状态,对应的重载方法——OnLoad,如果仅要实现初始化时的逻辑,那么if(IsPostBack==false){........}
7.引发修改事件(仅用于回传过程,可选项):只有控件实现了IPostBackDataHandler接口参与了回传数据时,才会发生。控件状态由回发而引起改变,如:TextBox。
8.引发回传事件(仅用于回传过程,可选项):只有控件实现了IPostBackDataHandler接口参与了回传数据时,才会发生,通过实现接口的RaiscPostBackEvent方法,
实现逻辑,目的,把客户端事件映射到服务器端事件。如:Button。
9.预生成(PreRender):在此阶段中,通过执行OnPreRender方法,将执行在生成控件之前的所需的任何操作。
10.保存视图状态:如果要自定义状态管理,则在此阶段重载SaveViewState方法,且只对EnableViewState为true的有效,在此阶段后,控件的任何改变将不做保存。
11.生成(Render):在输出流上通过重载Control的Render方法或者WebControl的Rendering方法中的一个绘制界面
12.卸载(UnLond):此阶段中,页面通过调用Page_UnLoad,来进行清除工作。在控件树中的页面和控件都会默认引发UnLoad事件。
13.释放(Dispose):重载Dispose方法释放占用的控件。
优化事件实现:使用事件属性去替代私有域
因为1.原来的如:public event EventHandler Click这种,编译器会生成一个私有域,而且每一个事件都声明一个,及为浪费内存。2.在编译器产生的添加和移除方法
时会为线程的安全做出同位标记,也就是说在从事件中添加或删除委托时,线程会加锁,这会增加系统的开销。
事件属性的实现:
1.声明
// 私有静态的只读事件对象
private static readonly object EventClickNext = new object();
// 事件属性
public event EventHandler ClickNext
{
add
{
Events.AddHandler(EventClickNext, value);
}
remove
{
Events.RemoveHandler(EventClickPrevious, value);
}
}
2.使用
/// <summary>
/// 回传处理
/// </summary>
/// <param name="eventArgument"></param>
void IPostBackEventHandler.RaisePostBackEvent(string eventArgument)
{
// eventArgument接收页面_EVENTARGUMENT隐藏变量的值,
// 就是Page.GetPostBackEventReference中的第二个参数
if (eventArgument == "Previous")
{
OnPreviousClick(EventArgs.Empty);
}
else if (eventArgument == "Next")
{
OnNextClick(EventArgs.Empty);
}
}
/// <summary>
/// 前一按钮窗口
/// </summary>
/// <param name="eventArgument"></param>
private void OnNextClick(EventArgs eventArgs)
{
EventHandler nextClick = (EventHandler)Events[EventClickNext];
if (nextClick != null)
{
nextClick(this, eventArgs);
}
}
Tip:
在ReaderContent中和AddAttributesToReader中都可以为控件加属性/事件方法,例如:
/// <summary>
/// 添加客户端样式
/// </summary>
/// <param name="writer">输出流</param>
protected override void AddAttributesToRender(HtmlTextWriter writer)
{
base.AddAttributesToRender(writer);
writer.AddStyleAttribute(HtmlTextWriterStyle.FontSize, "30");
writer.AddAttribute("onmouseover", "this.style.textDecoration='underline';status='" + StatusBarText + "';");
writer.AddAttribute("onmouseout", "this.style.textDecoration='none';status='';",false);
}
在客户端生成:
οnmοuseοver="this.style.textDecoration='underline';status='好男儿当战死沙场,马革裹尸,搏一个封妻荫子。。。';">
在控件中直接执行js脚本,则需加上"javascript:",例如:
protected override void RenderContents(HtmlTextWriter writer)
{
// CheckBox
writer.AddAttribute(HtmlTextWriterAttribute.Type, "checkbox");
writer.AddAttribute(HtmlTextWriterAttribute.Onclick, "javascript:alert('AAAAA');");
writer.RenderBeginTag(HtmlTextWriterTag.Input);
writer.RenderEndTag();
// TextBox
base.RenderContents(writer);
}
复杂属性
子属性:如TextBox中的属性
例如Font属性中有Font-Size,Font-Color,Font-Name等,Font为FontInfo类型,这个类中有Size,Color,Name等属性。
public class WebControl : Control
{
// FontInfo是一个类,类中有Size,Name,Color等属性
// 进入子属性,并将子属性串行化
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
// 标记当前属性是否修改
[NotifyParentProperty(true)]
public FontInfo Font
{
}
}
// 类型转换器,ExpandableObjectConverter——折叠属性
[TypeConverter(typeof(ExpandableObjectConverter))]
public sealed class FontInfo
{
// 改变时标记当前属性
[NotifyParentProperty(true)]
public string Name { }
}
内部属性:如DataGrid中的HeaderStyle
<asp:DataGrid runat="server">
<HeaderStyle ForeColor=""/>
</asp:DataGrid>
必备属性标识:
[ParseChildren(true)]:告诉页面解析器把控制标签内的内容解析成属性。
[PersistChildren(false)]:告诉页面解析器把内部内容理解为属性而不是子控件。
当控件继承WebControl时可省略
// 串行化内容
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
// 标记属性改变
[NotifyParentProperty(true)]
// 将属性持久保存为内部属性
[PersistenceMode(PersistenceMode.InnerProperty)]
public virtual TableItemStyle HeaderStyle { }
CanConvertFrom:将string类型转换为xxxx。
CanConvertTo:将string类型转换为xxxx。
ConvertFrom:根据传入的string创建并返回xxxx对象实例。
ConvertTo:根据接收xxx参数,转换为string。