[continued from an article 9 years ago] a pit and solution for dynamically creating controls

Ask questions Yesterday, a netizen raised suc...
Ask questions
Analyze problems
Review an article 9 years ago
solve the problem

Ask questions

Yesterday, a netizen raised such a question: dynamically create a Disabled text input box, and it is invalid to modify its text attribute when sending back the page:

Analyze problems

In order to analyze and solve the problem more clearly, let's show the code and running effect first.

<f:PageManager ID="PageManager1" runat="server"></f:PageManager> <f:SimpleForm runat="server" ID="SimpleForm1"> </f:SimpleForm> <f:Button ID="btnSetValue" runat="server" OnClick="btnSetValue_Click" Text="assignment"></f:Button>

The foreground code is simple:

1. A form SimpleForm1. The background will dynamically add controls to it

2. Click a button and send back

protected void Page_Init(object sender, EventArgs e) { TextBox t = new TextBox() { ID = "Text1", Label = "Dynamically created 1", Text = DateTime.Now.ToString(), Enabled = false, }; SimpleForm1.Items.Add(t); } protected void btnSetValue_Click(object sender, EventArgs e) { TextBox t = SimpleForm1.FindControl("Text1") as TextBox; t.Text = DateTime.Now.ToString(); }

The above is the simplified code:

1. A Page_Init event, in which a text input box is dynamically created and added to SimpleForm1.

2. A button click event, find the dynamically created text input box, and modify its value to the latest time.

Page display effect:

During actual operation, it is found that when clicking the [assignment] button, the value of the text input box on the page does not change.

It is suspected that the problem is Enabled=false

At first, this page also suspected that Enabled=false, so I changed the code to:

protected void Page_Init(object sender, EventArgs e) { TextBox t = new TextBox() { ID = "Text1", Label = "Dynamically created 1", Text = DateTime.Now.ToString(), Enabled = true, }; SimpleForm1.Items.Add(t); }

The test found no problem:

It seems that this is true. After debugging, it is found that if the text input box is disabled, the value of the text input box will not be submitted to the background. Compare it.

Enable text entry box:

Disable text entry box:

Does that mean that when the page is posted back, as long as we send back the disabled text input box value to the background, the problem will not be solved.

Is that so?

This can really solve the problem. Because ASP.NET looks for the postback data in the request parameters and updates the value of the control.

The key question is, is it compliant? Whether it conforms to the specification of HTML, the display is not.

HTML5 Spec - disabled form items do not appear in the form request

Refer to this article: https://stackoverflow.com/questions/7357256/disabled-form-inputs-do-not-appear-in-the-request

  HTML5 Spec clearly defines the behavior of disabled controls:

  1. Disabled controls do not receive focus
  2. Disabled controls are automatically skipped in Tab navigation
  3. Disabled controls do not appear in the request parameters for form submission

Another control test found that the problem is really not Disabled=false

Another way of thinking, we tested other controls, replaced TextBox with Label, and found the same problem:

protected void Page_Init(object sender, EventArgs e) { TextBox t = new TextBox() { ID = "Text1", Label = "Dynamically created 1", Text = DateTime.Now.ToString(), Enabled = false, }; SimpleForm1.Items.Add(t); Label l = new Label() { ID = "Label1", Label = "Dynamically created Label1", Text = DateTime.Now.ToString() }; SimpleForm1.Items.Add(l); } protected void btnSetValue_Click(object sender, EventArgs e) { TextBox t = SimpleForm1.FindControl("Text1") as TextBox; t.Text = DateTime.Now.ToString(); Label l = SimpleForm1.FindControl("Label1") as Label; l.Text = DateTime.Now.ToString(); }

After the test, it was found that the values of both controls did not change when the button was clicked.

Because the Label control is not a form field that can be modified by the user, its data will not be placed in the request parameters at all when the form is submitted. To put it bluntly, this logic is very similar to the disabled text input box.

After debugging, I found that to solve this problem, I still need to go back to the dynamic creation of controls.

