複合控制項的事件處理
本文節選自《庖丁解牛:縱向切入ASP.NET 3.5控制項和組件開發技術》一書
複合控制項的事件處理按實現功能可分為三種:
(1)複合控制項中子控制項的內部事件處理。
(2)包含處理機制—子控制項事件中調用主控制項委託的事件執行個體。
(3)冒泡處理機制。
接下來的三節就分別說明這三種事件處理方式機制是如何?的。
5.3.3.1 複合控制項中子控制項的內部事件處理
這是最簡單的處理方式。複合控制項中的子控制項事件是單獨存在的,與主控制項沒有任何關係,並且它們各自完成自己的功能,使用方法也很簡單,就像以往直接在頁面中使用事件一樣。
這一節主要以CalculatorControl控制項為樣本示範這種類型事件的用法。首先看一下控制項的運行,5-4所示。
這是一個標準的複合控制項,全部由子控制項構成。其中包含兩個表示運算運算元的TextBox,在下面有四個按鈕分別執行加減乘除的運算。原始碼如下:
/// <summary>
/// 獲得本書更多內容,請看:
/// http://blog.csdn.net/ChengKing/archive/2008/08/18/2792440.aspx
/// </summary>
[ToolboxData("<{0}:CalculatorControl runat=server></{0}:CalculatorControl>")]
public class CalculatorControl : CompositeControl
{
//運算元
private TextBox tb1;
private TextBox tb2;
//顯示結果
private Label lb;
//操作(+-*/)
private Button bt1;
private Button bt2;
private Button bt3;
private Button bt4;
private const string ResultText = "結果清單: ";
private Unit ButtonWidth = Unit.Pixel(30);
protected override void CreateChildControls()
{
tb1 = new TextBox();
tb1.ID = "TextBox1";
this.Controls.Add(tb1);
tb2 = new TextBox();
tb2.ID = "TextBox2";
this.Controls.Add(tb2);
lb = new Label();
lb.ID = "Label1";
lb.Text = ResultText;
this.Controls.Add(lb);
bt1 = new Button();
bt1.ID = "Button1";
bt1.Width = ButtonWidth;
bt1.Text = "+";
bt1.CommandArgument = "+";
bt1.Click += new EventHandler(bt_Click);
this.Controls.Add(bt1);
bt2 = new Button();
bt2.ID = "Button2";
bt2.Width = ButtonWidth;
bt2.Text = "-";
bt2.CommandArgument = "-";
bt2.Click += new EventHandler(bt_Click);
this.Controls.Add(bt2);
bt3 = new Button();
bt3.ID = "Button3";
bt3.Width = ButtonWidth;
bt3.Text = "*";
bt3.CommandArgument = "*";
bt3.Click += new EventHandler(bt_Click);
this.Controls.Add(bt3);
bt4 = new Button();
bt4.ID = "Button4";
bt4.Width = ButtonWidth;
bt4.Text = "/";
bt4.CommandArgument = "/";
bt4.Click += new EventHandler(bt_Click);
this.Controls.Add(bt4);
}
void bt_Click(object sender, EventArgs e)
{
try
{
if (ResultText != lb.Text)
{
lb.Text = lb.Text + ", ";
}
switch (((Button)sender).CommandArgument)
{
case "+": lb.Text = lb.Text + Convert.ToString(Convert.ToInt32 (this.tb1.Text) + Convert.ToInt32(this.tb2.Text)); break;
case "-": lb.Text = lb.Text + Convert.ToString(Convert.ToInt32 (this.tb1.Text) - Convert.ToInt32(this.tb2.Text)); break;
case "*": lb.Text = lb.Text + Convert.ToString(Convert.ToInt32 (this.tb1.Text) * Convert.ToInt32(this.tb2.Text)); break;
case "/": lb.Text = lb.Text + Convert.ToString(Convert.ToInt32 (this.tb1.Text) / Convert.ToInt32(this.tb2.Text)); break;
}
}
catch
{
lb.Text = "It's is not right format, please input again.";
}
}
protected override void Render(HtmlTextWriter writer)
{
writer.AddAttribute(HtmlTextWriterAttribute.Style, "padding: 10;
background-color: #C0C0FE; font-size: 12px; width:180px;
height: 160; vertical-align: top; text-align: center;");
writer.RenderBeginTag(HtmlTextWriterTag.Div);
writer.AddAttribute(HtmlTextWriterAttribute.Border, "0");
writer.AddAttribute(HtmlTextWriterAttribute.Cellpadding, "0");
writer.AddAttribute(HtmlTextWriterAttribute.Cellspacing, "0");
writer.AddAttribute(HtmlTextWriterAttribute.Valign, "middle");
writer.RenderBeginTag(HtmlTextWriterTag.Table);
//Operating item 1
writer.RenderBeginTag(HtmlTextWriterTag.Tr);
writer.RenderBeginTag(HtmlTextWriterTag.Td);
tb1.RenderControl(writer);
writer.RenderEndTag();
writer.RenderEndTag();
//<br>
writer.WriteBreak();
//Operating symbol
writer.RenderBeginTag(HtmlTextWriterTag.Tr);
writer.AddAttribute(HtmlTextWriterAttribute.Align, "left");
writer.RenderBeginTag(HtmlTextWriterTag.Td);
writer.WriteEncodedText(" + - * / ");
writer.RenderEndTag();
writer.RenderEndTag();
//Operating item2
writer.RenderBeginTag(HtmlTextWriterTag.Tr);
writer.RenderBeginTag(HtmlTextWriterTag.Td);
tb2.RenderControl(writer);
writer.RenderEndTag();
writer.RenderEndTag();
//Operating symbol
writer.RenderBeginTag(HtmlTextWriterTag.Tr);
writer.AddAttribute(HtmlTextWriterAttribute.Align, "left");
writer.RenderBeginTag(HtmlTextWriterTag.Td);
writer.WriteEncodedText(" EQUAL ");
writer.RenderEndTag();
writer.RenderEndTag();
//The relust label
writer.RenderBeginTag(HtmlTextWriterTag.Tr);
writer.AddAttribute(HtmlTextWriterAttribute.Align, "left");
writer.RenderBeginTag(HtmlTextWriterTag.Td);
lb.RenderControl(writer);
writer.RenderEndTag();
writer.RenderEndTag();
//Button1
writer.RenderBeginTag(HtmlTextWriterTag.Tr);
writer.RenderBeginTag(HtmlTextWriterTag.Nobr);
writer.RenderBeginTag(HtmlTextWriterTag.Td);
bt1.RenderControl(writer);
bt2.RenderControl(writer);
bt3.RenderControl(writer);
bt4.RenderControl(writer);
writer.RenderEndTag();
writer.RenderEndTag();
writer.RenderBeginTag(HtmlTextWriterTag.Tr);
writer.AddAttribute(HtmlTextWriterAttribute.Height, "10px");
writer.RenderBeginTag(HtmlTextWriterTag.Td);
writer.RenderEndTag();
writer.RenderEndTag();
writer.RenderEndTag();
writer.RenderEndTag();
}
}
代碼邏輯也比較簡單。運算按鈕的事件註冊採用標準的事件形式:
bt1.Click += new EventHandler(bt_Click);
void bt_Click(object sender, EventArgs e)
{
//… …
}
與以往不同的是這裡的事件註冊不是像往常一樣用在頁面(Page控制項)中,而是用在我們自訂的控制項中。
另外,因為四個按鈕的事件比較相似,所以讓它們共用一個事件執行個體bt_Click,在事件方法體通過Button的CommandArgument屬性區分單擊了哪個按鈕,從而決定執行哪種運算。
以上事件定義在控制項內部,由子控制項註冊和引用事件,即相當於事件的註冊和調用完全封裝在控制項內部,對開發人員不具有互動性,這樣的事件在開發中也會常常用到。
但是在複合控制項中,控制項被引發一個事件時,開發人員往往也想做自己的事情,這就需要把事件交給主控制項,由主控制項統一暴露事件,這樣開發人員在使用控制項時僅需要為主控制項註冊事件即可,剩下的由主控制項負責引發子控制項的事件或執行子控制項的某些功能,這裡就涉及主控制項與其子控制項的事件銜接問題,一般分為:包含法和冒泡法兩種處理方式。接下來的兩節就講解這兩種方法。