IPostBackDataHandler and IPostBackEventHandler

I’ve been messing around with post back handler in ASP.NET today, and I
found out a few points of interest.  Firstly, a description of the
two interfaces used with server controls to handle post backs:

IPostBackEventHandler – Implemented by server controls that wish to handle post back events. The RaisePostBackEvent
method is invoked by the framework when the control that implements
this interface method is the source of a page post back – such as a
submit button.  The RaisePostBackEvent method is expected to call an event delegate on the control, suck as Click.

IPostBackDataHandler – Implemented by server controls that wish to handle posted form data state changes. The LoadPostData
method is invoked by the framework when the control that implements the
interface method has posted some form data.  This method should
compare the posted data (contained in a NameValueCollection, keyed with
a passed unique post data key) with the data internal to the control,
to see if the user changed the data on the page.  This method is
expected to return true if the state of the data has changed.  The
framework checks to return value of LoadPostData and calls the
RaisePostDataChangedEvent method if the return value was true.  The RaisePostDataChangedEvent methods is expected to call a changed event delegate on the control.

Below is is the source code to a couple of server controls that I had implemented to test these interfaces. 

public class MyButton : Control, IPostBackEventHandler
{
public string Text
{
get { return ViewState[“myText”] as string; }
set { ViewState[“myText”] = value; }
}

public delegate void ClickHandler(object sender);

public event ClickHandler Click;

public MyButton()
{

}

#region IPostBackEventHandler Members

public void RaisePostBackEvent(string eventArgument)
{
string res = eventArgument;
if (null != Click)
Click(this);

}

#endregion

protected override void Render(HtmlTextWriter writer)
{
writer.WriteLine(“”);
}

}

public class MyTB : Control, IPostBackDataHandler
{
private string VSID
{
get { return “myText” + this.UniqueID; }
}

public string Text
{
get { return ViewState[VSID] as string; }
set { ViewState[VSID] = value; }
}

public delegate void ChangedHandler(object sender);

public event ChangedHandler Changed;

#region IPostBackDataHandler Members

public bool LoadPostData(string postDataKey, System.Collections.Specialized.NameValueCollection values)
{
String presentValue = Text;
String postedValue = values[postDataKey];
if (!presentValue.Equals(postedValue))
{
Text = postedValue;
return true;
}
return false;
}

public void RaisePostDataChangedEvent()
{
if (null != Changed)
Changed(this);
}

#endregion

protected override void Render(HtmlTextWriter writer)
{
writer.WriteLine(“”);
}
}

Point #1:  Initially both controls were not working.  After
pulling out some hair, I figured out that each rendered control must
output a “name” attribute with a unique value. Without this attribute
the framework has no way of calling either the RaisePostBackEvent or LoadPostData
methods on the correct control instance. Adding an ID field is not
enough, for some reason ASP.NET insists on the “name” attribute.

Point #2: IPostBackDataHandler
makes no sense on controls that do not change their state between page
posts – duh.  Sounds obvious, but that still did not stop me
spending 20 minutes trying to figure out why this interface was not
working on my custom button control. 

Point #3: I wanted to know why the string argument passed to the RaisePostBackEvent
method was null when I rendered my custom button as a regular HTML form
submit button. Even though a simple submit button will cause a post
back or sort – after all a post back is essentially a form submission –
the framework will not interpret the form submit as a true post back
without the __doPostBack JavaScript call.  This JavaScript method
has the capacity to pass an argument to the framework during a form a
post.  Adding this method to my code was a simple case of
rendering the returned string from the GetPostBackEventReference method in an “onclick” attribute.

Point #4: When comparing posted data with that of the internal state of
the data in the control, using LoadPostData,
it helps if the control persists state
of its own data in the first place.  For example, when persisting
the text value in my custom text box I used the ViewState. Had I used a
private member variable to store the internal text value, the
persistence would have been lost for each post back; because a new
instance of each control on the page is loaded for each page request.

