一切福田,不離方寸,從心而覓,感無不通。

Category Archives: Programming Language

Asp.net控件开发学习笔记(十一)—-服务器控件模板

  在Asp.net 2.0以后的版本,Asp.net提供了服务器控件模板(Template)和数据绑定(Data Bind)来简化开发工作,模板是是用于定制化服务器控件或者HTML如何在页面呈现,而模板和数据绑定往往结合起来在一起实现更高级的功能,比如最经典的GridView.例如,在 GridView服务器控件中可以使用 HTML 元素和控件的组合来创建列表中每行的布局。同样,GridView服务器控件对网格中的每行都具有一个默认的外观。但是,您可以通过为单个行、间隔行、所选行等行定义不同的模板来自定义网格的外观。   定制控件内容 模板用于让开发人员自定义HTML或者服务器控件作为主要控件输出流的一部分。提供了模板的服务器控件其实是给予插入自定义内容提供了容器。 服务器控件模板的强大之处在于它通过让开发人员可以定制输出特定的html来给予了开发人员极高的灵活性.如下图: 使用服务器控件模板 使用服务器控件模板的一大好处是我们可以专注开发空间,而把外观等html和css设置内容让其他人来完成。 在GridView控件里,我们可以通过在ItemTemplate里设置任何我们想设置的内容,在DropDownList控件中我们可以插入ListItem子控件,但在里面插入比如TextBox控件则不行。这个原因就要说到下面一个标签(Attribute)   ParseChildren Attribute 服务器控件必须通过在类声明时添加ParseChildren标签来告诉asp.net页面分析器这个控件需要支持模板。ParseChildren的功能是让服务器控件所含有的子控件作为它的一个属性存在。 对于继承System.Web.UI.WebControls.WebControl基类的控件,这个标签已经通过继承而存在不需要再声明  ParseChildren标签还暴露了ChildrenAsProperties属性,在使用 可以:ParseChildrenAttribute(ChildrenAsProperties = true) 也可以用简便写法:ParseChildren(true) ChildrenAsProperty属性的作用是让控件的属性和直接在控件内部的html代码,或者说是XML代码(“<”和”>”)进行匹配.如下图: 而不使用ChildrenAsProperties属性的则会是如下图:     下面通过一个Demo来看 Demo 服务器导航菜单 先看Demo的效果 先声明两个用于存放子控件的容器,代码如下: publicclassBasicTemplateContainer : WebControl, INamingContainer     { public BasicTemplateContainer(): base(HtmlTextWriterTag.Div)         { this.BorderWidth = 1; this.BorderStyle = BorderStyle.Solid;         }     } publicclassSeperatorTemplateContainer : WebControl, INamingContainer     { public SeperatorTemplateContainer(): base(HtmlTextWriterTag.Span)         {         }  } 第一个用于存放HeaderTemplate和footerTemplate,而第二个用于存放分隔符 再声明一个存放菜单超链接的容器,代码如下:     [TypeConverter(typeof(ExpandableObjectConverter))] publicclassMenuItemData     { public MenuItemData()         {         }         [NotifyParentProperty(true)] publicstring Title { get; set; }         [NotifyParentProperty(true)] publicstring Url { get; set; }         [NotifyParentProperty(true)] publicstring ImageUrl { get; set; }         [NotifyParentProperty(true)] publicstring Target { get; set; }     } 最后声明一个继承于CompositeControl基类的控件,声明代码如下: publicclassTemplateMenu : CompositeControl 最终完全代码如下:     TemplateMenu完全代码  1using System;  2using System.Web;  3using System.Web.UI;  4using System.Web.UI.WebControls;  5using System.Collections;  6using System.ComponentModel;  7using System.Web.UI.WebControls;  8namespace bindcontrol  9{ 10    [ToolboxData("<{0}:templatemenu runat=server></{0}:templatemenu>")] 11publicclass TemplateMenu : CompositeControl 12    { 13private ArrayList menuData; 14public TemplateMenu(): base() 15        { 16        menuData =new ArrayList(){ 17 18new MenuItemData{Title="博客园", Url="http://www.cnblogs.com"}, 19new MenuItemData{Title="Microsoft", Url="http://www.microsoft.com"}, 20new MenuItemData{Title="ASP.Net", Url="http://asp.net"}}; 21        } 22private ITemplate headerTemplate; 23        [Browsable(false), Description("The header template"), 24        PersistenceMode(PersistenceMode.InnerProperty), 25        TemplateContainer(typeof(BasicTemplateContainer))] 26public ITemplate HeaderTemplate 27        { 28get 29            { 30return headerTemplate; 31            } 32set 33            { 34                headerTemplate = value; 35            } 36        } 37private ITemplate footerTemplate; 38        [Browsable(false), Description("The footer template"), 39        PersistenceMode(PersistenceMode.InnerProperty), 40        TemplateContainer(typeof(BasicTemplateContainer))] 41public ITemplate FooterTemplate 42        { 43get 44            { 45return footerTemplate; 46            } 47set 48            { 49                footerTemplate = value; 50            } 51        } 52private ITemplate separatorTemplate; 53        [Browsable(false), Description("The separator template"), 54        PersistenceMode(PersistenceMode.InnerProperty), 55        TemplateContainer(typeof(SeperatorTemplateContainer))] 56public ITemplate SeparatorTemplate 57        { 58get 59            { 60return separatorTemplate; 61            } 62set 63            { 64                separatorTemplate = value; 65            } 66        } 67privatevoid CreateControlHierarchy() 68        { 69if (HeaderTemplate !=null) 70            { 71                BasicTemplateContainer header =new BasicTemplateContainer(); 72                HeaderTemplate.InstantiateIn(header); 73                Controls.Add(header); 74            } 75int count = menuData.Count; 76for (int index =0; index < count; index++) 77            { 78                MenuItemData itemdata = (MenuItemData)menuData[index]; 79                HyperLink link =new HyperLink() 80                { 81                    Text = itemdata.Title, 82                    NavigateUrl = itemdata.Url, 83                    ImageUrl = itemdata.ImageUrl, 84                    Target = itemdata.Target 85                }; 86                Controls.Add(link); 87if (index != count –1) 88                { 89if (SeparatorTemplate !=null) 90                    { 91                        SeperatorTemplateContainer separator =new SeperatorTemplateContainer(); 92                        SeparatorTemplate.InstantiateIn(separator); 93                        Controls.Add(separator); 94                    } 95else 96                    { 97                        Controls.Add(new LiteralControl(" | ")); 98                    } 99                }100            }101if (FooterTemplate !=null)102            {103                BasicTemplateContainer footer =new BasicTemplateContainer();104                FooterTemplate.InstantiateIn(footer);105                Controls.Add(footer);106            }107        }108overrideprotectedvoid CreateChildControls()109        {110            Controls.Clear();111            CreateControlHierarchy();112        }113publicoverride ControlCollection Controls114        {115get116            {117                EnsureChildControls();118returnbase.Controls;119            }120        }121    }122123publicclass BasicTemplateContainer : WebControl, INamingContainer124    {125public BasicTemplateContainer(): base(HtmlTextWriterTag.Div)126        {127this.BorderWidth =1;128this.BorderStyle = BorderStyle.Solid;129        }130    }131publicclass SeperatorTemplateContainer : WebControl, INamingContainer132    {133public SeperatorTemplateContainer(): base(HtmlTextWriterTag.Span)134        {135        }136    }137    [TypeConverter(typeof(ExpandableObjectConverter))]138publicclass MenuItemData139    {140public MenuItemData()141        {142        }143        [NotifyParentProperty(true)]144publicstring Title { get; set; }145        [NotifyParentProperty(true)]146publicstring Url { get; set; }147        [NotifyParentProperty(true)]148publicstring ImageUrl { get; set; }149        [NotifyParentProperty(true)]150publicstring Target { get; set; }151    }152} 前台调用代码如下: 首先注册控件:<%@Register Namespace="bindcontrol"TagPrefix="dd"%> 然后是前台代码: <dd:TemplateMenurunat="server"> <HeaderTemplate>template header</HeaderTemplate> <SeparatorTemplate>%</SeparatorTemplate> <FooterTemplate>template footer</FooterTemplate> </dd:TemplateMenu> 注意,作为模板的类型必须声明成ITemplate类型,而这个ITemplate的具体类型则通过TemplateContainer标签进行注入.我们通过声明CreateControlHierarchy()函数来进行控制控件的具体输出,最后通过覆盖父类的CreateChildControls()方法来调用我们写好的CreateControlHierarchy方法达到控制输出的目的。   最后,你可能有疑问,那个神奇的ChildrenAsProperties属性跑哪去了?如果没有这个属性,那上面<headerTemplate>之类的标签又是如何匹配的呢?还记得吗,继承与WebControl基类的控件继承了这个标签,所以不用显示声明,所以ChildrenAsProperties属性come for free:-) http://www.cnblogs.com/CareySon/archive/2009/10/19/1586146.html

