Introduction to the use of TextChanged events in asp.net textbox _ practical Skills

Source: Internet
Author: User

In the blog Park, a brother asked me a question about how dynamically created controls load view state and refer to calls to Processpostdata methods. Here I use the TextChanged event of the textbox to say the loading of view data and the triggering of events.

Let's start by looking at a demo:

The code is as follows:

Run the results as shown in figure:

Now let's change the value of the text box and click the button to submit the page to see what's going on.

The TextChanged event of the textbox occurs at this time, and the results of the operation are as follows:

Now we do nothing and click the button again to submit to see what the effect will be:

This is why the TextChanged event of the TextBox is not triggered at this time.

Do you know the conditions that trigger the TextChanged event of the textbox, so let's take a look at how the event was triggered today.

Here we first look at the definition of the textbox:

Copy Code code as follows:

public class Textbox:webcontrol, IPostBackDataHandler, IEditableTextControl, Itextcontrol

public interface IPostBackDataHandler
{
BOOL LoadPostData (String postdatakey, NameValueCollection postcollection);
void RaisePostDataChangedEvent ();
}
public interface Ieditabletextcontrol:itextcontrol
{
Event EventHandler TextChanged;
}
public interface Itextcontrol
{
String Text {get; set;}
}


Our main concern here is the implementation of the IPostBackDataHandler interface,
Copy Code code as follows:

Protected virtual bool LoadPostData (string postdatakey, NameValueCollection postcollection)
{
Base. Validateevent (Postdatakey);
string text = this. Text;
String str2 = Postcollection[postdatakey];
if (!this. ReadOnly &&!text. Equals (STR2, stringcomparison.ordinal))
{
This. Text = str2;
return true;
}
return false;
}

protected virtual void RaisePostDataChangedEvent ()
{
if (this. AutoPostBack &&!this. page.ispostbackeventcontrolregistered)
{
This. Page.autopostbackcontrol = this;
if (this. CausesValidation)
{
This. Page.validate (this. ValidationGroup);
}
}
This. OnTextChanged (Eventargs.empty);
}



The RaisePostDataChangedEvent method here is better understood, primarily by invoking the TextChanged event method, and the LoadPostData method can take the current value of the TextBox (the old value string text = this. text;) and the new value (Postcollection[postdatakey]), if the current textbox is not read-only and the old and new values are unequal, the new value is assigned to the TextBox's Text property, returns True, or returns false. Here we can guess whether the loadpostdata of the textbox returns true before we call the RaisePostDataChangedEvent method.

In the previous ASP.net page event handling pipeline We have mentioned two sections of the more special code, a section is to deal with the IPostBackDataHandler section is to deal with IPostBackEventHandler.
First of all, let's have a look.

Copy Code code as follows:

This. Oninitcomplete (Eventargs.empty);

if (context. traceisenabled)
{
This. Trace.Write ("Aspx.page", "End InitComplete");
}
if (this. IsPostBack)
{
if (context. traceisenabled)
{
This. Trace.Write ("Aspx.page", "Begin loadstate");
}
This. Loadallstate ();
if (context. traceisenabled)
{
This. Trace.Write ("Aspx.page", "End LoadState");
This. Trace.Write ("Aspx.page", "Begin processpostdata");
}
This. Processpostdata (This._requestvaluecollection, true);
if (context. traceisenabled)
{
This. Trace.Write ("Aspx.page", "End Processpostdata");
}
}
if (context. traceisenabled)
{
This. Trace.Write ("Aspx.page", "Begin preload");
}
This. Onpreload (Eventargs.empty);



This section, after InitComplete, preload before we are dealing with the IPostBackDataHandler interface, here is mainly a loadallstate and Processpostdata method.

