对IPostBackDataHandler和IPostBackEventHandler冲突问题的理解

  在ASP.NET下开发自定义控件,一般情况下都会实现IPostBackEventHandler接口,以期在生命周期中能执行RaisePostBackEvent方法,如果控件还需要支持数据变更响应的话,就会让控件再去实现IPostBackDataHandler接口,以期在生命周期中通过LoadPostData方法触发RaisePostDataChangedEvent。这么做了后编译虽然会通过,但会发现原来的RaisePostBackEvent方法突然不再执行了。


  解决这个问题常有两种办法:
  第一种办法:在LoadPostData函数中调用Page.RegisterRequiresRaiseEvent(this);强制控件的RaisePostBackEvent方法执行。
  第二种办法稍显复杂,改原来的submit提交方式为_DoPostBack提交方式。(这么做可以解决RaisePostBackEvent不执行的问题,但多数情况下可能会带了LoadPostData不执行的问题,在自定义控件中追加一个hidden的内容,name值等于UniqueID即可)。

 

  为什么会这样呢,说一下个人的理解,不一定准确(查阅了部分资料,没有找到官方或权威的支撑)
  1.PostBack后,页框架将上传上来的postCollection与服务器端控件进行比对来决定触发事件。比对的是postCollection中的Key和服务器端控件的UniqueID;触发的先是IPostBackDataHandler接口的LoadPostData,而后才是IPostBackEventHandler接口的RaisePostBackEvent。
  2.对于postCollection的内容来源,假定客户端有很多可能引起PostBack的控件(Button、Submit以及通过_DoPostBack实现PostBack的其他控件,如CheckBox、Select、HyperLink等),由于Button、Submit这一类的控件并不承担客户端数据采集的职责,故默认情况下PostBack时它们并不会收录到postCollection中。为了能够在服务器端能够识别是谁发动的PostBack,当点击Button/Submit等时,被点击的控件(仅此一个)会被收录,举例来说:一个包含button1、button2、button3三个按钮的页面,当点击button2提交时,button2的name及value会被收录到postCollection中,但button1和button3则不会。而如果某一个CheckBox通过_DoPostBack完成PostBack时,由于三个按钮都不是触发者,所以它们都没有被收录,同时_DoPostBack方法的第一个参数因为赋值给了EVENTTARGET而被间接收入到postCollection中(即Key为EVENTTARGET,value为name)。
  3.下面谈一下对流程的理解:
  第一步.页框架检索postCollection中的Keys,如果Key对应的控件实现了IPostBackDataHandler接口,那么就会调用其LoadPostData方法,这里页框架不会为EVENTTARGET项做额外的工作,即即使EVENTTARGET中有一个控件UniqueID,且对应控件也实现了IPostBackDataHandler,页框架也不会调用它的LoadPostData方法,这也是上面说的第二种解决办法的由来(在自定义控件中追加一个name值等于UniqueID的hidden标记,使得postCollection中有Key为UniqueID)。
  第二步.页框架继续检索Keys,对于第一步中检索出来的Keys,页框架认为这些Keys是为IPostBackDataHandler准备的,而不是为IPostBackEventHandler准备的。所以对于这些Keys,不会触发RaisePostBackEvent,于是就出现了同时实现两个接口的控件RaisePostBackEvent不执行的现象。第一个解决办法正是在LoadPostData中直接明确本控件将强制执行RaisePostBackEvent来解决问题的。
  继续,对于第一步中剩下的没有实现IPostBackDataHandler接口的Keys,如果其实现了IPostBackEventHandler接口,原则上RaisePostBackEvent是会执行的,但是在同一个页面中,RaisePostBackEvent只能运行在一个控件上,所以如果剩下的这些Keys中有多个实现了IPostBackEventHandler接口的话,那么只有postCollection中的最后一个会执行RaisePostBackEvent。而如果剩余的Keys中都没有实现IPostBackEventHandler接口,那么这时候就会取EVENTTARGET的内容继而去判断其是否实现了IPostBackEventHandler接口,有则执行它的RaisePostBackEvent。

posted on 2010-10-23 13:44  武汉虫虫  阅读(560)  评论(0编辑  收藏  举报

导航