skip to Main Content

My scheme:

  • I have a label along with a number of textboxes loaded inside an asp:Updatepanel. These controls are initially loaded with values from an SQL database. These values are based on the initial index passed to the page..
  • Additionally the page contains a gridview which contains a list of "contacts".
  • The idea is that if the user selects a contact from the gridview, the index is used to re-query the SQL db. This function returns a datatable which is used to populate the above mentioned textboxes with the selected contacts data – name, address, emails, etc. The user can then modify the textboxes as necessary.
  • At present, I’m using a asp:timer to trigger the updatepanel when a different contact is selected (though I’d welcome a more elegant trigger solution).

When the page is first loaded, all the controls are populated without issue.

The problem:
When subsequent users are selected, ONLY the label value changes – NOT the textbox values.

What I’ve tried:

  • If I disable the timer/trigger, then even the label is not updated when a record is selected in the gridview. This seems to indicate that the timer/trigger is effective (when enabled) as an AsyncPostBackTrigger.
  • For the textboxes, I’ve tried variations of how to assign the textbox values (e.g. Textboxt1.text = value; TextBox1.Attributes.Add("value", value1);
  • Additionally instead of using an asp:Textbox, I’ve tried using:
    < input type="text" id="TextBox1" runat="server" />

Is what I’m trying to do even possible – what am I missing?

Markup:

<asp:Timer runat="server" ID="Timer1" Interval="400" Enabled="false" OnTick="ContactsTimer_Tick" />
<asp:UpdatePanel ID="UpdatePanel1" runat="server" UpdateMode="Conditional" >  
   <ContentTemplate>
      <asp:Label ID="lblContactAccountID" runat="server"/>
      <asp:TextBox ID="txtContactFirstName" runat="server"/> 
      <%--edit: also tried:
      <input type="text"  id="txtContactFirstName" runat="server" />--%>
   </ContentTemplate>
   <Triggers>
      <asp:AsyncPostBackTrigger ControlID="ContactsTimer" EventName="Tick" />
   </Triggers>
</asp:UpdatePanel>

<asp:GridView ID="gvContacts" runat="server" CssClass="table table-striped solid-top" AutoGenerateColumns="false"
   DataKeyNames="PersonID" OnRowCommand="gvContacts_RowSelected">
   <Columns>
      <asp:BoundField DataField="PersonID" />
      <asp:TemplateField HeaderText="Name" ItemStyle-Width="10%" ItemStyle-HorizontalAlign="Center">
         <ItemTemplate>
            <asp:LinkButton runat="server" CommandName="Selected" CommandArgument="<%# Container.DataItemIndex %>"><%#Eval("LastName")%></asp:LinkButton>
            <asp:LinkButton runat="server" CommandName="Selected" CommandArgument="<%# Container.DataItemIndex %>"><%#Eval("FirstName")%></asp:LinkButton>
         </ItemTemplate>
      </asp:TemplateField>
      <asp:TemplateField HeaderText="Action" ItemStyle-Width="10%" ItemStyle-HorizontalAlign="Center">
         <ItemTemplate>
            <asp:ImageButton runat="server" ImageUrl="~/Images/icon_pencil.png" ToolTip='<%# "Edit Profile for "  + Eval("firstname") + " " + Eval("lastname") %>' CommandName="Edit" CommandArgument="<%# Container.DataItemIndex %>" />
         </ItemTemplate>
      </asp:TemplateField>
   </Columns>
</asp:GridView>

Codebehind:

private void LoadSelectedContact(int personID)
{
   DataTable dt = GetProfileContacts(personID, true);
   if (dt.Rows.Count > 0)
   {
      foreach (DataRow row in dt.Rows)
      {
         lblContactAccountID.Text = row["PersonID"].ToString();
         txtContactFirstName.Text = row["FirstName"].ToString();

         // edit: also tried the below without success
         //            string FirstName = row["FirstName"].ToString();
         //            txtContactFirstName.value= FirstName;
         //            txtContactFirstName.Attributes.Add("value", FirstName);


         // ...
         ContactsTimer.Enabled = true;
      }
   }
}

protected void ContactsTimer_Tick(object sender, EventArgs e)
{
   ContactsTimer.Enabled = false;
   upnlContacts.Update();
}

protected void gvContacts_RowSelected(object sender, GridViewCommandEventArgs e)
{
   GridViewRow row;
   if (e.CommandSource.ToString() == "System.Web.UI.WebControls.ImageButton")
   {
      row = (GridViewRow)((ImageButton)e.CommandSource).NamingContainer;
   }
   else
   {
      row = (GridViewRow)((LinkButton)e.CommandSource).NamingContainer;
   }
   int personID = Int32.Parse(row.Cells[0].Text);
   switch (e.CommandName)
   {
      case "Selected":
         LoadSelectedContact(personID);
         break;
      //case "Edit" ...
   }
}

2

Answers


  1. Chosen as BEST ANSWER

    The solution I'm going with is to add an Id along with ClientIDMode="AutoID" to the linkbutton controls. Additionally I added 'OnRowDataBound="gvContacts_RowDataBound" to the Asp:DataGrid:

    <asp:ScriptManager ID="ScriptManager1" runat="server" />
    <asp:GridView ID="gvContacts" runat="server" .... OnRowDataBound="gvContacts_RowDataBound">
            ....
            <asp:TemplateField HeaderText="Name" >
                     <ItemTemplate>
                        <asp:LinkButton id="lnkLastName" ClientIDMode="AutoID"
            runat="server" CommandName="Selected" CommandArgument="<%# Container.DataItemIndex %>"><%#Eval("LastName")%></asp:LinkButton>
                        <asp:LinkButton id="lnkFirstName" ClientIDMode="AutoID"
            runat="server" CommandName="Selected" CommandArgument="<%# Container.DataItemIndex %>"><%#Eval("FirstName")%></asp:LinkButton>
                     </ItemTemplate>
                  </asp:TemplateField>
    

    In the Code behind I removed the Timer_click method and added the below method which registers the 'AsyncPostBack' for selected controls.

    protected void gvContacts_RowDataBound(object sender, GridViewRowEventArgs e) 
    { 
      if (e.Row.RowType == DataControlRowType.DataRow) {
       LinkButton lnk;
    
       lnk= e.Row.FindControl("lnkFirstName") as LinkButton; 
       ScriptManager.GetCurrent(this).RegisterAsyncPostBackControl(lnk); 
    
       lnk = e.Row.FindControl("lnkLastName") as LinkButton; 
       ScriptManager.GetCurrent(this).RegisterAsyncPostBackControl(lnk); 
      }
    }  
    

    Finally I added the Updatepanel .Update() call to the below method

    private void LoadSelectedContact(int personID)
    {
       DataTable dt = GetProfileContacts(personID, true);
       if (dt.Rows.Count > 0)
       {
          foreach (DataRow row in dt.Rows)
          {
             lblContactAccountID.Text = row["PersonID"].ToString();
             txtContactFirstName.Text = row["FirstName"].ToString();
             // ...
             upnlContacts.Update()
          }
       }
    }
    

  2. When you select a row, there’s a postback. You said that initial values are set when the page loads, so that’s what happens every time there’s a postback.

    If you have worked around that somehow, there is still a simpler solution, which is to use another data control, instead of single textboxes, etc.

    You can use a DetailsView control with its own datasource control. The datasource control can get the data you need based on the ID of the row selected.

    This is probably not 100% accurate but something like

    <asp:SqlDataSource ID="dsPersonDetails" runat="server" DataFile="~/App_Data/etc"
        SelectCommand="SELECT * FROM MyTable WHERE PersonID = ?">
        <SelectParameters>
            <asp:ControlParameter ControlID="gvContacts" Name="PersonID"
                PropertyName="SelectedValue" Type="Int32" />
        </SelectParameters>
    </asp:SqlDataSource>
    

    With the right query, this will also help with editing the data, right in the detailsview control.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search