First we need to know what the _requestvaluecollection here is, in fact, very simple, if the post is mainly this._request. Form (some of which filter processing, such as filtering out __viewstate ", __eventtarget), if a GET request has a QueryString collection is this._request. QueryString is this._request. QueryString.

The main band code for Loadallstate is as follows:

Copy Code code as follows:

View Code
? private void Loadallstate ()
{
Object obj2 = this. LoadPageStateFromPersistenceMedium ();
IDictionary-i = null;
Pair second = null;
Pair Pair2 = obj2 as Pair;
if (obj2!= null)
{
i = Pair2. The IDictionary;
Second = Pair2. Second as Pair;
}
if (!= null)
{
This._controlsrequiringpostback = (ArrayList) first["__controlsrequirepostbackkey__"];
if (this._registeredcontrolsrequiringcontrolstate!= null)
{
foreach (Control in (IEnumerable) this._registeredcontrolsrequiringcontrolstate)
{
Control. Loadcontrolstateinternal (First[control. UniqueID]);
}
}
}
if (second!= null)
{
string s = (string) second. A;
int num = Int. Parse (S, numberformatinfo.invariantinfo);
this._fpagelayoutchanged = num!= this. GetTypeHashCode ();
if (!this._fpagelayoutchanged)
{
Base. Loadviewstaterecursive (second. Second);
}
}
}
Protected internal Virtual Object LoadPageStateFromPersistenceMedium ()
{
PageStatePersister PageStatePersister = this. PageStatePersister;
Try
{
Pagestatepersister.load ();
}
catch (HttpException exception)
{
if (This._pageflags[8])
{
return null;
}
exception. Webeventcode = 0xbba;
Throw
}
return new Pair (Pagestatepersister.controlstate, pagestatepersister.viewstate);
}
internal void Loadchildviewstatebyid (ArrayList childstate)
{
int count = Childstate.count;
for (int i = 0; i < count; i + + 2)
{
String id = (string) childstate[i];
Object savedstate = childstate[i + 1];
Control control = this. FindControl (ID);
if (Control!= null)
{
Control. Loadviewstaterecursive (savedstate);
}
Else
{
This. Ensureoccasionalfields ();
if (this._occasionalfields.controlsviewstate = null)
{
This._occasionalfields.controlsviewstate = new Hashtable ();
}
This._occasionalfields.controlsviewstate[id] = savedstate;
}
}
}


The Loadallstate method notes that the ControlState and viewstate data for each control are loaded, and that the data source is obtained through the LoadPageStateFromPersistenceMedium method. The data class capacity is the ControlState data and viewstate data of the controls in the last response.

Next we should look at the Processpostdata method,

Copy Code code as follows:

private void Processpostdata (NameValueCollection postdata, bool fbeforeload)
{
if (this._changedpostdataconsumers = null)
{
This._changedpostdataconsumers = new ArrayList ();
}
if (postdata!= null)
{
foreach (String str in postdata)
{
if (str!= null) &&! Issystempostfield (str))
{
Control control = this. FindControl (str);
if (control = null)
{
if (fbeforeload)
{
if (This._leftoverpostdata = null)
{
This._leftoverpostdata = new NameValueCollection ();
}
This._leftoverpostdata.add (str, NULL);
}
}
Else
{
IPostBackDataHandler Postbackdatahandler = control. Postbackdatahandler;
if (Postbackdatahandler = null)
{
if (control. Postbackeventhandler!= null)
{
This. Registerrequiresraiseevent (Control. Postbackeventhandler);
}
}
Else
{
if (Postbackdatahandler!= null)
{
NameValueCollection postcollection = control. Calculateeffectivevalidaterequest ()? This._requestvaluecollection:this._unvalidatedrequestvaluecollection;
if (Postbackdatahandler.loadpostdata (str, postcollection))
{
This._changedpostdataconsumers.add (Control);
}
}
if (this._controlsrequiringpostback!= null)
{
This._controlsrequiringpostback.remove (str);
}
}
}
}
}
}
ArrayList list = null;
if (this._controlsrequiringpostback!= null)
{
foreach (String str2 in This._controlsrequiringpostback)
{
Control Control2 = this. FindControl (STR2);
if (control2!= null)
{
IPostBackDataHandler adapterinternal = control2. Adapterinternal as IPostBackDataHandler;
if (adapterinternal = null)
{
Adapterinternal = control2 as IPostBackDataHandler;
}
if (adapterinternal = null)
{
throw new HttpException (SR. GetString ("Postback_ctrl_not_found", new object[] {str2}));
}
NameValueCollection values2 = control2. Calculateeffectivevalidaterequest ()? This._requestvaluecollection:this._unvalidatedrequestvaluecollection;
if (Adapterinternal.loadpostdata (str2, Values2))
{
This._changedpostdataconsumers.add (control2);
}
}
else if (fbeforeload)
{
if (list = = null)
{
List = new ArrayList ();
}
List. ADD (STR2);
}
}
This._controlsrequiringpostback = list;
}
}

