第一章 .Net 控件开发(WebForm) 开发简单自定义控件(8) 页面的回传

 1、 我们运行上章的页面,会按下按钮会发现我们写的事件无效,大家可能在上章写的时候已经发现了,只不过在写上章说明了下,只为了让控件增加个事件。为什么按下按钮无效呢?这意味着TestControl3控件没引发Test事件,也就同步说明控件没调用OnTest方法,因为OnTest方法的责任是引发事件。TestControl3控件无法获知页面回传以及希望其引发Test事件。页面负责通知服务器控件,已经发生回传,现在要考虑的是页面如何通知服务器控件告诉它页面已经回传了?每个Html元素都有一个name属性,当Html元素例如Submit按钮导致回传时,Html属性的name的值将被回传到服务器,以便服务器了解是哪个Html元素导致了回传。

2、 包含页面执行以下任务:(1)该页面返回导致回传的Html元素的name属性值,在TestControl3空间中,页面返回Btn_Show按钮的name属性值,因为Btn_Show导致回传的Html元素;(2)该页面检索控件树,查找其中那个与导致回传的Html元素的name属性具有相同值的服务器控件的UnqueID。在TestControl3控件中,页面会搜索UniqueID与Btn_Show按钮的name属性的值相同的服务器控件。(3)如果页面发现了具有指定UniqueID值的控件,那么它将检测该控件是否实现了IPostBackEventHandler接口,这个接口仅公开了一个RaisePostBackEvent方法。因此,实现该接口意味这控件公开了RaisePostBackEvent方法,如果控件实现了这个接口,那么页面将调用它的RaisePostBackEvent方法。控件在方法内实现的内容就是控件的任务。换言之,在调用RaisePostBackEvent方法之后,页面直到回传事件引发才会输出。

3、 关键是确认Btn_Show按钮的name属性与TestControl3控件的UniqueID属性具有相同的值,控件TestControl3继承了TestControl2,我们看下TestControl2的RenderContent的方法,下面代码显示了Btn_Show的部分代码,如代码里显示的ShowNameName属性值,与Btn_Show按钮的name属性具有相同的属性值。

 writer.RenderBeginTag(HtmlTextWriterTag.Tr);
            writer.AddAttribute(HtmlTextWriterAttribute.Colspan, "2");
            writer.AddAttribute(HtmlTextWriterAttribute.Align, "center");
            writer.RenderBeginTag(HtmlTextWriterTag.Td);
            writer.AddAttribute(HtmlTextWriterAttribute.Id, ShowNameId); 
            writer.AddAttribute(HtmlTextWriterAttribute.Type, "submit");
            writer.AddAttribute(HtmlTextWriterAttribute.Value, ShowNameLable);
            writer.AddAttribute(HtmlTextWriterAttribute.Name, ShowNameName);
            writer.RenderBeginTag(HtmlTextWriterTag.Input);
            writer.RenderEndTag();
            writer.RenderEndTag();
            writer.RenderEndTag();

 

protected virtual string ShowNameName
        {
            get { return "Btn_Show"; }
        }

4、 这表明了TestControl2的RenderContent方法将字符串“Btn_Show”设置为Btn_Show按钮的name属性值,现在就要确认Btn_Show按钮的name与TestControl2控件的UniqueID属性具有相同的值。问题是谁设置了控件的UniqueID的值?答案还是包含页面。因为Btn_Show按钮的name属性值与TestControl2控件的属性值是由两种不同的实体来设置,具体而言是RenderContent方法和包含页面,所以它们绑定值的方式不同。

5、 说了这么多理论的东西,也未必能了解和懂,总结起来归根到底就是,点击Btn_Show,控件TestControl3没有引发Test事件有两个原因,一是控件的UniqueID的值不等于字符串“Btn_Show”,这也就是页面搜索该UniqueID值的服务器控件失败的原因,因为我们看到ShowNameName这个属性是只读的只有包含页面才能设置,所以我们只能重写这个属性让控件返回UniqueID的值,重新定义个控件叫TestControl4继承TestControl3;第二个原因就是TestControl3没有事件我们上面所说的IPostBackEventHandler接口,这样就好理解了。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace WebFormControl
{
    public class TestControl4:TestControl3
    {
        protected override string ShowNameName
        {
            get
            {
                return this.UniqueID;
                //return base.ShowNameName;
            }
        }
    }
}

6、 由于TestControl4控件必须实现IPostBackEventHandler接口,该接口必须实现RaisePostBackEvent方法,显示实现IPostBackEventHandler接口,定义一个受保护的虚拟方法,以便调用。

void IPostBackEventHandler.RaisePostBackEvent(string eventArgument)
        {
            this.RaisePostBackEvent(eventArgument);
            //throw new NotImplementedException();
        }
 protected virtual void RaisePostBackEvent(string eventArgument)
        {
            TestEventArgs3 e = new TestEventArgs3(Name);
            OnTest(e);
        }

7、 RaisePostBackEvent之前,我们要定义1个属性和1个字段,Name属性是来保存文本框Txt_Name,HasName字段是来判断Txt_Name是否修改。

