Asp.Net Add UserControl to a Page - asp.net

I have an ASP.Net web site and on one of the pages I'm using a repeater to render several iterations of a UserControl, that UserControl contains a second UserContol that has two text boxes that my User must enter information into. I want to be able to have my user push a button and add another instance of the second UserControl (with the two textboxes) to my original UserControl, so that the user has 4 textboxes displayed on the screen for the first UserControl. The problem I am seeing if I try to add the second UserControl to a given iteration of the first, is that the page postback causes any other of these second user controls to be deleted from the page.
Does anyone know of a way to do this using JQuery? I've had three posts that describe how to solve this problem using server side dynamic controls, and/or AJAX, but we've decided to focus on a JQuery solution because this server side mechanism is too costly in terms of resources for us.
I've been working on the suggestion by Zincorp below, and now have the JQuery working to clone a textbox, but having trouble using the server side Request.Form collection to iterate over the controls. Can anyone give adivce on how to iterate over the Request.Form collection?
OK, I think the problem with iterating over the controls using the Request.Form.AllKeys collection turned out to be that I was using an HTML Textbox, rather than an ASP TextBox Control. Apparently the Request.Forms.AllKeys collection only contains ASP controls, not HTML controls.
The problem I am seeing now is that when I clone the control in JQuery, and then submit my page with the submit button, the 2 controls have the same ID, and so are combined (I think) by http into one ASP TextBox Controls containing both values, with a comma delimiter (e.g.- 40,20). Anyone know how to get a new ID assigned to the cloned ASP TextBox?
Here is the updated markup in a sample ASP.Net web appliction:
<%# Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Label runat="server" ID="ProjectDisplay" Text="Project" />
<asp:TextBox ID="ProjectValue" runat="server" ></asp:TextBox>
<div id="mydiv" ></div>
<br />
<br />
<br />
<input id="AddProject" type="button" value="Add Project" />
<br />
<br />
<asp:Button ID="Submit" runat="server" Text="Submit" onclick="Submit_Click" />
</div>
</form>
</body>
</html>
<script language="jquery" src="js/jquery-1.3.2.js" type="text/javascript"></script>
<script type="text/javascript" >
$(document).ready(function() {
$("#AddProject").click(function() {
var x = $("#ProjectValue").clone();
x.appendTo("#mydiv");
});
});
</script>
And here is the updated server side code where I'm trying to iterated over items in the Request.Form collection to get information from it:
public partial class _Default : System.Web.UI.Page
{
protected void Submit_Click(object sender, EventArgs e)
{
foreach (string s in Request.Form.Keys)
{
object x = Request.Form[s];
}
}
}

Before choosing a solution for the problem, consider the problem first:
You effectively need to:
1) Duplicate controls/markup on the client-side
2) Obtain these values on the server-side on a postback
3) For each of the added "user controls" on the client-side, add them as children of the first user control on the server side.
I'm not going to give the code, but here are some ideas:
1) Use jQuery's .clone() method (http://api.jquery.com/clone/) to duplicate the markup being rendered by the usercontrol containing the textboxes. Perhaps wrap them in a div without runat="server" to so that you can easily obtain it by ID. You'll probably need to then recursively iterate through the children in the cloned element and append a # to them to avoid any conflicting identifiers. (eg. nameTextBox_1, nameTextBox_2, etc.)
2) On a postback, use the Request.Form collection on the server side to obtain the textbox values. Iterate through it and snag all of the items whose keys start with "nameTextBox_".
3) For each added "user control" on the client side, create the actual user control on the server side, assign to it the values entered in the textboxes, and then add it to the child controls of the first one. This way the state is maintained upon returning to the user.

The short answer is that you would have to add the controls before the ViewState is initialized.
The video on this site has a nice guide on adding dynamic controls. http://www.asp.net/%28S%28wnmvzu45umnszm455c1qs522%29%29/learn/ajax-videos/video-286.aspx

This is probably not a ViewState issue. That may be the first place to look, but after that you need to make sure that your dynamic controls are actually being CREATED on each load.
Generally speaking, the ViewState is only responsible for restoring STATE to existing controls (hence the name). It is not responsible for recreating controls.

I believe you are experiencing a viewstate problem. Your dynamic controls are not being persisted. If you haven't already, read Dave Reed's excellent article Truly Understanding Viewstate. Pay particular attention to the section "5. Initializing dynamically created controls programmatically" which applies to the trouble you are experiencing.

Related

Issues with User Control inside repeater