We first find our control controls based on the key of the parameter NameValueCollection you create, but the controls that are dynamically created in load are not found here. This method is divided into two parts, with the ArrayList list = null; This code is separate, and if you find a way to see if it's not a postbackdatahandler type, if it's not And its postbackeventhandler is not empty, then we call it directly to this. Registerrequiresraiseevent (Control. Postbackeventhandler) method, if it is a postbackeventhandler type of control, we call its LoadPostData method directly,
Copy Code code as follows:

if (Postbackdatahandler.loadpostdata (str, postcollection))
{
This._changedpostdataconsumers.add (Control);
}

Remove the control from the _controlsrequiringpostback collection at the same time
Copy Code code as follows:

if (this._controlsrequiringpostback!= null)
{
This._controlsrequiringpostback.remove (str);
}

The second part of the method is to iterate through the collection in Controlsrequiringpostback, which is similar to the previous section, except that the ID of the control is not found and recorded
Copy Code code as follows:

else if (fbeforeload)
{
if (list = = null)
{
List = new ArrayList ();
}
List. ADD (STR2);
}

By default, _controlsrequiringpostback is a control that contains dynamically created. Let's talk about the collection here, too.

The Controlsrequiringpostback setting is the code in the Loadallstate method:

This._controlsrequiringpostback = (ArrayList) first["__controlsrequirepostbackkey__"]; There is a loadallstate (load data state) there is saveallstate (save the Data state), in the saveallstate has such a code:

Dictionary. ADD ("__controlsrequirepostbackkey__", this._registeredcontrolsthatrequirepostback);

Where the _registeredcontrolsthatrequirepostback set is defined in the Registerrequirespostback method.

Copy Code code as follows:

public void Registerrequirespostback (Control control)
{
if (!) ( Control is IPostBackDataHandler) &&! (Control. Adapterinternal is IPostBackDataHandler))
{
throw new HttpException (SR. GetString ("Ctrl_not_data_handler"));
}
if (This._registeredcontrolsthatrequirepostback = null)
{
This._registeredcontrolsthatrequirepostback = new ArrayList ();
}
This._registeredcontrolsthatrequirepostback.add (Control. UniqueID);
}

In short, the dynamically added controls here are not able to load the data, but other default controls can be handled here.

Now let's see how the controls are added, and there's a Addedcontrol method in the control class that really adds the controls:

Copy Code code as follows:

protected internal virtual void Addedcontrol (control control, int index)
{
if (control. Ownercontrol!= null)
{
throw new InvalidOperationException (SR. GetString ("substitution_notallowed"));
}
if (control._parent!= null)
{
Control._parent. Controls.remove (Control);
}
Control._parent = this;
Control._page = this. Page;
Control.flags.Clear (0x20000);
Control NamingContainer = this.flags[0x80]? This:this._namingcontainer;
if (NamingContainer!= null)
{
Control. Updatenamingcontainer (NamingContainer);
if ((control._id = null) &&!control.flags[0x40])
{
Control. Generateautomaticid ();
}
else if ((control._id!= null) | | (Control._controls!= null))
{
Namingcontainer.dirtynametable ();
}
}
if (this._controlstate >= controlstate.childreninitialized)
{
Control. Initrecursive (NamingContainer);
if ((control._controlstate >= controlstate.initialized) && (control. Rarefields!= null)) && control. Rarefields.requiredcontrolstate)
{
This. Page.registerrequirescontrolstate (Control);
}
if (this._controlstate >= controlstate.viewstateloaded)
{
Object savedstate = null;
if ((This._occasionalfields!= null) && (this._occasionalfields.controlsviewstate!= null))
{
savedstate = This._occasionalfields.controlsviewstate[index];
if (this. Loadviewstatebyid)
{
Control. Ensureid ();
savedstate = This._occasionalfields.controlsviewstate[control.id];
This._occasionalfields.controlsviewstate.remove (control.id);
}
Else
{
savedstate = This._occasionalfields.controlsviewstate[index];
This._occasionalfields.controlsviewstate.remove (index);
}
}
Control. Loadviewstaterecursive (savedstate);
if (this._controlstate >= controlstate.loaded)
{
Control. Loadrecursive ();
if (this._controlstate >= controlstate.prerendered)
{
Control. Prerenderrecursiveinternal ();
}
}
}
}
}