I wrote an article 9 years ago to review it.

Review an article 9 years ago

This article 9 years ago explained the dynamic creation of controls in depth: https://www.cnblogs.com/sanshi/archive/2012/11/19/2776672.html

The life cycle of ASP.NET WebForms page is worth learning again:

  We are mainly concerned about the first four stages. We will review them in nine years. We can feel that the underlying design of WebForms is still very clever:

  1. Instantiation phase: handle page tag definition and page_ Code in init
  2. Postback - load view status: find hidden fields in the page__ VIEWSTATE and update the control properties
  3. Postback - load postback data: find the data in the request parameters and update the control properties (in this example, find the value of the text input box SimpleForm1$Text1 from the request parameters)
  4. Loading phase: execute page_ Code in load

It also seems clear that when the page is loaded for the first time, perform the following process:

  1. Instantiation: page tag + Page_Init
  2. Loading: Page_Load  

During page postback, perform the following process:

  1. Instantiation: page tag + Page_Init
  2. Load view state: hide fields from page__ Find in VIEWSTATE
  3. Load postback data: find from the request parameters of the current HTTP
  4. Loading: Page_Load  

If I am familiar with the above stages, I will ask a question:

__ How does the data in VIEWSTATE come from?

Here is a very key point. In that article nine years ago, I repeatedly mentioned:

When the control completes the [load view state phase], it will immediately start tracking the change of its view state, and any change to its properties will affect the final control view state.

Another implication of this sentence is that changes to control properties will not be tracked or recorded before the [load view status phase]   __ From VIEWSTATE.

More strictly speaking, the above statement is somewhat problematic because there is no [loading view status stage] when the page is loaded for the first time. A more accurate description:

  • When the page is loaded for the first time, after the control is added to the hierarchy tree, the state change is tracked and recorded in the__ VIEWSTATE
  • During page postback, after the [load view status phase], start tracking the status changes and record them in the__ VIEWSTATE
    • If the control is added to the hierarchy tree after the [load view status stage], start tracking the status change after adding the control to the hierarchy tree and record it to the__ VIEWSTATE

Let's take another look at the original code:

protected void Page_Init(object sender, EventArgs e) { TextBox t = new TextBox() { ID = "Text1", Label = "Dynamically created 1", Text = DateTime.Now.ToString(), Enabled = false, }; SimpleForm1.Items.Add(t); }

Problems can be found:

  1. When the page is first loaded
    1.   On Page_Init first assigns a value to text1: Text1.Text="2021-10-29 11:10:00"
    2. However, this assignment is performed before it is added to the hierarchy tree, so the Text1.Text value will not be recorded__ In VIEWSTATE
  2. After 10 minutes, when the page is posted back
    1. On Page_Init first assigns a value to text1: Text1.Text="2021-10-29 11:20:00"
    2. When loading view state, from  __ VIEWSTATE   Reply to the status before Text1, but  __ Not found in viewstate

Through the above detailed analysis, it can be seen that Text1 is set to 11:10 when the page is loaded for the first time. According to the truth, this value should be maintained during page postback, but it is incorrectly updated to 11:20!

How to assign values to dynamically added controls? We also propose a best practice:

solve the problem

If the above logic is clarified, it is not difficult to solve the problem:

protected void Page_Init(object sender, EventArgs e) { TextBox t = new TextBox() { ID = "Text1" }; SimpleForm1.Items.Add(t); } protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { TextBox t = SimpleForm1.FindControl("Text1") as TextBox; t.Label = "Dynamically created 1"; t.Enabled = false; t.Text = DateTime.Now.ToString(); } } protected void btnSetValue_Click(object sender, EventArgs e) { TextBox t = SimpleForm1.FindControl("Text1") as TextBox; t.Text = DateTime.Now.ToString(); }

Operation effect:

1 November 2021, 00:26 | Views: 7876

Add new comment

For adding a comment, please log in
or create account

0 comments