ASP.NET中設計帶事件定制控件
|
在試圖為客戶開發一個在網絡上運行的應用程序時,我發現有關正確使用.NET Web控件的討論非常少。下面是使用.NET Web控件的常見問題:
1、如何使這些控件間相互通訊?
2、如何使這些控件保持狀態?
3、如何將多個控件有效地聯接在一個網頁上?
我是一名ASP開發人員,發現轉向ASP.NET并非是件輕而易舉的事。我最初的想法是通過Session對象或使用查詢語句保持狀態,但發現這二種方法都太邋遢,而且,當試圖對網頁上的所有Web控件進行同步時就會出現問題。我在偶然間發現了一篇有關在Web控件中創建事件的文章,但在實踐中仍然吃足了苦頭,因此,我認為提供一個有關正確地創建Web控件并同時創建定制事件的實例是非常重要的。
討論將按照下面的順序進行:
1、創建一個Web控件
2、創建控件的定制事件和事件參數
3、在網頁上正確地使用Web控件
在討論期間,我還會向讀者提供一些小技巧,使讀者能夠更精確和快速地開發應用程序。
我們在這里創建的Web控件是一個定制的下拉選擇框,它基于標準版本的SQL Server或MSDE的pubs數據庫中的stores表。在開發中我們使用了Visual Studio .NET 2003開發工具和C#編程語言。
在創建Pubs Web項目后,第一個任務(至少對于我是如此)是將WebForm1.aspx文件改名為Default.aspx,并修改類,使之與名字相符。然后是在IDE環境中創建一個文件夾結構,方便對象的查找。

(圖1)
我創建了Controls目錄存儲所有創建的控件,以更方便地訪問它們。根據創建控件時的粒度,我們可以進一步地細分Controls目錄。
我將把控件命名為StoreSelector.ascx。第一步是在表單上添加DropDownList控件。

(圖2)
現在就該為該控件“布線”了。創建一個Dataset類的對象:
#code private DataSet data; #end code |
創建向下拉列表中填寫數據的BindData功能:
#code private void BindData() { data = new DataSet(); SqlConnection cnn = new SqlConnection("Data Source=(local);Initial Catalog=pubs;Integrated Security=SSPI"); SqlDataAdapter adapter = new SqlDataAdapter(); adapter.SelectCommand = new SqlCommand("SELECT stor_id, stor_name,stor_address, city, state, zip FROM stores", cnn); adapter.Fill(data, "stores"); storeList.DataSource = data; storeList.DataMember = "stores"; storeList.DataTextField = "stor_name"; storeList.DataBind(); Session.Add("Data", data); } #end code |
我在Session變量上增加了DataSet對象,以使數據在對話存在期間以及控件事件觸發期間傳遞數據時都是可以訪問的。注意,要確保Page_OnLoad事件的正確:
#code private void Page_Load(object sender, System.EventArgs e) { if(!Page.IsPostBack) { BindData(); } } #end code |
現在我們將新控件拖到Default.aspx網頁上,并運行該項目。

(圖3)

(圖4)
很簡單是吧?下面就該是技巧比較高的部分了。我們希望在Default.aspx上添加幾個標簽,反映不斷變化的商店。我們希望每個標簽顯示現在選擇的商店中的一列,在這里我們就需要為StoreSelector控件和事件參數類創建一個定制事件。下面我們先創建Event Argument Class(StoreSelectorCommandEventArgs.cs):
#code public class StoreSelectorCommandEventArgs { private string _stor_id; private string _stor_name; private string _stor_address; private string _city; private string _state; private string _zip; public StoreSelectorCommandEventArgs(string stor_id, string stor_name, string stor_address, string city, string state, string zip) { _stor_id = stor_id; _stor_name = stor_name; _stor_address = stor_address; _city = city; _state = state; _zip = zip; } public string stor_id{ get{ return _stor_id; } } public string stor_name{ get{ return _stor_name; } } public string stor_address{ get{ return _stor_address; } } public string city{ get{ return _city; } } public string state{ get{ return _state; } } public string zip{ get{ return _zip; } } } #end code |
該類的目的是為了處理定義事件參數的“e”變量,我們要做的僅僅是創建了其中的一個。下面是定義如何處理事件的代理類(StoreSelectorCommandEventHandler.cs):
#code public delegate void StoreSelectorCommandEventHandler(object sender, StoreSelectorCommandEventArgs e); #end code |
下面是產生的文件:

