Click here to Skip to main content
14,384,168 members
Rate this:
Please Sign up or sign in to vote.
See more:
I am trying to assign a value to a read-only TextBox which is lodged inside a DataGrid in a webpage. The TextBox is being reconstructed with each Postbox using automation called Add_TextBoxes. The TextBoxes inside the DataGrid can either be modified themselves by making an entry within the box (calls a method, TextBox_Changed) which is assigned idndividually, dynamically to each TextBox when they are created, or else via the automation which is causing me the problem. The automated call to update the textboxes within the grid is anchored inside longer textboxes, which are parsed based on a certain logic to distribute pieces of the Text (Substrings) to each of the textboxes in the grid. The problem I am having is that the textboxes inside the Grid are not being found. I am getting a Null Error exception. Here are some snippets of Code -

Inside my Page_Load (nested IF to call adding textboxes to Grid after Postback)

   else if (Session["SrcCtrl"].ToString() == "Noms")
    {
        this.Add_TxtBoxes();
        this.parse_Nomkey();
    }
}


Here is the Add_TxtBoxes method:

protected void Add_TxtBoxes()

        {

            List<sessVar> sessVars = ret_sv_data();
            int rw = 0;
            int cl = 0;

            // Cursor through all 31 positions

            for (int i = 0; i <= 30; i++)
            {

                //  Check to see if a new row for the data table / data grid is needed, - skipped on first iteration (row = 0)

                if (i > 0)
                {
                    if (newRow(sessVars[i].Nompos) == true)
                    {
                        rw = rw + 1;
                    }
                }

                //  Check to see if a column change is needed (col + 2), as we move through each component of the nomenclature

                if (i >= 1)
                {
                    if (sessVars[i - 1].Keyvis == false)
                    {
                        rw = 0;
                        cl = cl + 2;
                    }
                }

                //  If session variable is visible in the grid, add its text box and description one column over

                if (sessVars[i].Keyvis == true)
                {
                    Control thsctrl = this.FindControl("txtBoxNomPt" + rw + cl);

                    TextBox txtBxNm = new TextBox();
                    txtBxNm.Width = 48;
                    txtBxNm.ID = "txtBoxNomPt" + rw + cl;
                    txtBxNm.AutoPostBack = true;
                    txtBxNm.Attributes.Add("runat", "server");
                    txtBxNm.TextChanged += new EventHandler(TextBox_TextChanged);
                    this.NomFlds.Rows[rw].Cells[cl].Controls.Add(txtBxNm);
                    {
                        if (!string.IsNullOrEmpty(sessVars[i].Value as string) || sessVars[i].Svexists == true)
                        {
                            txtBxNm.Text = sessVars[i].Value.ToString();
                            if (sessVars[i].Value.Substring(0, 1).ToString() == "*")
                            {
                                this.NomFlds.Rows[rw].Cells[cl + 1].Text = sessVars[i].PosDesc.ToString();
                            }
                            else
                            {
                                TextBox_TextChanged(txtBxNm, EventArgs.Empty);
                                txtBxNm.Text = Session[sessVars[i].Sessnm].ToString();
                            }
                        }
                    }
                }
            }
        }



Here is the method for assigning a TextBox within the Grid a value after a user has updated one of the longer String 'macro' textboxes and tabbed out to start the parsing sequence -

public void parse_str_arr(int[] pos, string[] cts, string inp_str)
  {
      int startpt = 0;
      String thsval = "";
      for (int i = 0; i < pos.Length; i++)
      {
          if (pos[i] != -1)
          {
              string prow = cts[i].Substring(0, 1).ToString();
              int ctrw = Int32.Parse(prow);
              GridViewRow thsrow = this.NomFlds.Rows[ctrw];
              String ctrlnm = "txtBoxNomPt" + cts[i].ToString();
              Control thsfld = this.FindControl(ctrlnm);
             // Control [] thsfldarr = Retr_Set(ctrlnm, ctrlnm.Length);
             // Control thsfld = thsfldarr[1];
              TextBox thsfldtxt = thsfld as TextBox;
              if (inp_str.Length >= (startpt + PoslengthA[i]))
              {
                  thsval = inp_str.Substring(startpt, PoslengthA[i]).ToString();
                  thsfldtxt.Text = thsval;
                  TextBox_TextChanged(thsfld, EventArgs.Empty);
                  Session[SessnameA[pos[i]]] = thsval;
              }
              else
              {
                  thsval = ValueA[pos[i]];
                  thsfldtxt.Text = thsval;
                  TextBox_TextChanged(thsfld, EventArgs.Empty);
                  Session[SessnameA[pos[i]]] = thsval;
              }
              startpt = startpt + PoslengthA[pos[i]];

          }
      }
  }



Here is where my error is occurring. The Control thsfldtxt is not being found. In Rendering I can see the textboxes and I know they are there. But I am not finding them. Either there are hidden postbacks which are blowing away the names or else I have a syntax issue somewhere. I wrote a function to reassign the names but I am not sure where to build it in. This one has really got me on the run!