I am using ASP.NET
I have created a user control that look like this:
when pressing the + : the score is raised by 0.5 and the opposite for minus.
The user control contains an update panel, and the pages itself containing the script manager.
When I put this user control in page and NOT inside repeater, this works perfect.
When I put this as part of a repeater. this not work at all.
I tried to delete all the update panels and still not working.
This is the error I'm getting
Don't know how to fix this.
This is the code of the user control:
Often, this error shows due to not post back:
If(!IsPostBack){
// your controls code here
}
Or, Check is your web page not using <form> tag more than once:
<form id="form1" runat="server">
<form id="form2" runat="server">
<!-- Your user controls -->
</form>
</form>
You have to use only one <form> tag in your page.
Or, try in your *.aspx page like:
EnableEventValidation="false"

ViewState is not required to preserve control values so what does it do?

I have a very simply web page with ViewState disabled everywhere:
<%# Page Language="C#" AutoEventWireup="true" CodeFile="test.aspx.cs" Inherits="test" EnableViewState="false" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<body>
<form id="form1" runat="server">
<div>
<asp:TextBox runat="server" EnableViewState="false"></asp:TextBox>
<asp:DropDownList runat="server" id="mylist" EnableViewState="false">
<asp:ListItem>my item 1</asp:ListItem>
<asp:ListItem>my item 2</asp:ListItem>
<asp:ListItem>my item 3</asp:ListItem>
<asp:ListItem>my item 4</asp:ListItem>
<asp:ListItem>my item 5</asp:ListItem>
<asp:ListItem>my item 6</asp:ListItem>
</asp:DropDownList>
<asp:Button runat="server" Text="click me"/>
</div>
</form>
</body>
</html>
Code behind
public partial class test : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
Response.Write("Dropdown list value is " + mylist.SelectedValue);
}
}
As you can see, no viewstate is enabled but it does preserve controls values, see here for the running example http://www.yart.com.au/stackoverflow/viewstate/test.aspx
Edit
latr0dectus has somewhat answered my question below. But what's an example where ViewState is required practically? I can't see what you need from the form other than control values.
#Petras: ViewState is not required to preserve control values so what does it
do?
Controls that implements IPostBackDataHandler uses LoadPostData() method to assign to some properties.
Read this article : Understanding ASP.NET View State
It is a common misconception among developers that view state is
somehow responsible for having TextBoxes, CheckBoxes, DropDownLists,
and other Web controls remember their values across postback. This is
not the case, as the values are identified via posted back form field
values, and assigned in the LoadPostData() method for those controls
that implement IPostBackDataHandler.
I'm not really sure what your question is.
View state is used in the page lifecycle. After the page is served it is destroyed on the server. Then the browser posts back it also posts back the viewstate. The server can use this in combination with the posted form values to recreate the previous state of the page and then show the changes.
In some cases even with viewstate disabled certain controls will appear to work as if they have viewstate enabled. This is because some controls have what is called "Control State". It operates almost like viewstate, except it cannot be disabled. This is because some controls would cease to function properly without it.
In the example you posted I think you are observing that the selected value of the dropdown is being posted to the server during postback. Not that it was reconstructed from viewstate.
Im adding this information that I found from the following link:
http://aspnetresources.com/articles/ViewState
What's the moral of this story? You don't always need view state enabled to maintain page state. "When do I need it though? What's it for then?" Glad you asked. The prime candidates for participation in view state are those controls that don't post back with the HTTP form and controls added or populated dynamically.
Scan to that part of the document and you should find what you are looking for.

When isn't runat="server" used in asp.net?

When don't you need to use runat="server" in ASP.NET?
EDIT: Thanks for all the answers, but I was really thinking of runat="server" inside an <asp: tag.
Use the runat=server attribute when you're using ASP.NET controls, and/or you require programmatic access to those controls in your code-behind.
HTML controls don't require this attribute. It's useful if you have any HTML element like <span> <div>, or <table> when you want the ability to access them in code-behind.
<asp:Label runat="server" id="foo" />
<div runat="server" id="bar />
...
foo.Text = "Hello Label";
foo.Attributes["class"] = "baz";
You need to use runat="server" on any control that you want to be parsed as a server control.
Any element with runat="server" will be parsed into a server control in the Page herarchy. Anything else will be handled as plain text, and put in LiteralControl controls in the Page hierarchy.
The exception is elements that aren't real elements, but special tags within another server tag, for example ContentTemplate tags. They don't need a runat="server" because the containing control will parse them.
When you don't want the server side ASP.NET to render a server side variable against us.
Generally speaking you don't use it when you don't need to manipulate the DOM element at the server side e.g. which are only used for layout purposes.
Without runat="server" there would also be no other way to make html controls server side controls. It does look like an odd thing, because you can't do runat="client".
So in summation you can't leave it out on any ASP .Net controls ever and it was probably the easiets and cleanest way to find all server side controls for the developers who created ASP .Net Web forms.
source: http://mikeschinkel.com/blog/whyrunatserverforaspnetpart2/
Tag runat="server" indicates that the code contained within the script block will run on the server (and not on the client). On execution, ASP.NET will create server-side objects that contain this code as well as an instance of the Page class to contain the controls defined inside the page as instances of their given type (System.Web.UI.WebControls.Textbox, for example). This server-side object will be invoked on user request and will execute code in response to events.
Create Control in Runtime
I need one label in runtime that time don't need runat="Server" is not required
Example
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
Label lblNew = new Label();
lblNew.ID ="lblnew";
lblNew.Text ="Test";
}
}
this code create label in runtime at page load event