8 thoughts on “IPostBackDataHandler and IPostBackEventHandler

  1. http://

    Point #1: Initially both controls were not working. After pulling out some hair, I figured out that each rendered control must output a "name" attribute with a unique value. Without this attribute the framework has no way of calling either the RaisePostBackEvent or LoadPostData methods on the correct control instance. Adding an ID field is not enough, for some reason ASP.NET insists on the "name" attribute.
    <br>
    <br>The reason is
    <br>Upon postback, the page framework searches the posted content for values that match the UniqueIDs of server controls that implement

  2. Rob Garrett

    Correct, but why is the &quot;name&quot; attribute required, surely you’d expect they would match against the &quot;ID&quot; attribute.
    <br>
    <br>I understood that ASP.NET needs to something from the client to compare against controls in the tree, but was confused when I found out that MS chose the &quot;name&quot; attribute and not &quot;ID&quot;.

  3. http://

    Please check the following link
    <br><a target=”_new” href=”http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/cpconreceivingpostbackdatachangednotifications.asp”>http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/cpconreceivingpostbackdatachangednotifications.asp</a&gt;
    <br>and you can implement INamingContainer to ensures that child controls have unique IDs in the hierarchical tree of controls.
    <br><a target=”_new” href=”http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/cpconKeyConceptsInWebFormsControlDevelopment.asp”>http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/cpconKeyConceptsInWebFormsControlDevelopment.asp</a&gt;

  4. http://

    Hi Rob,
    <br>I had the same problem u were having in your Section #1, and after having investigated what exactly is wrapped in the form upon submission I found the following :
    <br>
    <br>—————————————————————————-
    <br>
    <br>17.13.3 Processing form data
    <br>When the user submits a form (e.g., by activating a submit button), the user agent processes it as follows.
    <br>
    <br>Step one: Identify the successful controls
    <br>Step two: Build a form data set
    <br>A form data set is a sequence of control-name/current-value pairs constructed from successful controls
    <br>
    <br>Step three: Encode the form data set
    <br>The form data set is then encoded according to the content type specified by the enctype attribute of the FORM element.
    <br>
    <br>Step four: Submit the encoded form data set
    <br>Finally, the encoded data is sent to the processing agent designated by the action attribute using the protocol specified by the method attribute.
    <br>
    <br>This specification does not specify all valid submission methods or content types that may be used with forms. However, HTML 4 user agents must support the established conventions in the following cases:
    <br>
    <br>If the method is &quot;get&quot; and the action is an HTTP URI, the user agent takes the value of action, appends a `?’ to it, then appends the form data set, encoded using the &quot;application/x-www-form-urlencoded&quot; content type. The user agent then traverses the link to this URI. In this scenario, form data are restricted to ASCII codes.
    <br>If the method is &quot;post&quot; and the action is an HTTP URI, the user agent conducts an HTTP &quot;post&quot; transaction using the value of the action attribute and a message created according to the content type specified by the enctype attribute.
    <br>For any other value of action or method, behavior is unspecified.
    <br>
    <br>User agents should render the response from the HTTP &quot;get&quot; and &quot;post&quot; transactions.
    <br>
    <br>17.13.2 Successful controls
    <br>A successful control is &quot;valid&quot; for submission. Every successful control has its control name paired with its current value as part of the submitted form data set. A successful control must be defined within a FORM element and must have a control name.
    <br>
    <br>However:
    <br>
    <br>Controls that are disabled cannot be successful.
    <br>If a form contains more than one submit button, only the activated submit button is successful.
    <br>All &quot;on&quot; checkboxes may be successful.
    <br>For radio buttons that share the same value of the name attribute, only the &quot;on&quot; radio button may be successful.
    <br>For menus, the control name is provided by a SELECT element and values are provided by OPTION elements. Only selected options may be successful. When no options are selected, the control is not successful and neither the name nor any values are submitted to the server when the form is submitted.
    <br>The current value of a file select is a list of one or more file names. Upon submission of the form, the contents of each file are submitted with the rest of the form data. The file contents are packaged according to the form’s content type.
    <br>The current value of an object control is determined by the object’s implementation.
    <br>If a control doesn’t have a current value when the form is submitted, user agents are not required to treat it as a successful control.
    <br>
    <br>Furthermore, user agents should not consider the following controls successful:
    <br>
    <br>Reset buttons.
    <br>OBJECT elements whose declare attribute has been set.
    <br>Hidden controls and controls that are not rendered because of style sheet settings may still be successful. For example:
    <br>
    <br>&lt;FORM action=&quot;…&quot; method=&quot;post&quot;&gt;
    <br>&lt;P&gt;
    <br>&lt;INPUT type=&quot;password&quot; style=&quot;display:none&quot;
    <br> name=&quot;invisible-password&quot;
    <br> value=&quot;mypassword&quot;&gt;
    <br>&lt;/FORM&gt;
    <br>
    <br>will still cause a value to be paired with the name &quot;invisible-password&quot; and submitted with the form.
    <br>
    <br>——————————————————————————
    <br>That’s the reason why the ID property is not enough, it has nothing to do with the framework itselt, it’s just how the forms submission model works. For more info go to :
    <br><a target=”_new” href=”http://www.w3.org/TR/REC-html40/interact/forms.html#form-data-set”>http://www.w3.org/TR/REC-html40/interact/forms.html#form-data-set</a&gt;
    <br>
    <br>

  5. http://

    Hi Rob,
    <br>
    <br>Just a point to add for #4. If I am not wrong, ViewStates are not why the values of the server controls persist during a postback. It is during the LoadPostData() method that the values are assigned. ViewStates only persist the PROPERTIES that are dynamically changed in the program codes but not the data in the control.
    <br>
    <br>For those server controls like textboxes, dropdownlist boxes..etc in a page, even when viewstate is set to false for the page, the data values in the controls will still be persisted across postback but not the Properties.
    <br>
    <br>
    <br>John Tan

  6. http://

    A little note on setting the “name” value when working with Composite Controls and INamingContainer is the following:

    You have to add the control to the Controls BEFORE you try and get the [control].ClientID. If you are nesting your controls all controls have to be added to Controls first so .NET can create the ClientID’s.

Comments are closed.