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

来源:互联网 发布:重庆对外贸易数据分析 编辑:程序博客网 时间:2024/05/16 18:22

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" onclick="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" /> 的疑问。朋友能帮忙解释吗?它的回发机制是怎样的?

 

原创粉丝点击