(圖5)
現在我們來調整StoreSelector控件,觸發事件。
下面的代碼需要添加到StoreSelector控件中,才可能執行我們創建的事件:
#code public event StoreSelectorCommandEventHandler StoreSelectorChanged; protected virtual void OnStoreSelectorChanged(StoreSelectorCommandEventArgs e) { if(StoreSelectorChanged != null) StoreSelectorChanged(this, e); } #end code |
現在,我們已經為控件定義了事件,我們需要觸發該事件。我們計劃在DropDownList OnChange事件被觸發后觸發該事件。注意確保DropDownList控件的AutPostBack屬性被設置為真。

(圖6)
下面是事件的代碼:
#code private void storeList_SelectedIndexChanged(object sender, System.EventArgs e) { data = (DataSet)Session["Data"]; OnStoreSelectorChanged( new StoreSelectorCommandEventArgs (data.Tables["stores"].Rows[storeList.SelectedIndex].ItemArray[0].ToString (), data.Tables["stores"].Rows[storeList.SelectedIndex].ItemArray[1].ToString( ), data.Tables["stores"].Rows[storeList.SelectedIndex].ItemArray[2].ToString(), data.Tables["stores"].Rows[storeList.SelectedIndex].ItemArray[3].ToString(), data.Tables["stores"].Rows[storeList.SelectedIndex].ItemArray[4].ToString(), data.Tables["stores"].Rows[storeList.SelectedIndex].ItemArray[5].ToString( ))); } #end code |
我們來分析一下在這里所作的工作。當SelectedIndexChanged事件被觸發時,我將它傳遞給為控件創建的新事件,我傳送的數據直接與填寫的dataset相關,所有條目都一個一個地被傳遞給StoreSelectorCommandEventArgs對象,然后觸發事件。
為了訪問Default.aspx網頁的新功能,我們需要在該類的OnInit部分添加事件處理程序:

(圖7)
如上圖所示,StoreSelectorChanged事件出現在了Default.aspx網頁上。下面我們賦予它一個功能。我將在Default.aspx網頁上添加6個標簽,隨DropDownList的變化顯示值:

(圖8)
現在我們來編寫事件。
美觀是Intellisense是Intellisense認可定制的EventArg類屬性的原則:

(圖9)
最終的事件函數如下所示:
#code private void StoreSelector1_StoreSelectorChanged(object sender, Pubs.Controls.StoreSelectorCommandEventArgs e) { Label1.Text = e.stor_id; Label2.Text = e.stor_name; Label3.Text = e.stor_address; Label4.Text = e.city; Label5.Text = e.state; Label6.Text = e.zip; } #end code |
現在我們對該項目進行測試。該網頁一加載,讀者的頭腦中可能會閃現出這樣的念頭:它有問題,但我向你保證保證,該項目沒有任何問題。如果想在網頁一加載時就觸發該事件,我們必須通過設置DropDownList控件中有選擇的索引屬性在已經創建的控件中進行設置。

(圖10)
只要我們從DropDownList中選擇另一個Store,標簽就會發生變化:

(圖11)
現在我們使表單加載到第一個記錄。我們在StoreSelector控件上添加下面的屬性:
#Code public int SelectedIndex { get{ return storeList.SelectedIndex; } set { if(!Page.IsPostBack) { BindData(); } if(value < storeList.Items.Count) { storeList.SelectedIndex = value; OnStoreSelectorChanged( new StoreSelectorCommandEventArgs (data.Tables["stores"].Rows[value].ItemArray[0].ToString(), data.Tables["stores"].Rows[value].ItemArray[1].ToString(), data.Tables["stores"].Rows[value].ItemArray[2].ToString(), data.Tables["stores"].Rows[value].ItemArray[3].ToString(), data.Tables["stores"].Rows[value].ItemArray[4].ToString(), data.Tables["stores"].Rows[value].ItemArray[5].ToString())); } } } #End Code |
然后設置Default.aspx中Page_Load事件的屬性:
#code private void Page_Load(object sender, System.EventArgs e) { // 用戶初始化網頁的代碼 if(!Page.IsPostBack) { StoreSelector1.SelectedIndex = 0; } } #end code |
運行該項目時,它就會將表單加載到第一個記錄。
小結
希望這篇文章能夠對廣大讀者有一定的幫助。這種類型的Web應用程序的開發幾乎沒有什么限制,只要設計得當,我們創建的每個Web控件可以在整個Web應用程序中使用。