我的web控件开发经历(3)——button机制

button是用来接受用户在页面点击的。有些点击要把页面提交回服务端的。其实提交回服务端必然是基于类似这样的最简单的js: form1.submit()。问题是:服务端是如何知道页面上多个回传按钮中被点击的这一个呢?现在打算做一个最简单的button来看看:

public class button1:Control     {         protected override void Render(HtmlTextWriter writer)         {             writer.AddAttribute("type", "button");             writer.AddAttribute("value", this.UniqueID);             writer.AddAttribute("id", this.UniqueID);             writer.AddAttribute("onclick", Page.ClientScript.GetPostBackClientHyperlink(this, this.UniqueID));             writer.RenderBeginTag("input");             writer.RenderEndTag();         }     }

 在测试页面上把这个控件加上去。写如下代码:

protected void Page_Load(object sender, EventArgs e)     {         if (IsPostBack)                {             Response.Write(this.Request.Form["__EVENTARGUMENT"].ToString());         }     }

在浏览器中浏览测试页面,点击后,页面会显示 Button1_1。在浏览器查看源代码,可看到相关的:

<input type="button" value="Button1_1" id="Button1_1" οnclick="javascript:__doPostBack('Button1_1','Button1_1')" />     <div>

 <input type="hidden" name="__EVENTTARGET" id="__EVENTTARGET" value="" />  <input type="hidden" name="__EVENTARGUMENT" id="__EVENTARGUMENT" value="" /> </div> <script type="text/javascript"> <!-- 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>

这就是一句话:GetPostBackClientHyperlink  做到的。你需要注意页面上的两个隐藏域:__EVENTTARGET和__EVENTARGUMENT。

以上是客户端的提交机制。但asp.net的回发机制就不太清楚了:即一个<input type='submit' />引起的提交,与__EVENTTARGET和__EVENTARGUMENT是无关的。作为一个疑问吧。

接下来,继续完善这个控件,使点击它后做些处理。

protected void Page_Load(object sender, EventArgs e)     {         if (IsPostBack)         {             switch (Request.Form["__EVENTTARGET"])             {                 case "Button1_1":                     Button1_1_click();                     break;             }         }     } 

void Button1_1_click()     {         Response.Write("Button1_1_click");     }  

确实我们看到点击后的效果。但很显然页面代码很快就会很复杂了。条条道路通罗马,但要走好一点的路。如果想到用观察者模式,会使问题的逻辑清楚很多。你觉得一个页面与上面的一个按钮,应该是“按钮观察页面”还是“页面观察按钮”呢?我觉得是后者,就是说:页面是观察者,按钮是被观察者(可参考:http://www.cnblogs.com/zhenyulu/articles/73723.html一般来说:被观察者是观察者的成员)。使用委托和事件,我们可轻易的实现:

    public delegate void myHandle();

    public class button1:Control,IPostBackEventHandler     {         public event myHandle click;         public event EventHandler click2;         protected override void Render(HtmlTextWriter writer)         {             writer.AddAttribute("type", "button");             writer.AddAttribute("value", this.UniqueID);             writer.AddAttribute("id", this.UniqueID);             writer.AddAttribute("runat", "server");             writer.AddAttribute("onclick", Page.ClientScript.GetPostBackClientHyperlink(this, this.UniqueID));             writer.RenderBeginTag("input");             writer.RenderEndTag();         }

        #region IPostBackEventHandler 成员

        public void RaisePostBackEvent(string eventArgument)         {             if (click != null)             {                 click();             }

            if (click2 != null)             {                 click2(this,null);             }         }

        #endregion     }

页面代码:

protected void Page_Load(object sender, EventArgs e)     {         Button1_1.click+=new mybutton.myHandle(Button1_1_click);         Button1_1.click2 += new EventHandler(Button1_1_click2);     }

    void Button1_1_click2(object sender, EventArgs e)     {         Response.Write("Button1_1_click2");     } 

    protected void Button1_1_click()     {         Response.Write("Button1_1_click");     } 过程可描述为:页面注册按钮事件等候通知,按钮通知页面。myHandle不是常规的,只是让大家清楚机制与委托类型无关。接下来,所有的焦点集中在通知上。通知机制的关键在于IPostBackEventHandler。我们可以把页面代码加一个如下方法试一试:

protected override void RaisePostBackEvent(IPostBackEventHandler sourceControl, string eventArgument)     {         Response.Write("www");     }

点击看看。为什么有且仅有www。把page的私有方法反射出来:

private void RaisePostBackEvent(NameValueCollection postData) {     if (this._registeredControlThatRequireRaiseEvent != null)     {         this.RaisePostBackEvent(this._registeredControlThatRequireRaiseEvent, null);     }     else     {         string str = postData["__EVENTTARGET"];         bool flag = !string.IsNullOrEmpty(str);         if (flag || (this.AutoPostBackControl != null))         {             Control control = null;             if (flag)             {                 control = this.FindControl(str);             }             if ((control != null) && (control.PostBackEventHandler != null))             {                 string eventArgument = postData["__EVENTARGUMENT"];                 this.RaisePostBackEvent(control.PostBackEventHandler, eventArgument);             }         }         else         {             this.Validate();         }     } }

清楚吗:

有:是因为(control != null) && (control.PostBackEventHandler != null) 仅有:是因为this.RaisePostBackEvent(control.PostBackEventHandler, eventArgument)被我们重载了。

最后,我们还有一个<input type="submit" /> 的疑问。朋友能帮忙解释吗?它的回发机制是怎样的?

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值