I use a great number of arrays to control this application because it is a lot of string manipulation using fixed rules. So if there are questions about the arrays and their function, feel free to ask.

What I have tried:

Tried to use a cool tool I found on the NET for getting at controls inside DataGrids called FlattenHierarchy which is supposed to remove the data container issue for finding a Control which is nested but that didn't work either.
Posted
Updated 4-Nov-19 3:53am
v2
Rate this:
Please Sign up or sign in to vote.

Solution 2

Please read about lifecycles, roundtrips and viewstates. The problem you run into is you assume the control to be persistent after postback. So when you look into your html you see the TextBox but after you've done some postback it is no longer existent, only the viewstate of it. So in order to get the value you want to access you have to create the control with the SAME ID on each postback and .NET will assign the viewstate to it.

Working example

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security;
using System.Text;
using System.Threading.Tasks;
using Microsoft.VisualBasic;
using System.Data;

partial class _Default : System.Web.UI.Page
{
    private DataSet ds;
    protected void Button1_Click(object sender, System.EventArgs e)
    {
        Label lbl;
        Label lbltext;
        TextBox txt;
        foreach (GridViewRow r in gvIndex.Rows)
        {
            lbl = r.FindControl("lblID");
            lbltext = r.FindControl("lblText");
            txt = r.FindControl(string.Concat("txt", lbl.Text));
            lbltext.Text = txt.Text;
        }
    }

    protected void Page_Load(object sender, System.EventArgs e)
    {
        if (!this.IsPostBack)
        {
            DataTable dt = new DataTable();
            ds = new DataSet();
            dt.Columns.Add("ID", typeof(string));
            dt.Rows.Add("1");
            dt.Rows.Add("2");
            dt.Rows.Add("3");
            dt.Rows.Add("4");
            dt.AcceptChanges();
            ds.Tables.Add(dt);

            this.gvIndex.DataSource = ds.Tables[0];
            this.gvIndex.DataBind();
        }
        CreateTextBoxes();
    }


    public void CreateTextBoxes()
    {
        Label lbl;
        TextBox txt;
        foreach (GridViewRow r in gvIndex.Rows)
        {
            lbl = r.FindControl("lblID");
            txt = new TextBox();
            txt.ID = string.Concat("txt", lbl.Text);
            r.Cells(0).Controls.Add(txt);
        }
    }
}


and the controls:

<body>
    <form id="form1" runat="server">
    <div>
        <asp:GridView ID="gvIndex" runat="server" AutoGenerateColumns="False">
            <Columns>
                <asp:TemplateField>
                    <ItemTemplate>
                        <asp:Label ID="lblID" runat="server" Text='<%# Eval("ID") %>'></asp:Label>
                        <asp:Label ID="lblText" runat="server"></asp:Label>
                    </ItemTemplate>
                </asp:TemplateField>
            </Columns>
        </asp:GridView>
        <asp:Button ID="Button1" runat="server" Text="Create" />
    </div>
    </form>
</body>


The controls are added dynamically on each page_load, there are several ways to transport the information of IDs, e.g. in Viewstate or Session object. So in your case after you know the IDs of the controls you added save them in a viewstate or session object (or database), recreate it on next postback and you will find them.
   
Comments
Ray Fischer 4-Nov-19 10:57am
   
Okay, I found the source of the error and it was definitely going in the direction of ST0rmi's post (with a little help from Rick). I have a bunch of session variables which are constantly being regenned based on each of the individual (smaller) textboxes which in turn feed the larger fields to be parsed later on in the code. They were overwriting the field's contents within the statebag multiple times(!). Thus when I went to parse my string, it had reverted itself back to its old (prechanged) form. In terms of the TextBox not being found, this appeared to be a container problem. I was in fact recreating them with each postback and giving them the correct Name. But I was searching at page level and I needed to search at DataRow Level. There was also this very strange phenomenon of them not having the string I was looking for as an ID but rather as a UniqueID. I found some stuff online about this but can't really understand the difference.
St0rmi 5-Nov-19 7:41am
   
The thing is, every DOM element needs a unique ID. So if you are using a datagrid which repeats data, this means if you have a textbox1 in a datarow, this will be repeated for every row. So in order to make it work, there is a container "datarow1" for the 1st row which has a container "datagridxy" and the UniqueID of the TextBox changes to "xxx_datagrid1_datagridxy_textbox1_1" (or similar). But if you are in codebehind, you are able to access that TextBox as "Textbox1" if you already have the container of it (datarow1). ASP.NET is not able to know which textbox1 you want if there are 10 on the page and you invoke Page.Findcontrol. So finding a control with its ID is always on container level.
Rate this:
Please Sign up or sign in to vote.

Solution 1

   

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)




CodeProject, 503-250 Ferrand Drive Toronto Ontario, M3C 3G8 Canada +1 416-849-8900 x 100