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
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:
In the Code behind I removed the Timer_click method and added the below method which registers the 'AsyncPostBack' for selected controls.
Finally I added the Updatepanel .Update() call to the below method
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
With the right query, this will also help with editing the data, right in the detailsview control.