龙生   08 Apr 2013
View Details

Asp.net控件开发学习笔记(十)—-服务器控件生命周期

  在每一次http的Request和Response周期asp.net web form都会执行一系列被称为控件生命周期的预定义过程     在第一次通过HTTP Get方法获取到页面后,每一次向服务端进行HTTP POST回传都会分为以下几个步骤: 1.初始化控件树 2.将回传的ViewState进行解析 3.根据前几次的回传解析来为控件树中的每一个控件设置状态 4.处理回传数据 5.处理Page_Load事件 6.通过PostBack通知控件的数据变化,并在必要的情况下更新控件状态 7.执行基于控件状态改变的服务端事件(比如button的点击) 8.将控件状态持久化为ViewState 9.按照次序Render控件树中的每一个控件 10. Dispose整个页面和控件树 由上面的列表可以看出整个的用户Request和服务器Response的周期,首先是将状态解析并根据控件的状态来处理状态的改变,最后处理完后将这些Render回客户端,并将新的状态以ViewState的形式保存在客户端的hidden form中。     页面生命周期对应事件 在页面生命周期中,上面所说的每一个步骤都有一个对应的事件。这也就意味着你可以通过Override事件的执行方法来在页面周期中插入你自己的实现 服务端事件 页面生命周期 描述 Init Initialization 初始化控件树 LoadViewState Unpack ViewState 从ViewState里提取出状态信息 LoadControlState Unpack control state 从控件状态中提取出状态信息 LoadPostData Handle form postback 从PostBack信息中更新控件状态信息 Load Page_Load event 执行Page_Load内的事件 TrackViewState Track ViewState   RaisePostDataChangedEvent Initialization for server-side events 通知控件回传的状态将改变其值 RaisePostBackEvent Execute server-side events 对于指定的控件,如果状态信息改变,则引发该事件 PreRender Render process 让每个空间接收最新的状态信息 SaveViewState Save ViewState 保存ViewState SaveControlState Save control state   Render Render process Render标准HTML,Render的HTML带有控件的状态信息 Dispose Dispose of control tree 释放资源   服务器生命周期和HTTP GET以及HTTP POST 在System.Web.UI.Control基类定义了OnInit, OnLoad, OnPreRender, OnUnload,这四个事件可以被重写。而对于Dispose事件虽然Control也有定义,但并没有相应的OnDispose方法来引发事件,如果需要Dispose事件,需要实现IDispose接口。 在通常情况下,第一次访问aspx页面时通过HTTP GET方法,而第二次以后都会通过HTTP POST方法,而HTTP POST方式进行访问服务器时,所需要经历的过程要比GET方式多,因为它包含了数据回传处理,下面是示意图: 下面通过一个小Demo来查看控件的生命周期: Demo Post回传生命周期 首先先写一个控件,对每个控件的上述事件进行覆盖,最后通过在页面Trace来查看 首先是控件的代码: using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.UI;   namespace Life {     [ToolboxData("<{0}:lifecycle runat=server></{0}:lifecycle>")] publicclassLifecycle : Control, IPostBackEventHandler, IPostBackDataHandler     { protectedoverridevoid OnInit(System.EventArgs e)         {             Trace("Lifecycle: Init Event."); base.OnInit(e);  } protectedoverridevoid TrackViewState()         {             Trace("Lifecycle: Track ViewState."); […]

龙生   08 Apr 2013
View Details

Asp.net控件开发学习笔记(九)—-服务器控件事件

  EventCollection 如果在单个控件中有多个事件,那么使用System.ComponentModel.EventHandlerList对事件进行保存将会在内存占用上有不错的提高。EventHandlerList对一个类内发布多个事件提供了一个列表容器。下面是多个事件和使用EventHandlerList的对比示意: 第一步是实例化一个EventHandlerList的实例: protected EventHandlerList eventList = new EventHandlerList(); 第二步是声明一个容器用于保存事件的key privatestaticreadonlyobject ClickEvent = newobject(); 最后一步是像往常一样声明一个事件,但有所不同的是就像属性的get和set程序块一样,对于事件C#提供了add和remove关键字: publiceventEventHandler Click         { add             {                 Events.AddHandler(ClickEvent, value);             } remove             {                 Events.RemoveHandler(ClickEvent, value);             }       } 而在这时的事件调用方法就会像下面代码: protectedvirtualvoid OnClick(EventArgs e)         { EventHandler clickEventDelegate = (EventHandler)Events[ClickEvent]; if (clickEventDelegate != null) {                 clickEventDelegate(this, e);             }      } 上面代码首先从事件列表中通过索引器以第一步中保存事件的key为参数提取出事件并检查客户端是否注册到此事件,如果是,则激发事件。   Command事件和事件冒泡 Command事件是System.Web.UI.WebControls命名空间里的强大模式。这个最好的例子是GridView 在GridView的Row里嵌套的button点击会触发Command事件,后台可以根据CommandArgument的不同来决定是执行edit操作还是delete操作等。而事件冒泡有些像javascript里的事件冒泡,但有所不同的是这里的事件冒泡到能够处理这个事件的地方停止,比如上图中command事件会冒泡到DataGrid里的ItemCommand里停止,因为ItemCommand事件可以对command事件进行处理. 在定义Command事件时会和前面大同小异,不同之处在于首先需要一个继承与System.EventArgs的CommandEventArgs类来进行参数传递,代码如下 publicclassCommandEventArgs : EventArgs { public CommandEventArgs(string _commandName,string _commandArgument) {     CommandName=_commandName;     CommandArgument=_commandArgument; }  privatestring commandname; privatestring commandArgument; publicvirtualstring CommandName         { get             { return commandname;             } set             {                 commandname = value;             }         } publicvirtualstring CommandArgument         { get             { return commandArgument;             } set             {                 commandArgument = value;             }         } } 然后在需要定义的控件里定义这两个属性,代码如下: publicvirtualstring CommandName          { get             { object name = ViewState["CommandName"]; if (name == null) returnstring.Empty; else return (string)name;             } set             {                 ViewState["CommandName"] = value;             }         } publicvirtualstring CommandArgument         { get             { object arg = ViewState["CommandArgument"]; if (arg == null) […]

龙生   08 Apr 2013
View Details

Asp.net控件开发学习笔记(八)—-服务器控件事件

  事件和委托之间的暧昧关系往往是大多Web Developer在学习.net中的一个里程碑,当明白事件和委托的关系后,.net水平往往就上了一个新的台阶.下面说到服务器控件的事件模型. 在任何一个服务器编程开发框架中,事件都是解耦功能和具体实现的一剂良方,Asp.net当然也不例外。比如说吧,页面上的button的click事件表示它的功能,而具体的实现将会被分离交给Developer来进行具体实现。 传统的编程模型和基于事件的编程模型可以用下图进行简约概括: 我们可以看出事件极大的简化了编程工作,客户端程序只需要注册到事件并且和事件的签名保持一致(即参数个数和类型相同)即可。在事件发生后,客户端程序会被通知并执行相应实现(.net framework的事件正是观察者模式的最好例子:-))   Asp.net通过ViewState和Http Post协议巧妙的实现了让开发人员感觉貌似控件能像WinForm程序中那样记住自己的状态。这使Asp.net可以在不使用客户端javascript的情况下,而实现数据回传。       上面的图例展示出TextBox通过暴露相应的事件来通知被注册的函数.还记得前面所说的IPostDataHandler接口嘛,大多数服务器控件的事件都是通过ViewState来将数据以Http Post协议传回服务器,服务器根据回传数据的不同来引发相应事件。因此我们可以看出Button控件生成的<input type=”submit” />是有往服务器提交的功能的,而其他控件比如DropDownList或者是Checkbox是没有像服务器提交的功能。因此引发服务器事件便无从谈起。Asp.net通过在客户端设置javascript事件来引发向服务器的Http Post回传。而这一切仅仅需要将AutoPostBack属性设置为true.     .net FrameWork 事件模型 .net framework提供了基于委托的使不同类之间进行异步交互的机制。下面先简单说一下事件的核心——-委托   Delegate 委托在一定程度上有点像接口,是在发布者和订阅者之间的一个协议。接口是制订类的数据成员以及成员函数的签名。而委托,是制订单个函数的签名. 创建一个委托的实例是通过创建一个和委托相匹配的函数。 MSDN里把委托比喻成类型安全的函数指针。但是委托不仅限于此,因为.net framework大大的扩展了这个“类型安全的指针”,在CLR via C#这本书里说委托的实质上是一个类。因此委托可以按照次序依次调用多个匹配的方法,无论是静态方法还是实例方法。 委托有两个部分,委托的声明和委托实例的声明。 委托的声明代码会像: publicdelegatevoidfoo(string A); 而委托实例的声明会像 foo f=new foo(MethodName)   下面通过一个简单的Demo说明一下:   Demo 委托 先写一个简单的类: publicclassDelegateDemo     { publicdelegatevoidDeleDemo(string a); publicstaticvoid FunctionA(string a)         { HttpContext.Current.Response.Write("静态方法,传入的参数是:" + a + "<br />");         } publicvoid FunctionB(string a)         { HttpContext.Current.Response.Write("实例方法,传入的参数是:" + a + "<br />");         } } 下面是客户端代码: DelegateDemo dd = newDelegateDemo(); DelegateDemo.DeleDemo d = newDelegateDemo.DeleDemo(dd.FunctionB);         d += DelegateDemo.FunctionA;     d("参数");   最后的输出结果为: 实例方法,传入的参数是:参数静态方法,传入的参数是:参数   通过上面小Demo可以发现委托不仅仅是“类型安全的指针”,并且委托是按照次序调用实例方法和静态方法.   事件 C#里有专门用于声明事件的event关键字,一个典型的事件生命会像: publiceventEventHandler click;   事件关键字后面是委托,再后面是事件名称,命名事件的名称最好是动词,表名某些事情发生了。比如click,Init,Load,TextChanged这样。由此可以看出事件其实就是特殊的委托。因为所有的事件都是继承于System.EventHandler.   EventHandler 委托 所有asp.net内置控件事件处理函数的签名都和EventHandler或者继承于它的子类保持一致。它的原型是: [SerializableAttribute] [ComVisibleAttribute(true)] publicdelegatevoidEventHandler( Object sender, EventArgs e )   第一个参数表示引发事件的对象,第二个参数表示引发事件后所要传给处理程序的参数。   在一般情况下,开发人员最好是按照这种签名格式来声明函数事件的委托.   在控件内部声明事件后,你必须在需要的情况下引发事件,直接引发事件是非常不好的做法。而在asp.net预定义的控件中都使用了如下方法: 声明一个virtual protected void的方法,命名方式为On+事件名称.下面是一个例子: protectedvirtualvoid OnClick(EventArgs e)         { if (Click != null)                 Click(this, e);        } 这个方法首先做的是先检查客户端方法是否注册,如果有客户端方法进行了注册,则引发事件。 http://www.cnblogs.com/CareySon/archive/2009/10/12/1581792.html

龙生   08 Apr 2013
View Details

Asp.net控件开发学习笔记(七)—-WebControl基类

  WebControl基类 在Asp.net控件开发中,WebControl基类给我们提供了对于控件的Style更加灵活的解决方案,因为在System.Web.UI.Control基类中只能手动的输入呈现在客户端的代码,但如果开发的服务器控件对style的要求较高。那Control基类的局限性就显而易见了,而继承WebControl类作为基类将会是很好的选择。      System.web.UI.WebControls.Webcontrol直接继承与Control类。在继承了Control的特性的基础上,WebControl基类不仅在生成客户端html使用了另一种更好的render方式,并且还提供了对于老版本浏览器的兼容。   WebControl的ControlStyle属性    ControlStyle属性其实是System.Web.UI.WebControls.Style的一个实例,这个属性用于读取或者设置常用的CSS类,以下是System.Web.UI.WebControls.Style的属性和CSS属性的对应关系。 Style的属性 CSS标准属性 BackColor background-color BorderColor border-color BorderStyle border-style BorderWidth border-width CssClass CSS的类名 Font Font weight, style, family, and so on ForeColor color Height height width width   而在ControlStyle.Font是一些设置字体的属性,是System.Web.UI.FontInfo对象的实例。和标准CSS属性的对照如下表:   Font 属性 CSS标准属性 Bold font-weight: bold Italic font-style: italic Name font-family Names font-family Overline text-decoration: overline Underline text-decoration: underline Size font-size Strikeout text-decoration: line-through   WebControl基类ControlStyle属性的简化 下面这行代码: webcontrol.ControlStyle.BorderWidth = 1; 和      webcontrol.BorderWidth = 1; 代码是等价的,WebControl基类可以不通过ControlStyle属性而访问ControlStyle内的成员,这样在前台可以直接对控件进行style设置,刚才的后台代码于如下前台代码是等价的: <cc:WebControlid="WebControl"runat="server"borderwidth="1"/>   WebControl的Style属性 因为ControlStyle属性只暴露了一部分可用于操控CSS的属性,而除了上述ControlStyle暴露的基本的CSS属性设置之外,WebControl基类还为我们提供了Style属性用于对CSS进行精确完整的操作,可以用如下图让概念更加清晰:     Style属性是System.Web.UI.CssStyleCollection这个类的实例,style属性大多在.aspx文件中用到,比如: <asp:ButtonID="Button1"runat="server"Text="Button"style="background:blue;"/> 而与上面对Style赋值等价的后台代码则是: Button1.Style["background"] = "blue"; 或者 Button1.Style.Add("background", "blue");   一个新的Render系统 和集成Control并重写Render方法不同,WebControl给我们提供了一个新的系统用于Render控件。下面写一个Label的Demo:   Demo:label控件 代码如下:     [ToolboxData("<{0}:label runat=server></{0}:label>"),DefaultProperty("Text")] publicclassLabel : WebControl     { public Label(): base(HtmlTextWriterTag.Span)         {         } publicvirtualstring Text         { get             { object text = ViewState["Text"]; if (text == null) returnstring.Empty; […]

龙生   08 Apr 2013
View Details

Asp.net控件开发学习笔记(六)—-数据回传

  在Asp.net中,利用Http Post的回传机制意味着可以再客户端存储状态并且可以在服务器接收.Asp.net中大部分控件都提供了存储自身状态的功能并且在自身状态改变时引发对应事件。IPostDataHandler接口提供了在服务器处理客户端通过Http Post回传数据的方法。   IPostDataHandler 通过实现IPostDataHandler接口,服务器可以在不使用Page和Request对象的情况下来读取客户端回传数据。IPostDataHandler还提供了在用户状态改变的情况下来引发相应事件的框架。IPostDataHandler的定义如下: publicinterfaceIPostBackDataHandler     { publicbool LoadPostData(string postDataKey,         NameValueCollection postCollection); publicvoid RaisePostDataChangedEvent(); }   对于LoadPostData函数,如果返回值为true,则会引发下面的RaisePostDataChangeEvent方法。这个方法中我们可以加入需要引发的事件,比如: publicvirtualvoid RaisePostDataChangeEvent()     {         OnTextChanged(EventArgs.Empty); } 这个方法有两个参数,先说第二个参数,第二个参数返回键值对,key(键)是控件的unique id,这个id是通过客户端的id来决定的,大多数情况下,这两个id相等,比如客户端的<input id=”xx” runat=”server” />则在服务端的unique id也会是”xx”,但是如果控件放在gridview或者masterpage里的话,uniqueid会是母控件的uniqueid+分隔符+子控件的uniqueid.而value(值)则是对应控件的回传数据。比如下图: 在页面只有两个控件,TextBox控件和Button控件,前两个是asp.net内置的ViewState和验证。而第三个是id名为”cc”的TextBox,第四个是id为Button1的button.则可以看出postCollection参数其实是页面所有实现了IPostBackDataHandler接口的回传数据,而第一个参数postDataKey则是这个方法所属控件的uniqueid. 所以可以这样来获得本控件这一次的回传数据: postCollection[postDataKey] 当然也可以获得其他控件这一次的回传数据以达到和其它控件的交互,比如: postCollection[3]   下面通过一个Demo来展示IPostDataHandler   DEMO1  自己写一个拥有状态的TextBox控件 通过这个Demo可以更清楚的让我们明白ViewState和PostBack Data之间通过实现IPostDataHandler的交互。 代码如下: [ToolboxData("<{0}:textboxDemo runat=server></{0}:textboxDemo>")] publicclassTextboxDemo : Control, IPostBackDataHandler     { string _text; publicvirtualstring Text         { get             { object text = ViewState["Text"]; if (text == null) returnstring.Empty; else return (string)text;             } set             {                 ViewState["Text"] = value;             }         } publicbool LoadPostData(string postDataKey,NameValueCollection postCollection)         {             Text = postCollection[postDataKey]; returnfalse;         } publicvirtualvoid RaisePostDataChangedEvent()         {         } overrideprotectedvoid Render(HtmlTextWriter writer)         {             Page.VerifyRenderingInServerForm(this); base.Render(writer); //输出 <INPUT type="text">标签             writer.Write("<INPUT type=""text"" name=""");             writer.Write(this.UniqueID);             writer.Write(""" value=""" + this.Text + """ />");         } } 这是一个简单的TextBox实现。通过实现IPostBackDataHandler接口,我们可以在每次回传到服务器后保存TextBox的状态.即TextBox的Value的值. 注意在Render方法里有:Page.VerifyRenderingInServerForm(this);,这行代码表示此控件必须在<form>标签内,如果不在此标签内,则会报错.所有需要实现数据回传的控件最好都要使用这个方法. TextBoxDemo控件的使用方法这里就不再累述了。   ASP.net控件状态 在asp.net 2.0以后的版本。可以通过设置控件的EnableViewState属性来控制单个控件是否保存其状态。在一些访问量比较大的网站上,如果不注意关闭不需要的ViewState,则用户在每回提交时都会导致传送额外的ViewState字符串,这回导致性能问题. 控件的状态还有一个很棒的特性是在即使ViewState被禁用的情况下,控件的状态保持依然可用. http://www.cnblogs.com/CareySon/archive/2009/10/09/1579781.html

龙生   08 Apr 2013
View Details

Asp.net控件开发学习笔记(五)—Asp.net客户端状态管理

  Asp.net提供了很多种与客户端状态交互的方式,控件开发人员可以给控件添加额外的值(比如控件的ViewState)来使控件貌似能记住前一个值.Asp.net提供了四种客户端状态管理的方式。他们是: l ViewState l URL strings l Hidden Html Variables l Cookies   URL String 利用URL传值请求服务器是简单并且应用最广泛的。比如在电子商务中,一个像这样的地址: http://xxx.com/product.aspx?categoryid=1&productid=1 表示传入两个键值对。 在服务器接收对应值时可以用Request对象的QueryString属性和Params属性来进行访问,也可以利用Request本身的索引器来访问,比如Request[“category”]。 注意:QueryString属性只能访问以GET方式传的值.   Cookies Cookies是一个通过在Http协议中添加额外的信息让服务器和客户端共同实现在用户的机器上存储一定量的信息.Cookies里存放的信息针对特定站点,并且有时间限制。这意味着Cookies在一个站点存放的信息只能这个站点读取,而不能在其他站点被读取。    Cookies的信息是通过Http头里发送Set-Cookies然后加上服务器想在客户端存储的信息. 在Asp.net中对Cookies的操作是通过HttpResponse类的Cookies属性. 给客户端的Cookies赋值的代码如下: Response.Cookies["LastVisit"].Value = DateTime.Now.ToShortDateString();          Response.Cookies["LastVisit"].Expires = DateTime.Now.AddDays(1); 这两行代码会在Http头中传送到客户端服务器,HTTP会如下:        Set-Cookie: LastVisit=mm/dd/yy; path=/ 当在对此代码进行读取时,只需要利用Request对象中的Cookies属性,代码如下 string firstname = Request.Cookies["LastVisit"].Value;   在Cookies中,不要存储大量信息.在控件开发的过程中,尽量不要使用Cookies,因为Cookies可能被客户端浏览器禁用.   HTML Hidden variables Html hidden variable也是被经常使用的客户端状态存储方式,在这种方式相对于前两种方式的优势在于,这种方式没有传送字节的大小限制,并且不用怕客户端浏览器不支持(啥?难道有不支持HTML的浏览器???) 利用Http Post方法,可以将客户端的Hidden variable回传到服务器.Asp.net通过System.Web.UI.HtmlControls.HtmlInputForm服务器控件,这个控件会在页面中产生如下代码: <formid="first"method="post"runat="server"> 而当render到客户端时,会产生如下代码 <formid="first"method="post"action=”first.aspx”> 注意,first.aspx就是指向页面本身   再来看一个完全点的例子: <formid="first"method="post"runat="server"> <inputtype="text"value="CareySon"id="name"/> <inputtype="text"value="Write Code"id="Task"/> </form>   当上面的form被提交时,或者利用javascript来提交时,asp.net会将当前所有的input格式化成字符串以便服务端进行提取.上面的代码格式化成字符串时会变成: Name=CareySon&Task==Write Code 而在服务器端进行读取时,可以使用Request对象的Form属性索引器或者Params属性索引器: string name = Request.Form["name"]; string task = Request.Params["task"];   Asp.net的回传机制也可以用下图表示: 剑是双刃的,当然Hidden Form也并不是只有好处。比如Hidden Form的值虽然不显示在网页中,但是依然可以被用户查看,所以不要在Hidden Form里存放敏感信息,否则必须的进行字符串加密.还有当Hidden Form中存放的值过大时,会有一些潜在的性能问题.因为每次进行Post提交的时都会将所有的Hidden Form提交的服务器L 当然,虽然有一些缺点,但Hidden Form还是在控件开发中储存状态信息的比较好的方式.   ViewState  ViewState的本质其实就是在Hidden Form上抽象出一层,换句话说,ViewState的存储原理其实就是利用了Hidden Form.ViewState。克服了Hidden Form一些硬性弱点,比如ViewState会对Hidden Form里的值进行压缩,编码使减少传输的大小并使客户端无法查看Hidden Form里的值。在本质上ViewState就是如下一个Hidden Form: <input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value=" " /> ViewState还有一个比较有用的作用是用于存储控件状态.即存储与控件有关的数据.ViewState是System.Web.UI.StateBag类的实例,而StateBag实现了很多的接口,如下: 接口 描述 ICollection Defines enumerators, synchronization methods, and size for collections IDictionary Specialized collection interface that implements a collection of name/value pairs IEnumerable Provides the enumerator for iteration over a collection IStateManager Defines the properties and methods required to support ViewState management in server controls 其中最有趣的是IStateManager接口.StateManager实现了这个接口用于存储和载入控件的ViewState. .net Framework利用ISateManager对控件的ViewState在被序列化并存入名称为_viewstate的Hidden Form中之前进行精简. 在ViewState的状态信息中存储着以键/值对方式存储的控件信息,(包括当前页面,因为System.Web.UI.Page也是继承于System.Web.UI.Control的)。在页面执行过程中.ViewState会被Hash运算和压缩.最终存入名称为_ViewState的Hidden Form中。此外,ViewState能够防止修改,任何在Asp.net页面处理周期之外对ViewState的修改都会被Asp.net发现并且做出处理。   简单的使用 ViewState听起来很复杂,但是使用起来却非常简单.对ViewState赋值的时候只需要: ViewState["Task"] = "Write Code"; 上面的代码在客户端生成的时候会生成如下代码: <inputtype="hidden"name="__VIEWSTATE"id="__VIEWSTATE"value="/wEPDwULLTE2MTY2ODcyhc2spkL8ufmlbb5xWbI/"/>   对ViewState的读取也是类似的方法.代码如下: string task = ViewState["Task"].ToString();   页面中的ViewState在很多时候会很庞大,这大大加重了服务器负担。所以开发人员需要将不需要ViewState的控件的EnableViewState设置成false,这个属性时System.Web.UI.Control的,这意味着所有的控件都具有这个属性. http://www.cnblogs.com/CareySon/archive/2009/10/04/1577948.html

龙生   08 Apr 2013
View Details

Asp.net控件开发学习笔记(四)—Asp.net服务端状态管理

  Asp.net请求处理构架   当一个客户端浏览器对IIS发起访问请求资源时(比如一个.aspx文件),Asp.net会初始化并维护一个包含了多个Response和Request的Http Session 的客户端的连接。一次典型的访问如下图:    上图中,首先,一个请求发到IIS服务器,IIS会检查请求的扩展名,如果是aspx或者ascx文件,IIS会自动匹配到aspnet_isapi.dll来处理这个请求,如果是其他扩展名的文件,IIS会自动匹配到对应ISAPI文件来处理请求。 请求的过程会执行HttpRuntime对象,而HttpRuntiem会利用HttpApplicationFactory对象来确认当前的AppDomain并创建HttpApplication对象来处理请求。Global.asax处理的事件就是基于HttpApplication对象存在的事件。在当前Application中,当前用户的用户信息会通过HttpApplication对象的Context进行访问.接下来执行过程到了HttpModule,任何执行HttpModule的类在这时都会在程序中注册并引发他们的事件。比如Global.asax中的全局事件Session_Start和Session_End事件其实就是SessionStateModule,它实现了HttpModule.所以HttpModule的作用是实行全局的功能. 当HttpModule执行完成后,会到HttpHandler这一块,不同的请求会调用不同的HttpHandler,HttpHandler的执行方法是调用其内部的ProcessRequest()方法,ProcessRequest()方法只有一个参数,参数类型为保存了当前用户状态的HttpContext对象。然后,HttpHandler会负责利用Context.Response.Write()方法来响应当前的请求. 上面的整个处理过程都是利用了Asp.net的对对象,这些对象的关系可以简单用下图表示:     HttpHandler HttpHandler是Asp.net的处理.aspx和.asmx的构架和方法.HttpHandler允许用户在应用程序处理单个的Url或者相同的扩展名.Asp.net里面有两个Build-in的HttpHandler,如下: Handler 描述 Asp.net Web Service 默认用于处理.asmx的HttpHandler Asp.net 页面 默认用于处理.aspx的HttpHandler   注意,上面的描述中用了默认,这意味这我们也可以写自己的处理.asmx或.aspx的HttpHandler实现      Asp.net的PageHandlerFactory是用来专门为创建用于被Developer操作的Page实例的,在这个实例中会包含我们常用的用户信息,比如Session,Application,ViewState等……. 通常情况下,HttpHandler可以是异步的,也可以使同步的。 同步的过程是指处理完整个Http请求才返回数据,而异步指处理完请求立刻返回数据.   Asp.net和服务端状态管理 Asp.net服务端状态管理是由我们最熟悉的Application和Session对象组成的,它们以集合的方式将用户信息储存在服务器. Application是面向全局的,而Session对象是针对特定用户的.这两个对象都可以通过HttpContext对象来进行访问。   HttpContext对象 HttpContext提供了服务端状态管理并实现了HttpApplicationState和HttpSessionState,下面是一些HttpContext对象的属性:     AllErrors Gets an array of errors accumulated while processing an HTTP request.   Application Gets the HttpApplicationState object for the current HTTP request.   ApplicationInstance Gets or sets the HttpApplication object for the current HTTP request.   Cache Gets the Cache object for the current application domain.   Current Gets or sets the HttpContext object for the current HTTP request.   Error Gets the first error (if any) accumulated during HTTP request processing.   Handler Gets or sets the IHttpHandler object responsible for processing the HTTP request.   Items Gets a key/value collection that can be used to organize and share data between an IHttpModule interface and an IHttpHandler interface during an HTTP request.   PreviousHandler Gets the IHttpHandler object for the parent handler.   Profile Gets the ProfileBase object for the current user profile.   服务端状态管理总结 通常情况下,在开发服务器控件时,尽量少用服务端的状态管理,尤其是在能够使用客户端状态管理时,就不要用服务端状态管理。但在一些情况下,客户端浏览器被限制,比如cookies被禁止,这时使用服务端状态管理还是比较方便的J http://www.cnblogs.com/CareySon/archive/2009/10/03/1577745.html

龙生   08 Apr 2013
View Details

Asp.net控件开发学习笔记(三)-控件开发基础

 封装 在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>")] publicclassMenuCustomControl : Control     { protectedoverridevoid 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>");         } privatevoid 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,控件完成了.使用方法很简单,只需要在页面头部添加如下代码引入控件即可: <%@RegisterTagPrefix="sc"Namespace="SimpleControl"%> 在使用时就像使用用户控件一样,在页面注册完成后,系统会自动搜索命名空间内的直接或间接继承于Control基类的控件,在前台使用时,会自动出现智能提示: 代码如下: <sc:MenuCustomControlrunat="server"></sc:MenuCustomControl> 页面执行,效果如下:           Demo2:继承现有控件   在很多情况下,我们并不需要重新发明轮子,我们可以通过继承来利用现有控件的特性并额外添加我们需要的功能达到复用的目的.先看一下效果:    通过继承TextBox控件,并添加额外的Enable3d属性,使现有控件拥有额外的属性。前台代码摘录如下: 我是3D的:<sc:TextBox3drunat="server"></sc:TextBox3d><br/> 我不是:<sc:TextBox3drunat="server"Enable3D="false"></sc:TextBox3d>   后台代码如下: [ToolboxData("<{0}:textbox3d runat=server></{0}:textbox3d>")] publicclassTextBox3d : TextBox// 继承自TextBox     { public TextBox3d()         {         Enable3D = true;         } publicbool Enable3D         { get             { object enable3D = ViewState["Enable3D"]; if (enable3D == null) returnfalse; else […]

龙生   08 Apr 2013
View Details

Asp.net控件开发学习笔记(二)-控件开发基础

  接上篇……..   通过查看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 <inputtype="text"id="XTextBox"runat="server"/><br/> <br/> Y <inputtype="text"id="YTextBox"runat="server"/><br/> <br/> <inputtype="submit"id="BuildTableButton"runat="server" value="Build Table"onserverclick="BuildTableButton_ServerClick"/><br/> <br/> <spanid="Span1"runat="server"></span> </div> 后台代码如下: protectedvoid BuildTableButton_ServerClick(object sender, EventArgs e)     { int xDim = Convert.ToInt32(XTextBox.Value); int yDim = Convert.ToInt32(YTextBox.Value);         BuildTable(xDim, yDim);     } privatevoid BuildTable(int xDim, int yDim)     { HtmlTable table; HtmlTableRow row; HtmlTableCell cell; HtmlGenericControl content;         table = newHtmlTable();         table.Border = 1; for (int y = 0; y < yDim; y++)         {             row = newHtmlTableRow(); for (int x = 0; x < xDim; x++)             {                 cell = newHtmlTableCell();                 cell.Style.Add("font", "18pt");                 cell.Style.Add("background-color", "blue");                 cell.Style.Add("color", "red"); […]

龙生   08 Apr 2013
View Details
1 153 154 155 175