a page can have only one server-side form tag

I am using master page and when I run this page, it shows the following error message:
a page can have only one server-side form tag
How can I solve this problem?
I think you did like this:
<asp:Content ID="Content2" ContentPlaceHolderID="MasterContent" runat="server">
<form id="form1" runat="server">
</form>
</asp:Content>
The form tag isn't needed. because you already have the same tag in the master page.
So you just remove that and it should be working.
It sounds like you have a form tag in a Master Page and in the Page that is throwing the error.
You can have only one.
Does your page contain these
<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1"
Runat="Server">
</asp:content>
tags, and are all your controls inside these? You should only have the Form
tags in the MasterPage.
Here are some of my
understanding and suggestion:
Html element can be put in the body of html pages and html page does
support multiple elements, however they can not be nested each
other, you can find the detailed description from the W3C html
specification:
The FORM element
http://www.w3.org/MarkUp/html3/forms.html
And as for ASP.NET web form page, it is based on a single server-side form
element which contains all the controls inside it, so generally we do not
recommend that we put multiple elements. However, this is still
supported in ASP.NET page(master page) and I think the problem in your
master page should be caused by the unsupported nested element, and
multiple in the same level should be ok. e.g:
In addition, if what you want to do through multiple forms is just make our
page posting to multiple pages, I think you can consider using the new
feature for cross-page posting in ASP.NET 2.0. This can help us use button
controls to postback to different pages without having multpile forms on
the page:
Cross-Page Posting in ASP.NET Web Pages
http://msdn2.microsoft.com/en-us/lib...39(VS.80).aspx
http://msdn2.microsoft.com/en-us/lib...40(VS.80).aspx
Use only one server side form tag.
Check your Master page for <form runat="server"> - there should be only one.
Why do you need more than one?
Sometime when you render the current page as shown in below code will generate the same error
StringWriter str_wrt = new StringWriter();
HtmlTextWriter html_wrt = new HtmlTextWriter(str_wrt);
Page.RenderControl(html_wrt);
String HTML = str_wrt.ToString();
so how can we sort it?
please remove " runat="server" " from "form" tag then it will definetly works.

One user control updating another during AJAX Postback?

