博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

一步一步編寫控件...

Posted on 2006-05-12 11:44  自適應軟件......  阅读(1689)  评论(0编辑  收藏  举报
 
 

當你準備寫第一個Server Control的時候,我的這些也許會對你有用!

 可參考控件源碼: http://www.cnblogs.com/robin0925/archive/2006/05/11/397407.html
 


Asp.net 提供了幾種類型的控件,Html 控件,Web服務端控件,你可以隨心設計開發基於Web的客戶控件.
1.      服務端控件

試想你如果在一個項目中有一個Asp.net頁面,而你在其他的項目中也希望有用到這個頁面,你可以寫一個User Control.如果你想把多個現有的控件的特性整合起來提供給所有的項目的話, 你可以創建一個Server Control.你還可以應用遺傳原理來擴展一個現有的控件,從現有控件的一個具體類入手重寫提高他的功能.

2.      第一步 創建控件 

a.決定你将要實現的類的基類
b.如果
你的控件有介面,Override方法實現UI
c.規劃控件的功能,設計好屬性,方法和事件
d.決定用何種方式post back 數據
e.規劃客戶頁面功能
基類的選擇  你創建的Control不需要用戶介面,所以,你的基類應該繼承System.Web.UI.Control,如果你的Control需要用戶介面,那麼,你的控件基類應該繼承System.Web.UI.WebControls.

 3.       初始化你的控件 

控件生命週期的第一步是事件初始化.例如:你可以初始化Local變量.在這個時候確信你的控件沒有訪問其他的服務端控件.一旦這個控件被拖進了頁面的話,控件的load事件就被fired,從此,控件開始接受所有的事件,例如,增加數據集. 在控件Output到客户端之前,如果你有任何Atcion要執行的話,PreRender事件是最好的方式.( 注:PreRender是事件处理程序接收一个 EventArgs 类型的参数。)

4.      ViewState的理解 

如果重载本身父类提供的enable属性,将导致无法将子控件中的值用viewstate回传,即无法保持状态。所以最好自己定义该类属性并实现。定义属性时,如果是子控件本身属性的反映,可以直接取其值,值将自动保留,如果属于自己定义的属性,用viewState保留状态.

5.      弄清Aps.netRequest,Render然後Post的過程

asp.net页面如果是通过post请求到服务器,框架将会遵行事件周期生成、调用控件,而控件(如果支持回传)则将加载回传数据,并且映射成控件的服务器端事件,就好像在重放客户的客户行为(客户按下一个按钮,却引发服务器端控件的click事件)。其中的机制如何?如果一个控件需要处理回传事件,那么必须实现一个特定接口 IPostBackEventHandler接口:
public interface IPostBackEventHandler{
        void RaisePostBackEvent(string eventArgument);}
以及另外一个接口:IPostBackDataHandler {
        bool LoadPostData( string postDataKey, NameValueCollection postCollection);void RaisePostDataChangedEvent();}
    一旦控件实现了这些接口,页面框架就会自动在PostBack数据完成后,调用控件的此接口IPostBackDataHandler。LoadPostData,从而让控件读取post上来的数据。PostDataKey为PostBack数据中的命名键名,通过NameValueCollection[postDataKey]可以获得页面框架传递给控件的值。控件应当读取此值,进行自己内部状态更新,反映状态变化。如果控件返回真,表示服务器控件状态改变,此时页面框架会立即调用此控件的RaisePostDataChangedEvent方法。此时,控件应当自己定义该引发那些服务器控件对外提供的事件。这些事件往往是控件编程者精心设计留给使用这控键的aspx编程者的代码舞台。
    至于另一个接口IPostBackEventHandler,也是回传时候服务器调用的接口。我们知道每一个控件都有一个UniqueID,当客户端触发一个可以引起回传的客户端事件(譬如按下了submit按钮),那么自然HTTP Post数据到服务器端,服务器页面框架进行到PostBack处理时候,会检索控件是否支持IpostBackEventHandler接口,并且查找控件的UniqueID发现支持就立即调用此接口的RaisePostBackEvent方法,表示UniqueID的控件发生了一个需要捕获的事件。很明显,并非客户端所有事件都可以投射到服务器端,只能够是能够引发Post Back(也就是能够提交表单数据到服务器的事件)的事件和控件。注意,这里严格要求了UniqueID必须在服务器端和客户端对应一致,否则无法映射事件。
值得注意的是,如果要实现接口,需要如下实现接口,而不是通常的仅仅接口方法名同名即可:
void IPostBackEventHandler.RaisePostBackEvent(string eventArgument)
    {……}
也就是说,接口针对页面框架实现的,也由页面框架调用。

另一方面,在客户端,能够引起回传的实际上仅有2个HTML元素<inoput type=submit >和<input type=image,但是通过客户端脚本,其他客户端事件也可导致回传数据到服务器端。Page类提供了一系列的方法来帮助实现其他可引发回传的途径:public string GetPostBackClientEvent(Control control,string argument);

获取对客户端脚本函数的引用,该函数在被调用时将导致服务器回发到窗体。public string GetPostBackClientHyperlink(Control control,string argument);将 javascript: 追加到从 GetPostBackEventReference 调用的返回的开头,从而使服务器上可以进行超级链接回发处理。

public string GetPostBackEventReference(Control);

public string GetPostBackEventReference(Control, string);

        获取对客户端脚本函数的引用,调用该函数将使服务器.如果一个控件确定通过以上方法确保客户端引发回传事件,那么控件引用页将导致最终输出到客户端的HTML中包含脚本,并且脚本中藏有如下隐含变量:
<input type=”hidden” name=”__EVENTTARGET” value=””>
<input type=”hidden” name=”__EVENTARGUMENT” value=””>
<script language=”javascript”><!—
function __doPostBack(eventTarget,eventArgument){
var theform=document._ct10;
theform.__EVENTTARGET.value= eventTarget;
theform.__EVENTARGUMENT.value= eventArgument;}-- ></script>
任何客户端脚本只要合法调用了
__doPostBack方法即可实现回传到服务器端,并且服务器端也知道了是引发了那一个UniqueID得控件的事件。

6.      簡單分析一段代嗎

using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.ComponentModel;
using System.Collections.Specialized;
namespace MyWebControls
{
/// <summary>
/// 创建一个派生于WEBCONTROL的类
/// 实现一个公有构造函数,它将调用基类构造函数来指定服务器控件应该输出一个input元素
/// 重写AddAttributesToRender方法,调用该方法是为了允许派生类为根元素input 添加属性
/// 我们将添加一个name属性,它的值由uniqueID特性派生,asp.net使用这个特性来存储每个控件的唯一ID。
/// </summary>

[DefaultProperty("Text"), 
ToolboxData(
"<{0}:MyTextBox runat=server></{0}:MyTextBox>")]
public class MyTextBox : System.Web.UI.WebControls.WebControl,IPostBackDataHandler
{
public MyTextBox():base("input")
{
}

//使用ViewState对象将值保存起来,此对象的有效范围为当前页面都可以存取.最终保存在客户端。每次都会进行回送

//ViewState是StateBag类,可存放的数据类型有 int bool string 或数组 及其他的基本数据类型,及arraylist,hashtable,
//或具有类型转换器的类型,可以串行的类型
public string Text
{
get
{
if(ViewState["value"]==null)
{
return String.Empty;
}

return (string)ViewState["value"];
}

set
{
ViewState[
"value"]=value;
}

}

protected override void AddAttributesToRender(HtmlTextWriter writer)
{
base.AddAttributesToRender (writer);
writer.AddAttribute(HtmlTextWriterAttribute.Name,UniqueID);
writer.AddAttribute(
"type","text");
if(Text!=null)
writer.AddAttribute(
"value",Text);
}

IPostBackDataHandler 成员
//注册一个事件,文本改变事件
public event EventHandler OnMyTextChnaged;
}
}