There is a call to this in this method. Page.registerrequirescontrolstate (Control) and control. Loadviewstaterecursive (savedstate) method, a responsible for the controlstate of a responsible viewstate data loading, when we here 2nd and 3 times post requests, Creating the Textboxt control at load loads its existing control state and view state.
Now let's take a look at the section of code that handles IPostBackEventHandler in ProcessRequestMain:
Copy Code code as follows:

This. Loadrecursive ();
if (context. traceisenabled)
{
This. Trace.Write ("Aspx.page", "End Load");
}
if (this. IsPostBack)
{
if (context. traceisenabled)
{
This. Trace.Write ("Aspx.page", "Begin processpostdata Second Try");
}
This. Processpostdata (This._leftoverpostdata, false);
if (context. traceisenabled)
{
This. Trace.Write ("Aspx.page", "End Processpostdata Second Try");
This. Trace.Write ("Aspx.page", "Begin Raise changedevents");
}
This. Raisechangedevents ();
if (context. traceisenabled)
{
This. Trace.Write ("Aspx.page", "End Raise changedevents");
This. Trace.Write ("Aspx.page", "Begin Raise postbackevent");
}
This. RaisePostBackEvent (this._requestvaluecollection);
if (context. traceisenabled)
{
This. Trace.Write ("Aspx.page", "End Raise postbackevent");
}
}
if (context. traceisenabled)
{
This. Trace.Write ("Aspx.page", "Begin loadcomplete");
}
This. Onloadcomplete (Eventargs.empty);

First, let's look at what the _leftoverpostdata collection is, which is that a collection of IDs for the control was not found when the Processpostdata method was previously invoked. Here you can find the control, the main route of execution is the ArrayList list = null after the sentence, the end is to call
Copy Code code as follows:

if (Adapterinternal.loadpostdata (str2, Values2))
{
This._changedpostdataconsumers.add (control2);
}

This method, where the second call to the Processpostdata method is mainly to handle the event problem of dynamically creating the control.

Here, let's look at the Raisechangedevents method:

Copy Code code as follows:

internal void raisechangedevents ()
{
if (this._changedpostdataconsumers!= null)
{
for (int i = 0; i < This._changedpostdataconsumers.count; i++)
{
Control control = (control) this._changedpostdataconsumers[i];
if (Control!= null)
{
IPostBackDataHandler Postbackdatahandler = control. Postbackdatahandler;
if ((Control = null) | | control. Isdescendentof (This) && (Control!= null) && (control. Postbackdatahandler!= null))
{
Postbackdatahandler.raisepostdatachangedevent ();
}
}
}
}
}

I thought about the implementation of the TextChanged event in the TextBox. You should be very clear. And the RaisePostBackEvent method does not say, look at the code everyone will understand,
Copy Code code as follows:

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 ();
}
}
}

Here we are recalling that the state information of the general control is saved through the Saveallstate method, and the loading state information is the Loadallstate method before the InitComplete, preload, The data loaded is the last time the Saveallstate method was requested to save the data, the loading state calls the Processpostdata method to process the post data, dynamically added controls will load the state data the second time and every time after the request is added, To be straightforward, a dynamically added control loads its state data when it is added. After the load, before LoadComplete is we handle the control's event invocation problem, here we call again Processpostdata to handle the dynamically created control and post data, and then call Raisechangedevents, The RaisePostBackEvent method pulls up the event calls in IPostBackDataHandler, IPostBackEventHandler.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.