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

Category Archives: Asp.net

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

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

  服务器控件开发基础 当开发一个服务器控件时,首先要明白其内部的工作机理。其实在页面内部每一点由asp.net返回的HTML代码无论是简单的<span>标签,或者是button按钮,或者是复杂的gridview控件,都是由继承自System.Web.UI.Control的对象生成的。   控件的属性 控制控件的方法大多是通过控件的属性来操作的,通过控制服务器控件的属性,就可以相应的改变服务器生成的html. 下面是一个服务器控件的属性:    在Visual Studio里,当通过属性窗口来改变控件的属性时,VS会自动将属性添加到对应的aspx的HTML里,而在html内添加属性时,在属性窗口里也会对应显示更改过的属性视图比如: <asp:ButtonID="Button1"runat="server"Text="Button"CommandName="cName"/> 在属性窗口里会对应显示,如下图:        当然某些控件的属性会略有不同,比如常用的Label控件: <asp:LabelID="Label1"runat="server">这里是Text属性</asp:Label> 在开始符号和结束符号之间的内容会被设置成Text属性.   当然,最实用也是我们最常用的是通过C#以编程的方式动态的修改控件的属性.这就不说了.   控件的方法 控件通过方法来操作更加复杂的控件操作,通常在控件的方法内部会有很复杂的过程,一般包括几个内部函数和属性的组合.比如: privatevoid 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命名空间如图:       未完待续……… http://www.cnblogs.com/CareySon/archive/2009/09/30/1576984.html

龙生   08 Apr 2013
View Details

ASP.NET服务器控件开发(5)--添加客户端功能

  随着Ajax等技术的发展,客户端功能也逐渐变得越来越重要。如果在服务器控件中添加客户端功能,将会创作出功能更强大,界面更丰富的服务器控件。 客户端功能: 在Web编程中,客户端功能传统上是由Web页开发人员负责,并且不被封装在服务器组件中。ASP.NET脱离了这一范畴并使服务器控件能够发出客户端脚本,从而使服务器控件能够将客户端处理与服务器端处理结合起来。例如按钮控件的OnClientClick属性,就可以在其中声明一段脚本在客户端执行。 OnClientClick—>return confirm('Hello Word'),单击按钮时就会在客户端弹出一个提示框。 实现客户端功能的技术主要是客户端脚本(JavaScript、VBScript等)和DHTML。这个想必大家都知道。 ASP.NET服务器控件中客户端功能的实现: 下面我们进入正题,来看看ASP.NET服务器控件中是如何实现客户端功能的:代码如下: namespace ServerClientControl{    [DefaultProperty("Text")]    [ToolboxData("<{0}:SimpleButton runat=server></{0}:SimpleButton>")]publicclass SimpleButton :Button{protectedoverridevoid RenderContents(HtmlTextWriter output){        }protectedoverridevoid AddAttributesToRender(HtmlTextWriter writer){base.AddAttributesToRender(writer);            writer.AddAttribute("onclick", "window.confirm('Hello World! ');");        }    }} 我们创建一个继承自Button的类,通过AddAttributesToRender()方法添加一个onclick客户端事件。这样就简单的实现了向服务器控件添加客户端事件的功能。 ClientScriptManager 类 当然,这只是简单的方式。在 .NET Framework 2.0 版中为我们新增了ClientScriptManager 类。通过在网页的 HTML 标记中包含脚本,可以声明方式向网页添加客户端脚本。然而,有些情况下需要动态添加客户端脚本。 实现复杂客户端功能有关的几个常用方法:RegisterClientScriptBlock():向页的顶部添加一个脚本块。以字符串形式创建脚本,然后将其传递给方法,方法再将脚本添加到页中。可以使用此方法将任何脚本插入到页中。请注意,脚本可能在所有元素完成之前呈现到页中;因此,您可能无法从脚本中引用页上的所有元素。RegisterClientScriptInclude():与 RegisterClientScriptBlock 方法类似,但此方法将添加引用外部 .js 文件的脚本块。包含文件在任何其他动态添加的脚本之前添加;因此,您可能无法引用页上的某些元素。RegisterStartupScript():向页中添加一个脚本块,该脚本块在页完成加载后引发页的 onload 事件之前执行。该脚本通常不创建为事件处理程序或函数;它通常只包含要执行一次的语句。RegisterOnSubmitStatement():添加响应页的 onsubmit 事件而执行的脚本。该脚本在提交页之前执行,允许您取消提交。IsStartupScriptRegistered():确定Page对象是否注册了启动脚本。  IsClientScriptBlockRegistered():确定Page对象是否注册了客户端脚本。 更详细的说明讲解大家可以参看MSDN。 这里还要提下OnPreRender 方法。这个方法触发PreRender 事件。PreRender 事件在加载 Control 对象之后、呈现之前发生。可以理解为准备呈现的意思。在该事件的生存期内可以保存服务器控件视图状态的任何更改。不保存呈现阶段内所做的同样更改。开发人员可以再这个事件中添加脚本处理。 string JsPath ="js/";//重写OnPreRender方法protectedoverridevoid OnPreRender(EventArgs e){            Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "Ajax", "<script language='javascript' src='"+ JsPath +"Ajax.js"+"'></script>");//注册客户端脚本            Page.ClientScript.RegisterStartupScript(this.GetType(),"jQuery", "<script language='javascript' src='"+ JsPath +"jQuery.js"+"'></script>");//注册启动脚本base.OnPreRender(e);        } 这里简单的举个例子,Ajax.js中声明了要调用函数的名称,jQuery中对函数具体的实现。具体功能的代码就根据自己的需求实现啦!本人的js一般,这里就不做例子了。 IScriptControl 接口 IScriptControl接口:定义 ASP.NET 服务器控件为在启用 AJAX 的应用程序中定义JavaScript资源而必须实现的方法。创建将 ASP.NET 的 AJAX 功能用于浏览器中的扩展功能的自定义 Web 服务器控件。 当由类实现时,IScriptControl 接口的方法提供对脚本库的引用,这些脚本库定义客户端组件和表示客户端类型实例的脚本说明符。在将包含脚本控件功能的自定义服务器控件中实现此接口。这样,通过IScriptControl接口也能够实现ASP.NET服务器空间中添加客户端功能。 MSDN上有个通过IScriptControl向Web 服务器控件添加客户端功能的很好的例子。讲解的很详细。感兴趣的朋友可以参看: http://msdn.microsoft.com/zh-cn/asp.net/bb386450.aspx#Mtps_DropDownFilterText 小结:感冒了,就先写到这吧。通过向服务器控件中添加客户端功能,可以很好的增强控件的价值,提高用户客户端的体验。从中我们也不难看出,要想开发出一个好的服务器控件也是满不容易的,不但要对控件的生命周期,.NET提供的类库,接口有所了解,还要对js也要比较熟悉。所以从自定义服务器控件的开发过程中学习到很多知识。 转自:http://www.cnblogs.com/gaoweipeng/archive/2009/06/27/1512248.html

