Here's my HTML
<asp:UpdatePanel runat="server" ID="panel1" UpdateMode="Conditional">
<ContentTemplate>
<asp:FormView runat="server" ID="formViewUno" DataSourceID="odsBob" DefaultMode="Insert">
<InsertItemTemplate>
<span>Name:</span>
<asp:Literal ID="Literal4" runat="server" Text=" " />
<asp:TextBox runat="server" ID="tbxName" Text='<%# Bind("Name") %>' />
<br />
<span>Age:</span>
<asp:Literal ID="Literal5" runat="server" Text=" " />
<asp:TextBox runat="server" ID="tbxAge" Text='<%# Bind("Age") %>' />
<br />
<span>City:</span>
<asp:Literal ID="Literal6" runat="server" Text=" " />
<asp:TextBox runat="server" ID="tbxCity" Text='<%# Bind("City") %>' />
<br />
<asp:Button ID="Button1" runat="server" CommandName="Insert" Text="Insert" />
</InsertItemTemplate>
</asp:FormView>
<asp:Panel runat="server" ID="msgs">
</asp:Panel>
</ContentTemplate>
</asp:UpdatePanel>
Here's my C#
private void odsBob_Inserted(object sender, ObjectDataSourceStatusEventArgs e)
{
var p = e.ReturnValue as Person;
if (p != null)
{
var msg = new Label
{
Text =
String.Format("{0} [Age:{1}, City:{2}] was successfully added", p.Name, p.Age,
p.City)
};
var br = new LiteralControl { Text = "<br/>" };
msgs.Controls.Add(br);
msgs.Controls.Add(msg);
}
}
How can I persist (add a new one after the insert) the label controls? It is being wiped out. The new one added is added each time correctly. How can I keep the control collection in tact? Thanks for any help.
Cheers,
~ck
It looks like you're dynamically creating a label object during the event handler.
Dynamic controls are problematic because they need to be recreated on every postback. Remember that a postback creates a new instance of your Page object - which means that the controls you added to your last page are gone - your Panel is initialized as empty with each new request, so only the latest literal/label pair will be added.
One solution may be to add all the necessary textual information to Session, and have your Panel generate dynamic labels and literals from whatever is in Session during Prerender.
Another solution would be more complex, but you could have the Panel add labels and literals dynamically during the Init phase. If you can ensure that the same number of controls is added in the same order during Init, then the ViewState for those controls will be properly tracked on each PostBack. You would basically need to store the most recently added label and literal into Session, and have the Panel fetch it out on the next request to ensure it got added back in during Init. You'd also need to store a counter so that the Panel knew how many sets of controls to add during Init.
Related
I am trying to create a web app that can create a survey form just like google forms.
<asp:Panel ID="container" runat="server"></asp:Panel>
<asp:Panel ID="question" runat="server" Height="391px">
<br />
<br />
<asp:Label ID="Label1" runat="server" Text="Question: " Font-Size="Large"></asp:Label>
<asp:TextBox ID="txtQuestion" runat="server" Font-Size="Large"></asp:TextBox>
<asp:DropDownList ID="lstQuestionType" runat="server">
<asp:ListItem Enabled="False" Selected="True">Question Type</asp:ListItem>
<asp:ListItem>Short Answer</asp:ListItem>
<asp:ListItem>Paragraph</asp:ListItem>
<asp:ListItem>Multiple Choice</asp:ListItem>
<asp:ListItem>Check Box</asp:ListItem>
<asp:ListItem>Linear Scale</asp:ListItem>
</asp:DropDownList>
<asp:Button ID="btnGenerate" runat="server" OnClick="btnGenerate_Click" Text="Generate Question" Width="137px" />
</asp:Panel>
<asp:Button ID="btnAddQuestion" runat="server" Text="Add Question" OnClick="btnAddQuestion_Click" />
and this is the C# code that generates the panel
protected void btnAddQuestion_Click(object sender, EventArgs e)
{
Panel newQuestions = new Panel();
newQuestions = question;
container.Controls.Add(newQuestions);
}
but when I click the add question button, it does not add the panel
Although i can't tell from the code probably the problem is with the question parameter. Also use MVC with controllers it will be much more clean and also VS automatically generates the View for you based on your models and controllers which i guess it will save you time in the long run.
The Asp.net website I am creating uses a Repeater to display a list of Strings concerning duplicates or missing entries from two databases. There is another list of strings created in parallel of SQL statements with one SQL statement corresponding to the same numbered string in the Repeater list. The number of strings in the lists depends on the databases chosen and can range from zero to 100+.
Question: Since the number of Repeater rows are unknown, I am trying to find some method to generate an unknown number of checkboxes/buttons (one for each row). When clicked, the checkbox/button will find the appropriate SQL statement in the other list for the row in a separate method. Does anyone have an idea as to how a variable number of checkboxes could be created?
This can be done with adding a CommandArgument to a button and assigning a Command to it, not a Click.
<asp:Repeater ID="Repeater1" runat="server">
<ItemTemplate>
<asp:Label ID="Label1" runat="server" Text='<%# Eval("myColumn") %>'></asp:Label>
<br />
<asp:Button ID="Button1" runat="server" CommandArgument='<%# Eval("ID") %>' OnCommand="Button1_Command" Text="Button" />
<hr />
</ItemTemplate>
</asp:Repeater>
<asp:Label ID="Label2" runat="server" Text=""></asp:Label>
And then in code behind handle the OnCommand
protected void Button1_Command(object sender, CommandEventArgs e)
{
Label2.Text = e.CommandArgument.ToString();
}
If you want to read a CheckBox, you'll need slighty more code in code behind.
<asp:Repeater ID="Repeater1" runat="server">
<ItemTemplate>
<asp:Label ID="Label1" runat="server" Text='<%# Eval("field01") %>'></asp:Label>
<br />
<asp:CheckBox ID="CheckBox1" runat="server" Checked='<%# Convert.ToBoolean(Eval("itemid")) %>' />
<br />
<asp:Button ID="Button1" runat="server" CommandArgument='<%# Eval("itemid") %>' OnCommand="Button1_Command" Text="Button" />
<hr />
</ItemTemplate>
</asp:Repeater>
protected void Button1_Command(object sender, CommandEventArgs e)
{
Button btn = sender as Button;
RepeaterItem item = (RepeaterItem)btn.NamingContainer;
CheckBox cb = item.FindControl("CheckBox1") as CheckBox;
Label2.Text = "Item with ID " + e.CommandArgument + " has checkbox " + cb.Checked;
}
Background:
Trying to avoid the complete post back and use partial post back to refresh the data grid. I have checked MSDN, and stack overflow and tried different combinations of the control values for triggering the post back but no luck.
Code
<asp:ScriptManager ID="sm1" runat="server" EnablePartialRendering="true" />
<div>
<asp:UpdatePanel ID="upTest" runat="server" UpdateMode="Conditional" ChildrenAsTriggers="true" >
<ContentTemplate>
<asp:GridView ID="gvTest" runat="server" Visible="true" ShowHeader="true" AutoGenerateColumns="false">
<Columns>
<asp:TemplateField>
<HeaderTemplate>
<div>Document Type</div>
</HeaderTemplate>
<ItemTemplate>
<asp:Label ID="txtDescription" Style="margin: 2px" MaxLength="254" Text='<%# Bind("DocName") %>' runat="server" Width="200px" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
<br />
<label>
<AjaxControlToolkit:AsyncFileUpload ID="AsyncFileUpload1" Width="400px" runat="server"
OnUploadedComplete="AsyncFileUpload1_UploadedComplete" />
</label>
<label id="lblStatus"></label>
</ContentTemplate>
</asp:UpdatePanel>
</div>
Code behind
if (AsyncFileUpload1.HasFile)
{
string strPath = MapPath("~/Uploads/") + Path.GetFileName(e.filename);
AsyncFileUpload1.SaveAs(strPath);
SetGridData(1);
upTest.Update();
}
private void SetGridData(int count)
{
List<Document> Documents = new List<Document>();
Document doc = new Document();
doc.DocName = "test doc";
for (int i = 0; i < count; i++)
{
Documents.Add(doc);
}
gvTest.DataSource = Documents;
gvTest.DataBind();
}
On Page_Load the Grid is loaded with 5 data rows and on the async post back the grid is reset to one data row. While looking at the chrome debugger, I can see the grid data is coming from the server on both Page_Load (5 rows) and async load( 1 data row). But the data grid is not refreshed. I do call the grid.DataBind() during the async post back. Anyone has any ideas whats going on? Am I missing something?
Note: Everything works with normal ASP.Net controls, just dont work with AJAX file upload control
Are you calling the DataBind() method of your GridView within SetGridData? And also add a AsyncPostBackTrigger
Have a look at an example here
try UpdateMode="Always" . it will work
I am using a modal popup that contains a dropdown box. When the dropdown is changed I'm trying to retrieve data and assign it labels also within the modal. I observe the label values being set in the debugger but they do not show in the modal.
Modal/Panel Code:
<asp:Panel ID="pnlUpdate" runat="server" CssClass="modalPopup">
<div>
<asp:UpdatePanel runat="server" ID="upSubnetUpdate" UpdateMode="Conditional">
<ContentTemplate>
<asp:Label runat="server" ID="pnlLblSubnet" CssClass="searchLabel">Subnet:</asp:Label>
<asp:DropDownList runat="server" ID="ddlSubnet" OnSelectedIndexChanged="ddlSubnet_SelectedIndexChanged" AutoPostBack="true"></asp:DropDownList><br />
</ContentTemplate>
</asp:UpdatePanel>
</div>
<div>
<asp:Label runat="server" ID="lblIPStartUpdate"></asp:Label>
<asp:Label runat="server" ID="lblIPEndUpdate"></asp:Label>
<asp:Label runat="server" ID="lblGatewayUpdate"></asp:Label>
<asp:Label runat="server" ID="lblSubnetMaskUpdate"></asp:Label>
</div>
</asp:Panel>
Dropdown Code
protected void ddlSubnet_SelectedIndexChanged(object sender, EventArgs e)
{
SubnetInfo si = GetSubnetInfo(ddlSubnet.SelectedItem.Text);
lblIPStartUpdate.Text = si.IP_Start;
lblIPEndUpdate.Text = si.IP_End;
lblGatewayUpdate.Text = si.Gateway;
lblSubnetMaskUpdate.Text = si.Subnet_Mask;
}
I'm not sure if this is a page lifecycle issue or a limitation of the modal popup.
Thanks for the help!
You need to put the DropDown and the labels in an UpdatePanel. The dropdown is in an UpdatePanel, but it cannot update the labels if they're not in an UpdatePanel too.
First off, I am not dynamically creating any controls. This is the order I take to produce the error:
I have a listview on the page, when I click the edit link under the listview, I display a panel which is hidden by default. The panel has a few buttons on it along with some listboxes. When I click an item in the listbox or click one of the buttons, I get the following error:
Failed to load viewstate. The control tree into which viewstate is being loaded must match the control tree that was used to save viewstate during the previous request. For example, when adding controls dynamically, the controls added during a post-back must match the type and position of the controls added during the initial request.
Again, I am not creating anything dynamically, I am just hiding the panel with the controls by default and then displaying them, so I am not sure why I am getting this error.
Here is some code:
PAGE LOAD
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
Session["Albums"] = null;
Albums = AlbumCollection.GetAlbums(Common.GetUserName(),
ddlAlbumType.SelectedIndex);
lvwAlbums.DataSource = Albums;
lvwAlbums.DataBind();
}
}
When I click the edit link, this is the code that runs:
protected void lvwAlbums_RowEditing(object sender, ListViewEditEventArgs e)
{
this.AlbumId = int.Parse(
this.lvwAlbums.DataKeys[e.NewEditIndex].Values["AlbumId"].ToString());
this.AlbumName=
this.lvwAlbums.DataKeys[e.NewEditIndex].Values["AlbumName"].ToString();
Album album = new Album(this.AlbumId);
ViewState["AlbumId"] = this.AlbumId;
ViewState["AlbumName"] = this.AlbumName;
pnlAlbum.Visible = true; // This panel holds the controls
btnEditAlbum.Visible = true;
btnCancel.Visible = true;
EditAlbum(this.AlbumId);
this.lvwAlbums.EditIndex = e.NewEditIndex;
AlbumCollection.GetAlbums(Common.GetUserName(),ddlAlbumType.SelectedIndex);
}
If I click the cancel button, I get the error, but it also happens if click another button on the panel such as Add/Remove... Here is the code for the Cancel button:
pnlAlbum.Visible = false;
this.lvwAlbums.EditIndex = -1;
AlbumCollection.GetAlbums(Common.GetUserName(), ddlAlbumType.SelectedIndex);
Here is the aspx/html for the ListView:
<asp:ListView ID="lvwAlbums"
runat="server"
GroupItemCount="5"
DataKeyNames="AlbumId,AlbumName"
OnItemEditing="lvwAlbums_RowEditing"
OnItemCommand="lvwAlbums_ItemCommand"
OnItemDeleting="lvwAlbums_RowDeleting"
OnSelectedIndexChanging="lvwAlbums_SelectedIndexChanging"
OnPagePropertiesChanging="lvwAlbums_PagePropertiesChanging">
<EditItemTemplate>
<td>
<div>
<asp:TextBox ID="txtAlbumName" runat="server"
Text='<%# Eval("AlbumName").ToString().Trim() %>' />
<asp:LinkButton ID="lnkView" runat="server" Text="View" CommandName="View"
CommandArgument='<%# Eval("AlbumId") %>'>
</asp:LinkButton>
|
<asp:LinkButton ID="lnkEdit" runat="server" Text="Edit" CommandName="Edit"
CommandArgument='<%# Eval("AlbumId") %>'>
</asp:LinkButton>
|
<asp:LinkButton ID="lnkDelete" runat="server" Text="Delete" CommandName="Delete"
CommandArgument='<%# Eval("AlbumId") %>'>
</asp:LinkButton>
<br />
<span>Songs:
<%# Eval("total") %></span>
</div>
</td>
</EditItemTemplate>
<LayoutTemplate>
<asp:DataPager runat="server" ID="ItemDataPager" PageSize="20"
PagedControlID="lvwAlbums">
<Fields>
<asp:NumericPagerField ButtonType="Link" NumericButtonCssClass="pager" />
</Fields>
</asp:DataPager>
<table>
<tr>
<td>
<table>
<asp:PlaceHolder runat="server" ID="groupPlaceHolder"></asp:PlaceHolder>
</table>
</td>
</tr>
</table>
</LayoutTemplate>
<GroupTemplate>
<tr>
<asp:PlaceHolder runat="server" ID="itemPlaceHolder"></asp:PlaceHolder>
</tr>
</GroupTemplate>
<ItemTemplate>
<td>
<asp:Literal ID="litAlbumName" runat="server"
Text='<%# Eval("AlbumName").ToString().Trim() %>' />
<br />
<asp:LinkButton ID="lnkView" runat="server" Text="View" CommandName="View"
CommandArgument='<%# Eval("AlbumId") %>'>
</asp:LinkButton>
|
<asp:LinkButton ID="lnkEdit" runat="server" Text="Edit" CommandName="Edit"
CommandArgument='<%# Eval("AlbumId") %>'>
</asp:LinkButton>
|
<asp:LinkButton ID="lnkDelete" runat="server" Text="Delete" CommandName="Delete"
CommandArgument='<%# Eval("AlbumId") %>'>
</asp:LinkButton>
<br />
<span>Songs:
<%# Eval("total") %></span>
</td>
</ItemTemplate>
</asp:ListView>
Here is the markup for the Panel:
<asp:Panel ID="pnlAlbum" runat="server" Visible="false">
<asp:ListBox ID="lstAvailableSongs" runat="server" SelectionMode="Multiple">
</asp:ListBox>
<asp:Button ID="btnAddAll" runat="server" Text="Add All" OnClick="btnAddAll_Click" />
<asp:Button ID="btnAdd" runat="server" Text="Add" OnClick="btnAdd_Click" />
<asp:Button ID="btnRemove" runat="server" Text="Remove" OnClick="btnRemove_Click" />
<asp:Button ID="btnRemoveAll" runat="server"
Text="Remove All"OnClick="btnRemoveAll_Click" />
<asp:ListBox ID="lstSelectedSongs" runat="server" SelectionMode="Multiple">
</asp:ListBox>
<asp:Button ID="btnCancel" runat="server" Text="Cancel" OnClick="btnCancel_Click" />
<asp:Button ID="btnEditAlbum" runat="server"Text="Save"
ValidationGroup="CreateAlbum" OnClick="btnEditAlbum_Click" />
<asp:Button ID="btnSaveAs" runat="server" Text="Save As" ValidationGroup="CreateAlbum"
OnClick="btnSaveAs_Click" />
</asp:Panel>
Here is some extra info:
I put an update panel around one of the listboxes in the panel and when I clicked the edit link under a listview item, I received the following error:
Microsoft JScript runtime error: Sys.InvalidOperationException: Could not find UpdatePanel with ID 'ctl00_ctl00_InnerContent_MainContent_UpdatePanel4'. If it is being updated dynamically then it must be inside another UpdatePanel.
Putting an UpdatePanel around the whole asp.net panel resolved the issue above, but I still get the Failed to load viewstate error when clicking on Cancel or Add, etc...
First off, you probably need to rebind the ListView after setting the EditIndex. (honestly, I haven't used ListView at all, but this is how the other repeater controls work) What does "EditAlbum()" do?
Your code is a little odd... why do you have the same controls in your EditItemTemplate as in the ItemTemplate? Ie, the Edit button should only be in the ItemTemplate... Then EditItemTemplate should have a Save or Cancel button.
Bottom line... your control tree is different on LoadViewState than it is when SaveViewState was called. One thing you can do is override these methods and then put a breakpoint there to manually look at the Controls collection in the debugger. You will probably see that the controls inside the ListView are different. But try my first suggestion before you do this.
Question for you:
in your Page_Load you have
Albums = AlbumCollection.GetAlbums(Common.GetUserName(), ddlAlbumType.SelectedIndex);
but in lvwAlbums_RowEditing(..) and in btnCancel_Click(...) you have
AlbumCollection.GetAlbums(Common.GetUserName(), ddlAlbumType.SelectedIndex);
shouldn't these be (Albums = ...)
Albums = AlbumCollection.GetAlbums(Common.GetUserName(), ddlAlbumType.SelectedIndex);