IPostBackDataHandler and IPostBackEventHandler in ASP.NET v2.0
In ASP.NET 1.1 if your custom control implemented both IPostBackDataHandler and IPostBackEventHandler interfaces, it had to manually call Page.RegisterRequiresRaiseEvent to get IPostBackEventHandler implementation (RaisePostBackEvent method) called. Or that's the general assumption and also defined as sort of rule in Developing ASP.NEt Server Controls and Components book.
Assuming I'm not now totally goofing with my tests (VS2005 RC), seems that this has changed in ASP.NET v2.0, at least so that it's easier to get to the control implementation in base classes. Take following control derived from TextBox (totally silly test but shows what I mean):
Namespace Test
Public Class MyTestTextBox
Inherits System.Web.UI.WebControls.TextBox
'TextBox already implements IPostBackDatahandler as it loads text from postback data
Implements IPostBackEventHandler
Public Sub RaisePostBackEvent(ByVal eventArgument As String) Implements System.Web.UI.IPostBackEventHandler.RaisePostBackEvent
Context.Trace.Write("RaisePostBackEvent from MyTestTextBox...")
End Sub
Protected Overrides Sub AddAttributesToRender(ByVal writer As System.Web.UI.HtmlTextWriter)
MyBase.AddAttributesToRender(writer)
'Add for testing that double-click to TB causes a postback
writer.AddAttribute("ondblclick", Page.ClientScript.GetPostBackEventReference(Me, ""))
End Sub
'We can get better to the derived postback data loading phase
'as these methods are overridable in v2
Protected Overrides Function LoadPostData(ByVal postDataKey As String, ByVal postCollection As System.Collections.Specialized.NameValueCollection) As Boolean
Context.Trace.Write("LoadPostData from MyTestTextBox...")
Return MyBase.LoadPostData(postDataKey, postCollection)
End Function
End Class
End Namespace
If you check the trace output after double-clicking to the TB on otherwise blank page, it is somewhat like this (at
Trace Information |
| Category |
Message |
From First(s) |
From Last(s) |
| aspx.page |
Begin PreInit |
|
|
| aspx.page |
End PreInit |
5,33587369344428E-05 |
0,000053 |
| aspx.page |
Begin Init |
9,5822234390125E-05 |
0,000042 |
| aspx.page |
End Init |
0,000158679385229128 |
0,000063 |
| aspx.page |
Begin InitComplete |
0,00018521907113893 |
0,000027 |
| aspx.page |
End InitComplete |
0,000213155582622931 |
0,000028 |
| aspx.page |
Begin LoadState |
0,000239695268532733 |
0,000027 |
| aspx.page |
End LoadState |
0,000465981011553144 |
0,000226 |
| aspx.page |
Begin ProcessPostData |
0,000499784190448786 |
0,000034 |
|
LoadPostData from MyTestTextBox... |
0,00175161927004689 |
0,001252 |
| aspx.page |
End ProcessPostData |
0,0019443811992865 |
0,000193 |
| aspx.page |
Begin PreLoad |
0,00198097802933054 |
0,000037 |
| aspx.page |
End PreLoad |
0,00201310501753715 |
0,000032 |
| aspx.page |
Begin Load |
0,00204160025925083 |
0,000028 |
| aspx.page |
End Load |
0,00210780979146791 |
0,000066 |
| aspx.page |
Begin ProcessPostData Second Try |
0,00213658439829643 |
0,000029 |
| aspx.page |
End ProcessPostData Second Try |
0,00216256535397655 |
0,000026 |
| aspx.page |
Begin Raise ChangedEvents |
0,00219022250034571 |
0,000028 |
| aspx.page |
End Raise ChangedEvents |
0,0022173209164852 |
0,000027 |
| aspx.page |
Begin Raise PostBackEvent |
0,00224218441170596 |
0,000025 |
|
RaisePostBackEvent from MyTestTextBox... |
0,0026690543071815 |
0,000427 |
| aspx.page |
End Raise PostBackEvent |
0,00271179716975202 |
0,000043 |
| aspx.page |
Begin LoadComplete |
0,00273945431612118 |
0,000028 |
| aspx.page |
End LoadComplete |
0,00276599400203098 |
0,000027 |
| aspx.page |
Begin PreRender |
0,00279253368794079 |
0,000027 |
| aspx.page |
End PreRender |
0,00283080670867387 |
0,000038 |
| aspx.page |
Begin PreRenderComplete |
0,00285958131550239 |
0,000029 |
| aspx.page |
End PreRenderComplete |
0,00288556227118251 |
0,000026 |
| aspx.page |
Begin SaveState |
0,00328728930632245 |
0,000402 |
| aspx.page |
End SaveState |
0,00348088933090658 |
0,000194 |
| aspx.page |
Begin SaveStateComplete |
0,00351413377957254 |
0,000033 |
| aspx.page |
End SaveStateComplete |
0,0035417909259417 |
0,000028 |
| aspx.page |
Begin Render |
0,00357335918391863 |
0,000032 |
| aspx.page |
End Render |
0,00412175290434958 |
0,000548 |
As you see, both implementations get called. On the other hand, I'm thinking that this implementation is also different in that as deriving from TextBox, there's always a value in form post collection (enough for IPostBackDataHandler) and double clicking the textbox always causes the control id to be found from __EVENTTARGET hidden field (__doPostBack call sets it, enough for IPostBackEventHandler), so that also explains why it works for both interfaces at the same.
If nothing else was learned here, I warmly welcome that Framework's base control classes provide overridable implementation, especially with postback data loading. With v1.1 , these were implemented purely with explicit interface implementation which made overriding bit difficult.