龙生   08 Apr 2013
View Details

ASP.NET服务器控件开发(4)--复合控件

  复合控件 概念:     所谓复合控件:简单的理解就是将多个基本的控件组合成一个控件,从而实现自己想要的效果。微软为ASP.NET2.0中推出的登录控件等就是一个复合控件。从功能的实现上,复合式控件有点像用户控件,只是一个是.ascx文件,一个是.dll文件。 呈现简单的复合控件: 要想呈现一个复合控件,需要了解以下几个方面: -->实现INamingContainer接口。 任何实现该接口的控件都创建一个新的命名空间,在这个新的命名空间中,所有子控件 ID 属性在整个应用程序内保证是唯一的。 -->Control.CreateChildControls 方法。 由 ASP.NET 页面框架调用,以通知使用基于合成的实现的服务器控件创建它们包含的任何子控件,以便为回发或呈现做准备。 当开发复合服务器控件或模板服务器控件时,必须重写此方法。重写 CreateChildControls 方法的控件应实现 INamingContainer 接口以避免命名冲突。    -->Control.ChildControlsCreated 属性。 获取一个值,该值指示是否已创建服务器控件的子控件。    -->Control.EnsureChildControls 方法。 确定服务器控件是否包含子控件。如果不包含,则创建子控件。    下面就通过实例来呈现个简单的复合登陆控件:创建ASP.NET服务器控件工程。complexControl。 先来看代码: namespace complexControl{    [DefaultProperty("Text")]    [ToolboxData("<{0}:LoginControl runat=server ButtonText='登录' NameLabel='用户名:' PasswordLabel='用户密码:'></{0}:LoginControl>")]publicclass LoginControl : WebControl, INamingContainer, IPostBackEventHandler{private Button _button;private TextBox _nameTextBox;private Label _nameLabel;private TextBox _passwordTextBox;private Label _passwordLabel;private RequiredFieldValidator _nameValidator;private RequiredFieldValidator _passwordValidator;        [Bindable(true),Category("Appearance"),DefaultValue(""),Description("按钮文本")]publicstring ButtonText{get{                EnsureChildControls();//确定服务器控件是否包含子控件return _button.Text;            }set{                EnsureChildControls();                _button.Text = value;            }        }        [Bindable(true),Category("Default"),DefaultValue(""),Description("姓名")]publicstring Name{get{                EnsureChildControls();return _nameTextBox.Text;            }set{                EnsureChildControls();                _nameTextBox.Text = value;            }        }        [Bindable(true),Category("Appearance"),DefaultValue(""),Description("必须输入姓名")]publicstring NameErrorMessage{get{                EnsureChildControls();return _nameValidator.ErrorMessage;            }set{                EnsureChildControls();                _nameValidator.ErrorMessage = value;                _nameValidator.ToolTip = value;            }        }        [Bindable(true),Category("Apperance"),DefaultValue(""),Description("姓名标签")]publicstring NameLabel{get{                EnsureChildControls();return _nameLabel.Text;            }set{                EnsureChildControls();                _nameLabel.Text = value;            }        }        [Browsable(false),DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]publicstring Password{get{                EnsureChildControls();return _passwordTextBox.Text;            }        }        [Bindable(true),Category("Appearance"),DefaultValue(""),Description("必须输入密码")]publicstring PasswordErrorMessage{get{                EnsureChildControls();return _passwordValidator.ErrorMessage;            }set{                EnsureChildControls();                _passwordValidator.ErrorMessage = value;                _passwordValidator.ToolTip = value;            }        }        [Bindable(true),Category("Appearance"),DefaultValue(""),Description("密码标签")]publicstring PasswordLabel{get{                EnsureChildControls();return _passwordLabel.Text;            }set{                EnsureChildControls();                _passwordLabel.Text = value;            }        }protectedoverridevoid CreateChildControls(){            Controls.Clear();            _nameLabel =new Label();            _nameTextBox =new TextBox();            _nameTextBox.ID ="nameTextBox";            _nameValidator =new RequiredFieldValidator();            _nameValidator.ID ="validator1";            _nameValidator.ControlToValidate = _nameTextBox.ID;            _nameValidator.Text ="*";            _nameValidator.Display = ValidatorDisplay.Static;            _passwordLabel =new Label();            _passwordTextBox =new TextBox();            _passwordTextBox.TextMode = TextBoxMode.Password;            _passwordTextBox.ID ="passwordTextBox";            _passwordValidator =new RequiredFieldValidator();            _passwordValidator.ID ="validator2";            _passwordValidator.ControlToValidate = _passwordTextBox.ID;            _passwordValidator.Text ="*";            _passwordValidator.Display = ValidatorDisplay.Static;            _button =new Button();            _button.ID ="button1";//_button.Click += new EventHandler(_button_Click);            _button.CommandName ="ClickLogin";this.Controls.Add(_nameLabel);this.Controls.Add(_nameTextBox);this.Controls.Add(_nameValidator);this.Controls.Add(_passwordLabel);this.Controls.Add(_passwordTextBox);this.Controls.Add(_passwordValidator);this.Controls.Add(_button);        }protectedoverridevoid Render(HtmlTextWriter writer){            AddAttributesToRender(writer);            writer.AddAttribute(HtmlTextWriterAttribute.Cellpadding,"1", false);            writer.RenderBeginTag(HtmlTextWriterTag.Table);            writer.RenderBeginTag(HtmlTextWriterTag.Tr);            writer.RenderBeginTag(HtmlTextWriterTag.Td);            _nameLabel.RenderControl(writer);            writer.RenderEndTag();  // Td            writer.RenderBeginTag(HtmlTextWriterTag.Td);            _nameTextBox.RenderControl(writer);            writer.RenderEndTag();  // Td            writer.RenderBeginTag(HtmlTextWriterTag.Td);            _nameValidator.RenderControl(writer);            writer.RenderEndTag();  // Td            writer.RenderEndTag();  // Tr            writer.RenderBeginTag(HtmlTextWriterTag.Tr);            writer.RenderBeginTag(HtmlTextWriterTag.Td);            _passwordLabel.RenderControl(writer);            writer.RenderEndTag();  // Td            writer.RenderBeginTag(HtmlTextWriterTag.Td);            _passwordTextBox.RenderControl(writer);            writer.RenderEndTag();  // Td            writer.RenderBeginTag(HtmlTextWriterTag.Td);            _passwordValidator.RenderControl(writer);            writer.RenderEndTag();  // Td            writer.RenderEndTag();  // Tr            writer.RenderBeginTag(HtmlTextWriterTag.Tr);            writer.AddAttribute(HtmlTextWriterAttribute.Colspan, "2");            writer.AddAttribute(HtmlTextWriterAttribute.Align, "right");            writer.RenderBeginTag(HtmlTextWriterTag.Td);            _button.RenderControl(writer);//writer.AddAttribute(HtmlTextWriterAttribute, Page.GetPostBackEventReference(_button));            writer.RenderEndTag();  // Td            writer.RenderBeginTag(HtmlTextWriterTag.Td);            writer.Write("&nbsp;");            writer.RenderEndTag();  // Td            writer.RenderEndTag();  // Tr            writer.RenderEndTag();  // Table        }    }} 首先我们实例化了几个现有控件的对象。然后声明了一大堆的属性,要注意的:和平时定义属性不同,我们在每一个属性中都添加了EnsureChildControls ()方法。其他的没有任何变化,和一般的属性声明一样。 接下来我们从写了重要的CreateChildControls()。将前面声明好的实例化控件对象添加到controlcollection中。融合成一个控件。 最后重写控件显示的Render()方法。生成登录窗体的样式。效果如下: 这样,我们基本上就完成了复合控件的基本显示功能。 复合控件的事件处理: 由于复合控件中包含子控件,这就使得复合控件的事件处理变得复杂起来。由于不允许开发人员直接访问子控件,如果子控件的事件不能作为顶级事件引发,那么将无法实现子控件的事件处理。 我们可以以两种形式来完成事件的处理:一是直接将事件封装到控件中,显然灵活性很差。二就是自定义事件,用户来完成事件的代码。 第一种情况比较简单:就是在创建我们得控件时,将要实现的效果直接封装在dll中。这里就不做说明了。 但是往往控件触发时,我们想做自己的事情,这就是第二种情况的事件处理。这就需要把事件交给主控件,由主控件统一暴露事件,这样开发人员在使用控件时仅需要为主控件注册事件即可,剩下的由主控件负责引发子控件的事件或执行子控件的某些功能,这里就涉及主控件与其子控件的事件衔接问题,复合控件的这种事件处理,主要是实现子控件事件上传的过程。一般分为:包含法和冒泡法两种处理方式。 -->包含法: 基本思想是:通过在子控件的事件处理程序中调用复合控件的顶层事件处理程序,以完成子控件的事件上传。 在CreateChildControls方法中,为子控件添加事件处理程序。 接着上面登陆控件的例子,来实现下登录按钮的事件。 首先在CreateChildControls()中,为_button添加单击事件。(其他代码略) _button =new Button();            _button.ID ="button1";             _button.Click +=new EventHandler(_button_Click); 然后创建主控件对外的处理函数: void _button_Click(Object source, EventArgs e){            OnClickLogin(EventArgs.Empty);        }privatestaticreadonlyobject EventClickLogin =newobject();publicevent EventHandler ClickLogin{            add{                Events.AddHandler(EventClickLogin, value);            }            remove{                Events.RemoveHandler(EventClickLogin, value);            }        }protectedvirtualvoid OnClickLogin(EventArgs e){            EventHandler clickLoginHandler = (EventHandler)Events[EventClickLogin];if (clickLoginHandler !=null){                clickLoginHandler(this, e);            }        }publicvoid RaisePostBackEvent(string eventArgument)//处理回发事件{            OnClickLogin(new EventArgs());        } 事件的详细处理请参看上一篇。这里要说明的是:在按钮的单击事件处理函数中,将我们在主控件中声明的事件传入进去: void _button_Click(Object source, EventArgs e){     OnClickLogin(EventArgs.Empty);} 这样,我们就实现了第一种方法。测试一下: protectedvoid LoginControl1_ClickLogin1(object sender, EventArgs e){     Label1.Text ="sssssssssssssssqwwssss";} 单击按钮,将触发上面的事件。 -->冒泡法: 基本思想:使用ASP.NET 2.0框架提供的事件上传机制。这种机制允许子控件将事件沿其包容层次结构向上传播到合适的位置引发,并且允许将事件处理程序附加到原始控件以及公开冒泡的事件的控件上。 冒泡法的实现,使用Control基类中专门用于事件上传的两个方法:OnBubbleEvent和RaiseBubbleEvent。OnBubbleEvent方法用于确定子控件的事件是否沿复合控件层次结构向上传递。在该方法中,参数source表示事件源,参数args表示包含事件数据的EventArgs对象。如果子控件的事件向上传递,则为true;否则为false。默认值为false。RaiseBubbleEvent方法用于将所有事件源及其信息分配给控件的父级,并且不能被重写。尽管无法重写此方法,但创作的控件可以通过重写 OnBubbleEvent 方法处理或引发冒泡事件。 还是通过例子说明一下: 首先在CreateChildControls()中声明commandname属性。 _button.CommandName ="ClickLogin"; 然后定义事件: privatestaticreadonlyobject EventClickLogin =newobject();publicevent EventHandler ClickLogin{            add{                Events.AddHandler(EventClickLogin, value);            }            remove{                Events.RemoveHandler(EventClickLogin, value);            }        }protectedvirtualvoid OnClickLogin(EventArgs e){            EventHandler clickLoginHandler = (EventHandler)Events[EventClickLogin];if (clickLoginHandler !=null){                clickLoginHandler(this, e);            }        }protectedoverridebool OnBubbleEvent(object source, EventArgs e){bool handled =false;if (e is CommandEventArgs){                CommandEventArgs ce = (CommandEventArgs)e;if (ce.CommandName =="ClickLogin"){                    OnClickLogin(EventArgs.Empty);                    handled =true;                }            }return handled;        }publicvoid RaisePostBackEvent(string eventArgument)//处理回发事件{            OnClickLogin(new EventArgs());        } 里主要要注意的是:OnBubbleEvent()的使用。通过CommandName的值,来相应的找到处理事件的控件。 测试一下: protectedvoid LoginControl1_ClickLogin1(object sender, EventArgs e){     Label1.Text ="sssssssssssssssqwwssss";} 单击按钮,将触发上面的事件。 小结:这样,复合控件的基本使用就介绍完了,不是很难。只要记住特定的一些东西,就可以很容易的创造出复合控件。值得大家注意的是复合控件中事件的两种处理方法。希望对新手有帮助。 转自:http://www.cnblogs.com/gaoweipeng/archive/2009/06/23/1507554.html

龙生   08 Apr 2013
View Details

ASP.NET服务器控件开发(3)--事件和回传数据的处理

  前两篇介绍了服务器控件的基本显示,属性的设定,继承Webcontrol开发控件等内容,这篇介绍下定制服务器控件的事件的处理和回传数据的处理。 当ASP.NET页面处理回传到服务器端的表单时,两种信息会传递给页面中的控件: 回传事件,如Button一类控件触发的回传,会引发服务器端事件; 回传数据:是Web表单中包含的数据,该数据是在Web表单提交到服务器端时传递给如TextBox一类的控件。 处理回传数据 PostBack(回传):ASP.NET控件提交表单到服务器端,将信息从浏览器传递到服务器端的过程。 我们可能经常会在Page_Load事件中写这样的代码: protectedvoid Page_Load(object sender, EventArgs e)        {if (!IsPostBack)            {.            }        } 但是初学的时候我们很少回去问,为什么要写这段代码,只知道这么写就是对的。其实这就是数据回传的一个表现,通过该值指示该页是否正为响应客户端回发而加载。 ASP.ENT服务器控件处理回传数据,基本上完成以下两个工作: -->继承并实现IPostBackDataHandler接口的  -->实现RaisePostDataChangedEvent方法,处理回发数据 通过例子说明一下,这里创建一个自己的文本框:创建一个ASP.NET服务器控件项目(MyTextBox) Codenamespace NewTextBox{    [DefaultProperty("Text")]    [ToolboxData("<{0}:NewTextBox runat=server></{0}:NewTextBox>")]publicclass NewTextBox : WebControl, IPostBackDataHandler    {publicevent EventHandler TextChanged; publicstring ViewText//定义显示文字属性        {get            {if (ViewState["Text"].Equals(null))                {return String.Empty;                }else                {return ViewState["Text"].ToString();                }            }set            {                ViewState["Text"] = value;            }        } protectedoverride HtmlTextWriterTag TagKey//向页面中添加文本框        {get            {return HtmlTextWriterTag.Input;            }        } protectedoverridevoid AddAttributesToRender(HtmlTextWriter writer)        {            writer.AddAttribute(HtmlTextWriterAttribute.Type, "text");            writer.AddAttribute(HtmlTextWriterAttribute.Value, ViewText);            writer.AddAttribute(HtmlTextWriterAttribute.Name, this.UniqueID); base.AddAttributesToRender(writer);        } publicbool LoadPostData(string postDataKey, System.Collections.Specialized.NameValueCollection postCollection)//表单域的值和控件的ViewText(此示例中)属性的当前值不匹配,那么将新的值赋给ViewText属性,并且返回True。只有当LoadPostData返回True的时候,才会调用RaisePostDataChangedEvent方法。        {if (postCollection[postDataKey] != ViewText)            {                ViewText = postCollection[postDataKey];returntrue;            }returnfalse;        } publicvoid RaisePostDataChangedEvent()        {if (TextChanged !=null)                TextChanged(this, EventArgs.Empty);        }     }} 测试一下: protectedvoid Button1_Click(object sender, EventArgs e)        {            Label1.Text = NewTextBox1.ViewText;        } 只有当文本框中是文字发生变化是,才会引起数据的回发并从新获得数据。(控件拖到页面时,要给viewText赋值)   处理回发事件 ASP.NET服务器控件处理回发事件,基本上需要完成以下两个工作: -->继承并实现IPostBackEventHandler接口的  -->实现RaisePostBackEvent方法,处理回发事件 Button控件继承IPostBackEventHandler接口(所有的按钮控件,ImageButton,LinkButtton都继承了这个接口)。IPostBackEventHandler接口专门定义了处理回发事件的方法,如果自定义控件需要处理回发事件,你就需要继承IPostBackEventHandler接口。 通过例子说明一下,这里我们定制一个自己的按钮:创建一个ASP.NET服务器控件项目(MyButton) Codenamespace MyButton{    [DefaultProperty("Text")]    [ToolboxData("<{0}:MyButton runat=server></{0}:MyButton>")]publicclass MyButton : WebControl, IPostBackEventHandler    {privatestaticreadonlyobject ClickKey =newobject(); publicevent EventHandler Click //定义事件的委托        {            add            {                Events.AddHandler(ClickKey, value);            }            remove            {                Events.RemoveHandler(ClickKey, value);            }        } protectedvirtualvoid OnClick(EventArgs e)//定义单击事件的处理程序        {            EventHandler clickEventDelegate = (EventHandler)Events[ClickKey]; if (clickEventDelegate !=null)            {                clickEventDelegate(this, e);            }        } publicvoid RaisePostBackEvent(string eventArgument)//处理回发事件        {            OnClick(new EventArgs());        } protectedoverridevoid RenderContents(HtmlTextWriter output)        {            output.Write("<INPUT TYPE=submit name="+this.UniqueID +" Value='这是自己定制的按钮!' />");        }    }} 测试一下: protectedvoid MyButton1_Click(object sender, EventArgs e)        {            Label1.Text ="Hello World!!!!!!!!!";        } 按钮的事件回发处理成功。 客户端回发事件 在asp.net2.0中,Button 控件多了一个UseSubmitBehavior 属性,指示 Button 控件使用客户端浏览器的提交机制(客户端回发)还是 ASP.NET 回发机制,默认采用ASP.NET回发机制,如果设置为false的话,则需要调用GetPostBackEventReference 方法来返回 Button 的客户端回发事件。 当设置UseSubmitBehavior 属性为flase时,运行页面时,则会发现一段自动生成的javascript代码(查看源文件) Code<script type="text/javascript">//<![CDATA[var theForm = document.forms['form1'];if (!theForm) {    theForm = document.form1;}function __doPostBack(eventTarget, eventArgument) {if (!theForm.onsubmit || (theForm.onsubmit() !=false)) {        theForm.__EVENTTARGET.value = eventTarget;        theForm.__EVENTARGUMENT.value = eventArgument;        theForm.submit();    }}//]]></script> 这里我们创建一个按钮,根据属性的设定,更改其事件回发的方式: Codenamespace MyLinkButton{    [DefaultProperty("Text")]    [ToolboxData("<{0}:MyLinkButton runat=server></{0}:MyLinkButton>")]publicclass MyLinkButton : WebControl, IPostBackEventHandler    {publicvirtual ButtonDisplay Display        {get            {object display = ViewState["Display"];if (display ==null)return ButtonDisplay.Button;elsereturn (ButtonDisplay)display;            }set            {                ViewState["Display"] = value;            }        } publicvirtualstring Text        {get            {object text = ViewState["Text"];if (text ==null)returnstring.Empty;elsereturn (string)text;            }set            {                ViewState["Text"] = value;            }        } privatestaticreadonlyobject ClickKey =newobject(); publicevent EventHandler Click//定义委托        {            add            {                Events.AddHandler(ClickKey, value);            }            remove            {                Events.RemoveHandler(ClickKey, value);            }        } protectedvirtualvoid OnClick(EventArgs e)//定义Click事件处理函数        {            EventHandler clickEventDelegate =               (EventHandler)Events[ClickKey];if (clickEventDelegate !=null)            {                clickEventDelegate(this, e);            }        } publicvoid RaisePostBackEvent(string argument)        {             OnClick(EventArgs.Empty);        } overrideprotectedvoid Render(HtmlTextWriter writer)        {base.Render(writer);            Page.VerifyRenderingInServerForm(this); if (Display == ButtonDisplay.Button)            {                writer.Write("<INPUT type=\"submit\"");                writer.Write(" name=\"" + this.UniqueID + "\"");                writer.Write(" id=\"" + this.UniqueID + "\"");                writer.Write(" value=\"" + Text + "\"");                writer.Write(" />");            }elseif (Display == ButtonDisplay.Hyperlink)            {                writer.Write("<A href=\"");                writer.Write(Page.ClientScript.GetPostBackClientHyperlink(this, ""));                writer.Write("\">" + Text + "</A>");            }        } publicenum ButtonDisplay        {            Button =0,            Hyperlink =1        }     } } 根据属性Display的属性的设置,对事件的回发进行控制,如果是Hyperlink则是客户端回发机制。   小结:新手在对事件的回发上可能会迷糊,但是不要紧,慢慢的理解。简单的理解事件的回发就是我们点击一个按钮发生的事件,而这个事件的处理ASP.NET给我们提供了两种方式。更多ASP.NET服务器控件事件可以参考: http://msdn.microsoft.com/zh-cn/library/cc437696(VS.71).aspx http://msdn.microsoft.com/zh-cn/library/xax2hw3x.aspx 写的不好,希望能对新手有帮助。 转自:http://www.cnblogs.com/gaoweipeng/archive/2009/06/19/1506243.html

龙生   08 Apr 2013
View Details

ASP.NET服务器控件开发(2)--继承WebControl类

  前篇文章简单介绍了如何封装Html来创建我们的ASP.NET服务器控件。这篇说说如何继承ASP.NET独有的WebControl类来制作标准服务器控件。 先来介绍下WebControl类 WebControl类: WebControl 类从 Control 派生,用作定义 System.Web.UI.WebControls 命名空间中的所有控件的公共方法、属性和事件的基类。提供所有 Web 服务器控件的公共属性、方法和事件。通过设置在此类中定义的属性,可以控制 Web 服务器控件的外观和行为。主要的属性有:AccessKey、Attributes、 Width、Height等。此外,一个从 WebControl 派生的控件也自行参与到 ASP.NET 的主题功能。WebControl类的属性和方法详细的内容可以参看MSDN。 这里再简单的说下WebControl和HtmlContrlol的区别: Web控件和Html控件虽然好多功能相同并且长得很像,但是它们的内部实现机制是完全不一样的。 Web控件具有回送功能,能够用ViewState维持控件的状态。Html控件则不能,当点击页面的操作,其状态就会丢失。(ViewState后面会有讲解) Html控件与Web控件最大的区别是它们对事件处理的方法不同。对于Html窗体控件,当引发一个事件时,浏览器会处理它。但对于Web控件,事件仅由浏览器生成,但浏览器不会处理它,客户端要给服务器发个信息,告诉服务器处理事件。 不过有些事件,比如:按下键/移动/鼠标等事件,Asp.net中没有这些事件(因为这些事件即时性强,服务器处理得不够及时),这时候Html控件就发挥其作用了,结合Html事件协助完成。 有的资料上说:Web控件要比Html控件执行效率要好。这个没有太好的依据,仅供大家参考,高手也可以谈谈自己的想法。 自己动手: 这里我们不像上篇文章那样,简单的创建一个类库工程,而是直接创建ASP.NET服务器控件项目。 VS2008会自动的为我们生成如下代码: Codenamespace SelfServerControl{    [DefaultProperty("Text")]    [ToolboxData("<{0}:MyControl runat=server></{0}:MyControl>")]publicclass MyControl : WebControl    {        [Bindable(true)]        [Category("Appearance")]        [DefaultValue("")]        [Localizable(true)]publicstring Text        {get            {                String s = (String)ViewState["Text"];return ((s ==null) ?"["+this.ID +"]" : s);            } set            {                ViewState["Text"] = value;            }        } protectedoverridevoid RenderContents(HtmlTextWriter output)        {            output.Write(Text);        }    }}   代码说明: 是不是有点熟悉,很像上节课继承自Control类生成ASP.NET服务器控件的代码。 代码中定义了一个 Text 属性(属性的声明和上篇基本一样),并使用视图状态(ViewState )存储该属性值。使用视图状态保存回发间的 Text 值。每次回发时,将重新创建页并从视图状态还原值。如果 Text 值并未存储在视图状态中,则在每次回发时会将值设置为其默认的 Empty。ViewState 属性继承自 WebControl,是保存数据值的字典。通过使用 String 键,可输入和检索值。代码中将“Text”用作键。字典中的项被类型化为 Object,然后必须将其强制转换为属性类型。 ViewState想必大家都已经很熟悉了,简单的理解:当aspx页面重新加载后,为了避免上一次的存放在变量中的数据丢失,用ViewState来保存。 RenderContents 方法: 通常,在从 WebControl 派生控件并呈现单个元素时,应重写 RenderContents 方法(而不是 Render 方法),以呈现控件标记中的内容。在呈现控件及其样式属性的开始标记之后,WebControl 的 Render 方法将调用 RenderContents。如果重写 Render 方法以写入内容,则控件将丢失生成到 WebControl 的 Render 方法中的样式呈现逻辑。 如果我们将上篇的代码复制到这里,也能得到同样的效果。这里就不做演示了。 WebControl类为开发人员提供了几个特殊的方法,来完成我们对标注服务器控件的开发: AddAttributesToRender(HtmlTextWriter.writer):WebControl的子类应该重写该方法,以便包含用于呈现最外层HTML元素的HTML属性的代码块RenderBeginTag(HtmlTextWriter writer):WebControl的子类应该重写该方法,以便包含用于呈现最外层HTML元素的打开标记的代码块RenderContents(HtmlTextWriter writer): WebControl的子类应该重写该方法,以便包含用于呈现最外层HTML元素的打开和关闭标记之间嵌套的HTML的代码块。RenderEndTag(HtmlTextWriter writer):WebControl的子类应该重写该方法,以便包含用于呈现最外层HTML元素的关闭标记的代码块 实现WebControl类的Render方法: protectedinternaloverridevoid Render(HtmlTextWriter writer) {   RenderBeginTag(writer);   RenderContents(writer);   RenderEndTag(writer); } AddAttributesToRender方法中发生了什么。该方法将在RenderBeginTag方法中被调用。 具体的实例在这里就不做了,给大家一个参看的例子。 简单应用: ASP.NET给我们提供了很多现成的控件,比如Label,button,textbox等等。在平时的开发中,我们完全可以不继承Webcontrol类,直接继承它下面控件的子类,这样更有助于我们项目中的应用和开发。下面说个以前在项目中用到的小实例。 Codenamespace MyTextBox{    [DefaultProperty("Text"), ToolboxData("<{0}:BrianTextBox runat=server></{0}:BrianTextBox>"), Designer("System.Web.UI.Design.WebControls.PreviewControlDesigner, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")]publicclass BrianTextBox : System.Web.UI.WebControls.TextBox    {///<summary>/// 构造函数///</summary>public BrianTextBox()            : base()        {base.Attributes.Add("onfocus", "this.className='"+ onFocus +"';");base.Attributes.Add("onblur", "this.className='"+ onBlurCss +"';");base.CssClass = Class;        } privatestring _onFocusCss ="colorfocus";        [Bindable(true), Category("Appearance"), Description("文本框获取焦点时触发")]///<summary>/// 获取焦点时样式///</summary>publicstring onFocus        {get { return _onFocusCss; }set { _onFocusCss = value; }        } privatestring _onBlurCss ="colorblur";        [Bindable(true), Category("Appearance"), Description("文本框失去焦点时触发")]///<summary>/// 失去焦点时样式///</summary>publicstring onBlurCss        {get { return _onBlurCss; }set { _onBlurCss = value; }        } privatestring _Class ="colorblur";        [Bindable(true), Category("Appearance"), DefaultValue("")]///<summary>/// 样式///</summary>publicstring Class        {get { return _Class; }set { _Class = value; }        } ///<summary>/// 获取焦点的控件ID(如提交按钮等)///</summary>        [Bindable(true), Category("Appearance"), DefaultValue("")]publicstring SetFocusButtonID        {get            {object o = ViewState[this.ClientID +"_SetFocusButtonID"];return (o ==null) ?"" : o.ToString();            }set            {                ViewState[this.ClientID +"_SetFocusButtonID"] = value;if (value !="")                {this.Attributes.Add("onkeydown", "if(event.keyCode==13){document.getElementById('"+ value +"').focus();}");                }            }        }    }} 代码不是很难,简单说下。这里我不是继承自WebControl类,而是继承自它的子类TextBox类,向父类中添加了两个属性,分别代表失去焦点时的样式和获取焦点时的样式。还有一个属性是获取焦点的控件ID。这里默认的设定了css的类名称,所以在使用时,需要创建两个css: Code<style>    .colorblur{        cursor:hand;        background-color:Aquamarine;}         .colorfocus{        cursor:hand;        background-color:Red;}    </style> 不用做其他的任何设置,运行,会看到当我们得Textbox获得焦点的时候背景色红色,失去焦点时,背景是蓝色。,当然,这里只是做个例子,获得和失去焦点的样式大家可以自己去设计。 这只是简单的小应用,给大家提个思路。大家完全可以开动自己创新思维,创造出自己独特的服务器控件。灵活的运用在我们得项目开发中。 转自:http://www.cnblogs.com/gaoweipeng/archive/2009/06/16/1502952.html

龙生   08 Apr 2013
View Details

ASP.NET服务器控件开发(1)--封装html

  在我们的项目开发中,由于ASP.NET的服务器控件功能有限,所以我们经常会自己定义特定的服务器控件,来满足开发中特定的业务要求。可见知道如何开发ASP.NET服务器控件是非常有必要的。 其实简单的实现ASP.NET服务器控件不是很难,以前园子中也有大牛介绍过相应的内容,这里站在巨人的肩膀上也来分享下开发ASP.NET服务器控件的方法和自己的一些体会。写给新手,高手绕过。 学习ASP.NET的服务器控件开发,个人认为最好的方式就是自己去实践,当然理论知识也是很重要的,但是如果我们只是看理论的知识,可能会被里面的一些概念闹糊涂,看着看着就睡着了,如果自己动手创做出一个自己的控件,效果就不一样了。 下面就通过实例创建一个简单的服务器控件: 首先我们创建一个类库工程SelfWebControl。在同一解决方案中我们在创建一个ASP,NET Web应用程序(用来测试我们得控件) namespace SelfWebControl{publicclass ControlA:Control//Control类中定义了所有ASP.NET服务器控件共享的属性和方法    {     }} 我将ControlA类继承Control类,Control类是.NET中所有控件的基类,其中包含了控件共有的属性和方法。 Control类 公共属性: ClientID 获取由 ASP.NET 生成的服务器控件标识符。  Controls 获取 ControlCollection 对象,该对象表示 UI 层次结构中指定服务器控件的子控件。  EnableViewState 获取或设置一个值,该值指示服务器控件是否向发出请求的客户端保持自己的视图状态以及它所包含的任何子控件的视图状态。  ID 获取或设置分配给服务器控件的编程标识符。  NamingContainer 获取对服务器控件的命名容器的引用,此引用创建唯一的命名空间,以区分具有相同 Control.ID 属性值的服务器控件。  Page 获取对包含服务器控件的 Page 实例的引用。  Parent 获取对页 UI 层次结构中服务器控件的父控件的引用。  Site 获取有关服务器控件所属 Web 站点的信息(原文自MSDN,但是我认为不对,应该是指组件的“容器”站点,并非 web site)。  TemplateSourceDirectory 获取包含当前服务器控件的 Page 或 UserControl 的虚拟目录。  UniqueID 获取服务器控件的唯一的、以分层形式限定的标识符。  Visible 获取或设置一个值,该值指示服务器控件是否作为 UI 呈现在页上。 公共方法: DataBind 将数据源绑定到被调用的服务器控件及其所有子控件。  Dispose 使服务器控件得以在从内存中释放之前执行最后的清理操作。  Equals(从 Object 继承) 已重载。确定两个 Object 实例是否相等。  FindControl 已重载。在当前的命名容器中搜索指定的服务器控件。  GetHashCode(从 Object 继承) 用作特定类型的哈希函数,适合在哈希算法和数据结构(如哈希表)中使用。  GetType(从 Object 继承) 获取当前实例的 Type。  HasControls 确定服务器控件是否包含任何子控件。  RenderControl 将服务器控件的内容输出到所提供的 HtmlTextWriter 对象中;如果已启用跟踪功能,则存储有关控件的跟踪信息。  ResolveUrl 根据传递给 TemplateSourceDirectory 属性的值,将相对 URL 解析为绝对 URL。  ToString(从 Object 继承) 返回表示当前 Object 的 String。 公共事件: DataBinding 当服务器控件绑定到数据源时发生。  Disposed 当从内存释放服务器控件时发生,这是请求 ASP.NET 页时服务器控件生存期的最后阶段。  Init 当服务器控件初始化时发生;初始化是控件生存期的第一步。服务器控件应执行任何创建和设置实例所需的初始化步骤。在该事件内无法使用视图状态信息;它尚未填充。在该事件的生存期内不应访问其他服务器控件,不论它是此控件的子级还是父级。不一定会创建其他服务器控件,也不一定能够访问它们。 Load 当服务器控件加载到 Page 对象中时发生。通知服务器控件执行任何设置为在每次页请求时发生的处理步骤。开发者可以访问视图状态信息并利用该事件形成 POST 数据。还可以访问页控件层次结构内的其他服务器控件。 PreRender 当服务器控件将要呈现给其包含的 Page 对象时发生。使用该事件在服务器控件呈现给页的输出之前执行任何更新。在该事件的生存期内可以保存服务器控件视图状态的任何更改。不保存呈现阶段内所做的同样更改。 Unload 当服务器控件从内存中卸载时发生。 保护的属性: ChildControlsCreated 获取一个值,该值指示是否已创建服务器控件的子控件。  Context 为当前 Web 请求获取与服务器控件关联的 HttpContext 对象。  Events 获取控件的事件处理程序委托列表。此属性为只读。  HasChildViewState 获取一个值,该值指示当前服务器控件的子控件是否具有任何已保存的视图状态设置。  IsTrackingViewState 获取一个值,该值指示服务器控件是否将更改保存到其视图状态。  ViewState 获取状态信息的字典,这些信息使您可以在同一页的多个请求间保存和还原服务器控件的视图状态。  ViewStateIgnoresCase 获取一个值,该值指示 StateBag 对象是否不区分大小写。  受保护的方法: AddParsedSubObject 通知服务器控件某个元素(XML 或 HTML)已经过语法分析,并将该元素添加到服务器控件的 ControlCollection 对象。  ClearChildViewState 删除服务器控件的所有子控件的视图状态信息。  CreateChildControls 通知使用基于合成的实现的服务器控件创建它们包含的任何子控件,以便为回发或呈现做准备。  CreateControlCollection 创建一个新的 ControlCollection 对象来保存服务器控件的子控件(包括文本控件和服务器控件)。 EnsureChildControls 确定服务器控件是否包含子控件。如果不包含,则创建子控件。  Finalize(从 Object 继承) 已重写。允许 Object 在“垃圾回收”回收 Object 之前尝试释放资源并执行其他清理操作。  IsLiteralContent 确定服务器控件是否只包含文字内容。Asp.net页面中普通的html标签被asp.net编译为一个 LiteralContent控件(意味着轻型控件)。 LoadViewState 从 SaveViewState 方法保存的上一个页请求还原视图状态信息。  MapPathSecure 如果请求服务器控件有足够的安全权限读取映射结果,检索相对于源文件的映射物理文件路径。  MemberwiseClone(从 Object 继承) 创建当前 Object 的浅表副本。  OnBubbleEvent 确定服务器控件的事件是否沿页的 UI 服务器控件层次结构向上传递。  OnDataBinding 引发 DataBinding 事件。  OnInit 引发 Init 事件。  OnLoad 引发 Load 事件。  OnPreRender 引发 PreRender 事件。  OnUnload 引发 Unload 事件。 注意   在服务器控件生存期的此阶段,服务器控件应执行所有最后的清理操作,例如关闭文件、关闭数据库连接和丢弃对象。  RaiseBubbleEvent 将所有事件源及其信息分配给控件的父级。  Render 将服务器控件内容发送到提供的 HtmlTextWriter 对象,此对象编写将在客户端呈现的内容。  RenderChildren 将服务器控件子级的内容输出到提供的 HtmlTextWriter 对象,此对象编写将在客户端呈现的内容。  SaveViewState 保存自页回发到服务器后发生的任何服务器控件视图状态更改。  TrackViewState 导致跟踪服务器控件的视图状态的更改,以便这些更改可以存储到服务器控件的 StateBag 对象中。通过 Control.ViewState 属性可访问此对象。 这里我们要重写Render方法,通过HtmlTextWriter 对象将控件中的内容显示出去。 Codenamespace SelfWebControl{publicclass ControlA:Control//Control类中定义了所有ASP.NET服务器控件共享的属性和方法    {protectedoverridevoid Render(HtmlTextWriter writer)        {            writer.Write("<table style='width:300px; height:200px; background-color:Bisque'>");            writer.Write("<tr>");            writer.Write("<td>这是第一列</td>");            writer.Write("<td>这是第二列</td>");            writer.Write("<td>这是第三列</td>");            writer.Write("</tr>");            writer.Write("</table>");        }    }} 生成我们得SelfWebControl工程,再切换到ASP.NET应用程序的工具箱时,VS2008会自动的将我们刚刚创建的ControlA添加到工具箱中,避免了我们以前通过选择项添加控件的过程。 这样,我们就已最简单的形式实现了一个ASP.NET服务器控件。但是如果我想修改表格的宽度,高度,背景色该怎么改呢? 这就需要我们定义服务器控件的属性。大家也都知道,ASP.NET的服务器控件有很多属性,而我们现在的控件只有公有的几个属性。 先来看看我们做了那些改动: Codepublicclass ControlA:Control//Control类中定义了所有ASP.NET服务器控件共享的属性和方法    {privateint _tWidth;privateint _tHeight;privatestring _bgColor;         [Browsable(true)]//在属性窗口中是否可见        [Category("Appearance")]//属性的分类,如,行为,外观,大家可以在属性窗口看见这样的分类        [DefaultValue(100)]//属性的默认值        [Description("表格宽度")]//这些是显示在属性窗口底下的publicint tWidth        {get { return _tWidth; }set { _tWidth = value; }        }         [Browsable(true)]        [Category("Appearance")]        [DefaultValue(100)]        [Description("表格高度")]publicint tHeight        {get { return _tHeight; }set { _tHeight = value; }        }         [Browsable(true)]        [Category("Appearance")]        [DefaultValue("Bisque")]        [Description("表格背景颜色")]publicstring bgColor        {get { return _bgColor; }set { _bgColor = value; }        } protectedoverridevoid Render(HtmlTextWriter writer)        {            writer.Write("<table style='width:"+ tWidth +"px; height:"+tHeight+"px; background-color:"+bgColor+"'>");            writer.Write("<tr>");            writer.Write("<td>这是第一列</td>");            writer.Write("<td>这是第二列</td>");            writer.Write("<td>这是第三列</td>");            writer.Write("</tr>");            writer.Write("</table>");        }    } 代码很简单,想必大家都能看懂,值得注意的就是对每一个属性的声明。需要引用命名空间:using System.ComponentModel;每一个标签的作用我已经在代码中做了说明,这样我们就为我们得控件添加了属性. 还要说明一点的就是,如果我们想在把控件拖到页面中时标签内自动的添加一些属性,需要添加下面的代码: [ToolboxData("<{0}:ControlA runat='server' bgColor='red' tHeight='200' tWidth='300'></{0}:ControlA>")] 值得注意的是这里的写法,{0}的冒号中之后的那个"ControlA“就是类的名字,不要写错。还有runat='sever'一定要写。 是不是很简单,这样,我们只是封装了简单的html来完成ASP.NET控件的制作。 小结:简单的制作一个ASP.NET的服务器控件很简单,但是光只是通过html的输出有的时候意义不大,这里只是介绍一种方法和思路。打开学习定制自己的ASP.NET控件的第一扇门。在以后的文章中我会介绍针对于继承WebControl开发ASP.NET控件。 转自:http://www.cnblogs.com/gaoweipeng/archive/2009/06/13/1501833.html

龙生   08 Apr 2013
View Details
1 36 37 38 44