I developed a user control that displays a list of products and it works pretty good. Then I dropped this user control into another user control that allows the user to pick different criteria and the product UC updates to show those products, all pretty slick and with AJAX via UpdatePanel.
All was working just fine... then another requirement came in. The "search" control needs to be separate from the product control (so they can be positioned separately). Initially, I thought this was no problem as I would give the search control a reference to the product control and then it would talk to it via reference instead of directly inside the control (which has been removed).
And they do talk. But the product control loads, but refuses to display.
I checked and it is being passed via reference and not a copy ( as best I can tell ).
There is an updatepanel in the search control. There is an update panel in the product control. And then for good measure, there is an update panel surrounding them both in the actual search aspx page.
I've tried setting the product control update panel to conditional and then fire the .Update() method manually.
What's the secret here?
TIA!
SOLVED
Thanks to Jamie Ide for the tip to use events.
Search Control and Product control still have internal update panels, and NO LONGER have them on this particular page.
Search Control now raises an event OnSearchResultsUpdated and exposes the found items in properties. The page subscribes to this event and takes the properties and passes them to the product control and triggers triggers a .Refresh() method on the product control which simply calls the .Update() on its internal updatepanel.
The Product control, FYI, accepts products in several different flavors. A list of distinct SKUs, a list of product ids, a named collection in our database and finally a given product category.
Our designers need to be able to create a new page, drop the control onto it and set some properties and voila! New site page. They don't want to require a programmer's involvement. So keeping the controls self contained is a requirement. Fortunately all the changes I made still work completely with the other uses of the product control.
THANKS AGAIN SO MUCH!
I don't think there's really enough information to work with here, but my best guess is that the Product control is not getting data bound. You may try calling myProdcutsCtrl.DataBind() from the search control (or something inside the Product control that cause a DataBind() for instance myProductCtrl.Search(value1, value2, value3).
One other thing you might try is removing the UpdatePanels and seeing if things work. Then add them back in once you get core functionality going.
UPDATE: I've gone ahead and put some example code that works here which I believe accomplishes what you want. What follows are snippets for the sake of saving space, but include all code necessary to make it run. Hopefully this will at least give you something for reference.
Things to try:
EnablePartialRendering="true|false" setting it to false will force the natural postbacks and is good for debugging UpdatePanel problems.
Make sure you are seeing Loading... come up on your screen. (maybe too fast depending on your dev computer)
Page.aspx
<%# Register Src="~/Product.ascx" TagPrefix="uc" TagName="Product" %>
<%# Register Src="~/Search.ascx" TagPrefix="uc" TagName="Search" %>
...
<asp:ScriptManager runat="server" ID="sm" EnablePartialRendering="true" />
Loaded <asp:Label ID="Label1" runat="server"><%= DateTime.Now %></asp:Label>
<asp:UpdateProgress runat="server" ID="progress" DynamicLayout="true">
<ProgressTemplate><b>Loading...</b></ProgressTemplate>
</asp:UpdateProgress>
<uc:Search runat="server" ID="search" ProdcutControlId="product" />
<uc:Product runat="server" ID="product" />
Search.ascx
<asp:UpdatePanel runat="server" ID="searchUpdate" UpdateMode="Conditional" ChildrenAsTriggers="true">
<ContentTemplate>
<p>
<asp:Label runat="server" AssociatedControlID="filter">Less than</asp:Label>
<asp:TextBox runat="server" ID="filter" MaxLength="3" />
<asp:Button runat="server" ID="search" Text="Search" OnClick="SearchClick" />
</p>
</ContentTemplate>
</asp:UpdatePanel>
Search.ascx.cs
public string ProdcutControlId { get; set; }
protected void SearchClick(object sender, EventArgs e)
{
Product c = this.NamingContainer.FindControl(ProdcutControlId) as Product;
if (c != null)
{
c.Search(filter.Text);
}
}
Product.ascx
<asp:UpdatePanel runat="server" ID="productUpdate" UpdateMode="Conditional" ChildrenAsTriggers="false">
<ContentTemplate>
<asp:Label runat="server">Request at <%= DateTime.Now %></asp:Label>
<asp:ListView runat="server" ID="product">
<LayoutTemplate>
<ul>
<li id="itemPlaceHolder" runat="server" />
</ul></LayoutTemplate>
<ItemTemplate>
<li><%# Container.DataItem %></li></ItemTemplate>
</asp:ListView>
</ContentTemplate>
</asp:UpdatePanel>
Product.ascx.cs
IEnumerable<int> values = Enumerable.Range(0, 25);
public void Search(string val)
{
int limit;
if (int.TryParse(val, out limit))
product.DataSource = values.Where(i => i < limit);
else
product.DataSource = values;
product.DataBind();
productUpdate.Update();
}
Code does NOT represent best practices, just a simple example!
I'm fairly new to AJAX, but I don't think it's a good idea for user controls to have UpdatePanels. I would also advise you not to have the user controls reference each other; they should communicate through events and methods controlled by their container.
I do something similar with two user controls for a master-details display. The master raises an event when an item is selected from a list, the containing page handles the event and calls a method on the details display to display the selected item. If I remember correctly, my first attempt had UpdatePanels in the user controls and I wasn't able to make that work. Having the user controls inside an UpdatePanel on the page works fine.
If I understand you right you have a layout like this:
Outer UpdatePanel
SearchControl
Search UpdatePanel
ProductControl
Product UpdatePanel
Databound Control
Which one of those update panels is actually being called?
I assume that if you check the network traffic with something like Fiddler or Firebug if you're using Firefox, you aren't seeing any HTML for the product update panel coming back?
Have you tried doing something like:
UpdatePanel productUpdate =
Page.FindControl("Product UpdatePanel") as UpdatePanel;
if (null != productUpdate){
productUpdate.Update();
}
By default, if a postback is made from an UpdatePanel, only that control will be updated/re-rendered (this is called partial page-rendering).
To also update/re-render other UpdatePanels, you have to either:
set their UpdateMode property to Always
add the control that makes the postback to their Triggers collection
Check this page in MSDN for details.

Resources