I have created a user control which basically consists of 3 text boxes. I want to allow the user to click a hyperlink which will add a new instance of the user control onto a PlaceHolder. This seems to be working as I populate one of the text box controls with a random number which changes whenever I click the hyperlink. However, it is overwriting the previous control.
Heres the code on MyPage.aspx
protected void MyHyperlink_Click(object sender, EventArgs e)
{
var uc = new MyUserControl();
uc = (MyUserControl)LoadControl("~/path/to/my/usercontrol.ascx");
placeHolderCtrl.Controls.Add(uc);
}
Basically what I need to know is how can I get the control adding different instances underneath eachother as it just seems to be 1 control being overwritten each time.
Thanks.
The problem is after the postback, your previously added controls are not added to the placeholder. Dynamically added control should be added on each postback. My recommendation is to store a counter in a variable and at your page load, add your web controls again depending to this counter.
Related
I am having a problem with an C# ASP.NET form. The purpose of the form is to load some key/value pairs from a database to allow a user to view, edit or delete them.
The Key/Value pairs are dynamically generated in the Page_Load event, and everything works well when the page is first openend. Here is some example code (trimmed down from the original)
TableRow row = new TableRow();
TableCell cell = new TableCell();
cell.Text = keyName;
row.Cells.Add(cell);
cell = new TableCell();
cell.Text = keyValue;
row.Cells.Add(cell);
KeyValueTable.Rows.Add(row);
I just loop through all of the Key/Value pairs and each are added dynamically to a table. At the point of page loading, everything is running smoothly, and all Key/Value pairs show as expected.
The problem occurs when a user clicks a button, which since is set to runat="server", generates a post back event. What this does is it appears to do is clear the dynamic content generated above, and then recreates it (since it is created in the Page_Load event).
What I would prefer to do is choose when that dynamic content is cleared, since I don't want it refreshing unnecessarily, since each refresh is actually occurring from a database.
What I have attempted to do is perform the generation of the dynamic content if it isn't a postback. I.E:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
GenerateDynamicContent();
}
}
However what that now does is generate the dynamic content when the page first loads, however as soon as some postback event occurs (such as a user clicking a button), the dynamic content is wiped, but not created.
Basically what I am hoping for is to discover some way where I can create dynamic content, as shown above, that isn't wiped on any postback event. I want to be able to control when it is refreshed, rather than it occurring on any postback event. Is this possible?
Many thanks
I've found that putting the dynamic code into Page_Init instead of Page_Load prevents the content from being wiped during a postback
I've created 2 controls to manipulate a data object: 1 for viewing and another for editing.
On one page I load the "view" UserControl and pass data to it this way:
ViewControl control = (ViewControl)LoadControl("ViewControl.ascx");
control.dataToView = dataObject;
this.container.Controls.Add(control);
That's all fine and inside the control I can grab that data and display it.
Now I'm trying to follow a similar approach for editing. I have a different User Control for this (with some textboxes for editing) to which I pass the original data the same way I did for the view:
EditControl control = (EditControl)LoadControl("EditControl.ascx");
control.dataToEdit = dataObject;
this.container.Controls.Add(control);
Which also works fine.
The problem now is getting to this data. When the user clicks a button I need to fetch the data that was edited and do stuff with it.
What's happening is that because the controls are being added programmatically, the data that the user changed doesn't seem to be accessible anywhere.
Is there a solution for this? Or is this way of trying to keep things separated and possibly re-usable not possible?
Thanks in advance.
Just keep a reference to the control as a variable in the page's code-behind. I.e.
private EditControl control;
protected void Page_Init(object sender, EventArgs e)
{
control = (EditControl)LoadControl("EditControl.ascx");
control.dataToEdit = dataObject;
this.container.Controls.Add(control);
}
protected void Button_Click(object sender, EventArgs e)
{
var dataToEdit = control.dataToEdit;
}
As long as you're creating the control in the right part of the page's lifecycle (Initialization) then ViewState will be maintained. I'm assuming dataToEdit is just a TextBox or something?
Controls created dynamically must be added on Init or PreInit event on the page.
You have to do it here because controls state is not yet loaded. If you add the the control AFTER you'll have them empty since the page already filled control page values early in the page life cycle.
More info about page life cycle here
Here's my solution:
In the page, I keep a reference to the control that is loaded programmatically.
In the control I created a GetData() method that returns an object with the data entered by the user.
When the user submits the form, the page calls the GetData() method on the control to access the data the user entered.
I've a following requirement for my asp.net page:
User can add a textbox dynamically on a page A by clicking on link "Add a new category" hyperlink
He clicks submit button on page A and gets redirected to page B.
When he clicks on page A link from this page, the textboxes that he added should be persisted.
Can someone help me with the code on this?
Appreciate your help!
In the ButtonClick Method write.
TextBox tb = new TextBox();
Parent.Controls.Add( tb );
The Parent is the control you want to add the textbox to, for instance a panel.
You can also look at this resource.
Hope it helps.
Adding a user control dynamically is simple. But in this case, I don't think you need to do that, instead you should look at creating a repeater with a textbox inside it, and when the user clicks Add Category, add one item to the repeater datasource.
This way you can handle both control creation and state persistence at the same time.
dealing with dynamic user controls can be a pain in the ass.
as a rule of thumb i follow, whenever you create a dynamic user control, then you must set it's ID so ASP.net can reallocate it on post back, and to keep the controls values after post back you should reload your user controls on Page_Init event.
hope this helps.
Dynamically creating Textboxes:
suppose you have page like this
when you enter '1' in textbox and click on ADD button,output will be like display one textbox
below..
i have designed like this,
i have one textbox and placeholder for displaying dynamic textboxes..
double click on Add button...in btnadd_click,you have to write the following code
protected void btnadd_Click(object sender, EventArgs e)
{
int i;
for (i = 0; i < Convert.ToInt32(txtno.Text); i++)
{
TextBox txtbox = new TextBox();
phtxt.Controls.Add(txtbox);
phtxt.Controls.Add(new LiteralControl("<br>"));
}
}
debug it... and the output is,
As others have stated adding the text box dynamically is fairly straight forward, just create the Textbox and add it to the controls collections wherever you need it to show up. You then need to store the information that this user gets this additional text box. Assuming that this is meant for long term, you will need to store this information in your backend store. Whenever you are constructing the page you will need to read the store information first to see what textboxes to create.
I would suggest doing it as follows. In the Onload event, if you have not done so before, load the dynamic information from your DB. Add any necessary controls to the page and store this information in viewstate. On any subsequent postbacks, read the information from viewstate to add the additional controls. This will save you from having to read constantly from the database on each postback.
I have an ASP.NET web form which I am adding a variable number User Controls to. I have two problems:
The User Controls are added to a PlaceHolder on the form in the first PageLoad event (I only add them when "(!this.IsPostback)", but then when the form is posted back, the controls are gone. Is this normal? Since other controls on the form keep their state, I would expect these dynamically added ones to stay on the form as well. Do I have to add them for every postback?
I also have a button and an event handler for the button click event, but this event handler is never called when I click on the button. Is there something special I have to do to catch events on dynamically added controls?
Yes, you need to add them in every postback.
Yes... the control needs to be in the control hierarchy before asp.net dispatches the event (i.e. create the dynamic controls as early in the page lifecycle as possible).
1) You should add the controls on the Pre-init (Page life cycle)
2) You have to attach the event handler to the event of the created button.(events might occur much later in the page life cycle than the same events for controls created declaratively)
To achieve this, add your controls at page init instead of page load. (re-add at postback)
You'll need to know the id of the buttons added to bind them to the event.
I ran into a similar problem. I had a page that displayed a collection of custom web controls. My solution was to add an additional invisible web control so that when I clicked a button to add another control that I would just use the invisible one. Then on post back my load function would add another invisible control to the collection.
I figured out yesterday that you can actually make your app work like normal by loading the control tree right after the loadviewstateevent is fired. if you override the loadviewstate event, call mybase.loadviewstate and then put your own code to regenerate the controls right after it, the values for those controls will be available on page load. In one of my apps I use a viewstate field to hold the ID or the array info that can be used to recreate those controls.
Protected Overrides Sub LoadViewState(ByVal savedState As Object)
MyBase.LoadViewState(savedState)
If IsPostBack Then
CreateMyControls()
End If
End Sub
I ran into the exact same problem and struggled through like 5-6 hours.
I'm posting this maybe someone like me could get help.
1) You should initialize your controls at Page.PreInit event. (In my case I had to add my controls to a place holder so I extended PreInit to load those controls before but you don't need to do that. It depends on your scenario.)
2) You should bind those exact methods to your controls after you initialize them in your Page.PreInit event.
Here is my sample code:
protected override void OnPreInit(EventArgs e)
{
// Loading controls...
this.PrepareChildControlsDuringPreInit();
// Getting ddl container from session and creating them...
if (GetDDLSession().Count != 0)
{
foreach (DropDownList ddl in GetDDLSession())
{
ddl.SelectedIndexChanged += SelectedIndexChanged;
phDropDowns.Controls.Add(ddl);
}
}
base.OnPreInit(e);
}
public static void PrepareChildControlsDuringPreInit(this Page page)
{
// Walk up the master page chain and tickle the getter on each one
MasterPage master = page.Master;
while (master != null) master = master.Master;
}
I am trying to build a server control that, depending on a "QuestionTypeId" display either a text box, date picker or Yes-No radio buttons.
I have my control displaying how I want it to, but when the submit button is pressed on the form, the text box, date picker or radio buttons that were generated in the RenderContents method are all null.
I have attempted to store the generated controls in view state, that stopped them being null, but the user inputs were not being stored.
I will post code if it is needed. Just ask.
I think you need to create (and add) the controls in CreateChildControls. This will mean you'll need to store the value of the QuestionTypeId in either Viewstate or ControlState (I'd argue that ControlState is applicable in this case, as your control can't work without this value).
When you add controls dynamically, you need to make sure they are recreated before the viewstate is restored.
I haven't done this in a while, but from memory I think you should recreate your controls in the OnInit method. This happens before postback data has been loaded and before the controls have their values set from viewstate.
It may be worth doing some reading on the asp.net page lifecycle:
http://msdn.microsoft.com/en-us/library/ms178472.aspx
You can create a user control and use server controls for textbox, datepicker, radiobuttons.
If you create a cusom server control then you have to add the posted data to your control properties. You can do this at your control OnInit event:
MyProperty = Request.Form("myControl");
A simpler method would be to create all the controls at design time and make the controls invisible based on you requirements.
Example code:
protected void Page_Load(object sender, EventArgs e)
{
txtBox.Visible = QuestionTypeID == 1;
chkBox.Visible = QuestionTypeID == 2;
}
If you do use dynamic controls you should do as David pointed out, save the value QuestionTypeID in ViewState or ControlState and then create the control you want based on that value.
(the control needs to be created every time the page loads even on a post back and they cannot be created later in the page life cycle then the Page_Load method if you want their ViewState persisted and recovered)
Example code:
protected void Page_Load(object sender, EventArgs e)
{
var questionId = ViewState["QuestionTypeID"];
if(questionId == /* Value to create TextBox */) {
var txt = new TextBox { ID = "txt" };
placeHolder.Controls.Add(txt);
} else if(questionId == /* Value to create Calender */) {
var cal = new Calender { ID = "cal" };
placeHolder.Controls.Add(cal);
}
/* Once the controls are added they will be populated with the posted values */
}
P.S.
It's always a good idea with dynamic controls to specify the ID.
You can save the added controls to member variables and use them elsewhere (after they are assigned)
You can subscribe to their events and if the user posted a new value your method will be called
I have followed your advice and done the following:
1) Question Type is stored in view state in my server control.
2) on CreateChildControls now creates a new instance of my control and adds it to a place holder on the page.
My problem now is that things seem to fire in bit of an odd order:
1)On initial load of page, create child controls is fired and the RenderContents method of my server control fires.
2)A button is clicked to load a new contact, this triggers create child controls and RenderContents is fired.
3)details are entered and save is pressed, this triggers Create Child Controls but RenderContents is not triggered and a NullReferenceException is generated by trying to access my control to get the value out. (If i skip the code that access my controls, RenderContents is called and renders.
Seconly, another issue is that when I try an set a value (onDataBind) I try to access the Text box that has been generated in my server control and get another NullReferanceExeption
Thoughts?