private bool HasName;
        protected virtual string Name
        {
            get { return ViewState["Name"] != null ? (string)ViewState["Name"] : string.Empty; }
            set { ViewState["Name"] = value; }
        }

8、 实现了RaisePostBackEvent方法,如何从方法中获取信息呢?控件还必须实现另外个接口IPostBackDataHandler接口,以便访问表单数据,该接口有两个方法要实现LoadPostData和RaosePostDataChangEvent。这里也显示实现IPostBackDataHandler接口,写两个受保护的虚拟方法调用。

bool IPostBackDataHandler.LoadPostData(string postDataKey, System.Collections.Specialized.NameValueCollection postCollection)
        {
            return this.LoadPostData(postDataKey, postCollection);
            //throw new NotImplementedException();
        }
void IPostBackDataHandler.RaisePostDataChangedEvent()
        {
            this.RaisePostDataChangedEvent();
            //throw new NotImplementedException();
        }

9、 当用户点击Btn_Show按钮,将表单数据回传给服务器,页面将调用LoadPostData方法,并将包含回传表单数据的NameVauleCollection类型的集合传递给该方法。这个集合针对每个Html元素都存储了一个对应的名称/值对,其中名称包括元素的name属性值,值包括回传给服务器的值。换言之,集合包括1个与TestControl4中的1个表单元素相对应的名称/值对。因此LoadPostData方法必须将每个Html元素的name属性值作为NameVauleCollection的索引,从而实现对相关元素的访问。

protected virtual bool LoadPostData(string postDataKey, System.Collections.Specialized.NameValueCollection postCollection)
        {
            string name = postCollection[NameName];
            if (name != Name)
            {
                Name = name;
                HasName = true;
            }
            if (!string.IsNullOrEmpty(postCollection[ShowNameName]))
                Page.RegisterRequiresRaiseEvent(this);
            return HasName;
        }

10、 LoadPostData方法返回一个bool值,当LoadPostData返回true时也就是说TestControl4属性发生了变化,页面才会调用RaosePostDataChangEvent方法。

protected virtual void RaisePostDataChangedEvent()
        {
            if (HasName)
            {
                //可以在这个写个事件针对文本框值变化时写个事件,我们这里就不写了,我们主要先实现我们第一章的效果
            }
        }

11、 把TestControl4拖到页面上按照上一章第5点设置,我们就可以实现我们的最开始的效果,点击按钮,弹出对话框(效果图详见第一章(1)的第1点)就是界面样式不一样哈。在成功的背后还是有个问题存在,如果我拖两个控件,看下Html源码就会发现问题,很多ID等属性一样了。在控件内这些属性都是唯一的,但是在页面里就不是了,如何在页面中保证Html元素的唯一呢?我们重写控件的属性让(UniqueID+”_”+原始名)来保证唯一性。我们在看下Html源码就不会出现重复了。

<table id="TestControl41" style="border-collapse:collapse;">
	<tr>
		<td>姓名</td><td><input id="Txt_Name" type="text" name="Txt_Name" /></td>
	</tr><tr>
		<td colspan="2" align="center"><input id="Btn_Show" type="submit" value="显示" name="TestControl41" /></td>
	</tr>
</table>
        <table id="TestControl1">
	<tr>
		<td>姓名</td><td><input id="Txt_Name" type="text" name="Txt_Name" /></td>
	</tr><tr>
		<td colspan="2" align="center"><input id="Btn_Show" type="submit" value="显示" name="TestControl1" /></td>
	</tr>
</table>
 protected override string ShowNameName
        {
            get
            {
                return this.UniqueID + "_Btn_Show";
                //return base.ShowNameName;
            }
        }

        protected override string ShowNameId
        {
            get
            {
                return this.UniqueID + "_Btn_Show";
            }
        }

        protected override string NameName
        {
            get
            {
                return this.UniqueID + "_Txt_Name";
            }
        }
        protected override string NameId
        {
            get
            {
                return this.UniqueID + "_Txt_Name";
            }
        }
 
<table id="TestControl41" style="border-collapse:collapse;">
	<tr>
		<td>姓名</td><td><input id="TestControl41_Txt_Name" type="text" name="TestControl41_Txt_Name" /></td>
	</tr><tr>
		<td colspan="2" align="center"><input id="TestControl41_Btn_Show" type="submit" value="显示" name="TestControl41_Btn_Show" /></td>
	</tr>
</table>
        <table id="TestControl1">
	<tr>
		<td>姓名</td><td><input id="TestControl1_Txt_Name" type="text" name="TestControl1_Txt_Name" /></td>
	</tr><tr>
		<td colspan="2" align="center"><input id="TestControl1_Btn_Show" type="submit" value="显示" name="TestControl1_Btn_Show" /></td>
	</tr>
</table>

代码下载地址:点击下载

本博客内容有些来源于网络或书籍如果侵害到你的权益,请及时联系我(hch458458@vip.qq.com)
版权归nethch所有,转载请注明出处!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值