How to retain new controls after PostBack? - c#

I am creating a web app that allows the user to create their own forms. but once a control is added (for example a new label with its control) it will be deleted upon me trying to add another object to the form.
this is the code for the button that creates the new item.
protected void createFormButton_Click(object sender, EventArgs e)
{
////titles is the div id of where i want to insert the title label
var titlelabel = new Label();
titlelabel.Text = textboxForTitle.Text;
titles.Controls.Add(titlelabel);
controls.Add(titlelabel);
if (optionsDropdown.SelectedValue == "Checkbox")
{
//elements is the div id of where i want to insert the control
var newControl = new CheckBox();
newControl.CssClass = "checkbox";
newControl.Checked = true;
elements.Controls.Add(newControl);
controls.Add(newControl);
}
else if (optionsDropdown.SelectedValue == "Textbox")
{
//elements is the div id of where i want to insert the control
var newControl = new TextBox();
newControl.Text = "this is some text on the new box";
newControl.CssClass = "form-control";
elements.Controls.Add(newControl);
}
else if (optionsDropdown.SelectedValue == "Dropdown")
{
//elements is the div id of where i want to insert the control
var newControl = new DropDownList();
newControl.Items.Add("one");
newControl.Items.Add("two");
newControl.Items.Add("three");
newControl.CssClass = "form-control";
elements.Controls.Add(newControl);
}
}
how can I save the new controls, so with each button click they previous control does not get deleted on postback?

When adding controls dynamically they are deleted on each postback. Now if you follow the lifecycle of an asp page you will notice that the viewstate ( the variable that holds all of your data from the client side objects) comes after the page.init. So when working with dynamically added controls in asp you need to recreate then on each postback in the page.init event. Then the viewstate is loaded into thoses controls. The way i do it is i keep everycontrol created in a list(of control) in session and add them in the placeholder at the page.init

You could create a class-level variable which is a List of controls, rather than adding an item to the built-in controls collection. In your case you would need two, since you are adding controls both to the page and the elements div. These lists will persist across postbacks, so each time you can repopulate the page controls accordingly at the end of your method via AddRange.
NOTE: code untested.
List<Control> pageControls = new List<Control>();
List<Control> elementControls = new List<Control>();
protected void createFormButton_Click(object sender, EventArgs e)
{
////titles is the div id of where i want to insert the title label
var titlelabel = new Label();
titlelabel.Text = textboxForTitle.Text;
titles.Controls.Add(titlelabel);
pageControls.Add(titlelabel);
if (optionsDropdown.SelectedValue == "Checkbox")
{
//elements is the div id of where i want to insert the control
var newControl = new CheckBox();
newControl.CssClass = "checkbox";
newControl.Checked = true;
elements.Controls.Add(newControl);
pageControls.Add(newControl);
}
else if (optionsDropdown.SelectedValue == "Textbox")
{
//elements is the div id of where i want to insert the control
var newControl = new TextBox();
newControl.Text = "this is some text on the new box";
newControl.CssClass = "form-control";
elementControls.Add(newControl);
}
else if (optionsDropdown.SelectedValue == "Dropdown")
{
//elements is the div id of where i want to insert the control
var newControl = new DropDownList();
newControl.Items.Add("one");
newControl.Items.Add("two");
newControl.Items.Add("three");
newControl.CssClass = "form-control";
elementControls.Add(newControl);
}
Controls.AddRange(pageControls);
elements.Controls.AddRange(elementControls);
}

Related

Saving User Input in a Dynamically Created Form

I'm trying to get the values that a user inputs in a textbox in a dynamically generated form. Another method loads and parses an XML file and creates an object that has specific getters and setters for the settings that it finds in the file (Server, Port, Title, etc.).
The dynamic form is created using labels and textboxes like this. It was designed only to display the information from the XML file, and I am trying to implement a system that allows users to edit the information before saving it again to the file. I'm doing alright with the methods to save and edit the XML file, but I'm lost for how to associate the input in any given textbox with the associated label representing the key in the XML file to change.
Below is the current form implementation where the labels and textboxes are created as part of a foreach loop. I tried creating textbox.Leave eventHandler to track when the user has finished changing a value, but I can't figure out how to know what label it is associated with.
var sortedSettings = new SortedDictionary<string, string>(theSettings.Settings);
int numSettings = sortedSettings.Count;
TextBox[] txt = new TextBox[numSettings];
Label[] label = new Label[numSettings];
int labelSpacing = this.labelSecond.Top - this.labelTop.Bottom;
int textSpacing = this.textBoxSecond.Top - this.textBoxTop.Bottom;
int line = 0;
foreach (KeyValuePair<string, string> key in sortedSettings)
{
label[line] = new Label();
label[line].Text = key.Key;
label[line].Left = this.labelTop.Left;
label[line].Height = this.labelTop.Height;
label[line].Width = this.labelTop.Width;
txt[line] = new TextBox();
txt[line].Text = key.Value;
txt[line].Left = this.textBoxTop.Left;
txt[line].Height = this.textBoxTop.Height;
txt[line].Width = this.textBoxTop.Width;
txt[line].ReadOnly = false;
// Attach and initialize EventHandler for template textbox on Leave
txt[line].Leave += new System.EventHandler(txt_Leave);
if (line > 0)
{
label[line].Top = label[line - 1].Bottom + labelSpacing;
txt[line].Top = txt[line - 1].Bottom + textSpacing;
}
else
{
label[line].Top = this.labelTop.Top;
txt[line].Top = this.textBoxTop.Top;
}
this.Controls.Add(label[line]);
this.Controls.Add(txt[line]);
line++;
}
private void txt_Leave(object sender, EventArgs e)
{
String enteredVal = sender;
FormUtilities.FindAndCenterMsgBox(this.Bounds, true, "EventChecker");
MessageBox.Show("The current value of LABEL is " + enteredVal, "EventChecker");
}
One option is to use TextBox.Tag property.
Example (in foreach loop):
txt[line] = new TextBox();
txt[line].Text = key.Value;
txt[line].Tag = label[line];
To get label associated with TextBox:
TextBox t = txt[0];
Label l = t.Tag as Label;
//Here is how you identify textbox which generated the event.
private void txt_Leave(object sender, EventArgs e)
{
TextBox tb = sender as TextBox;
//..
}

how to validate dynamically added controls in asp.net

I am adding some controls in my page while loading page.
Some of them are required, so I add requiredfieldvalidator control with them also.
But when I do postback using button click, at that time this dynamically added controls are not validated.
I am not able to understand what is wrong.
protected override void OnPreRender(EventArgs e) {
Panel pn = new Panel();
RadTextBox rdts = new RadTextBox {
ID = "txt" + txField.ColumnName,
Width = 200
};
pn.Controls.Add(rdts);
RequiredFieldValidator rfv = new RequiredFieldValidator {
ControlToValidate = "txt" + txField.ColumnName,
Display = ValidatorDisplay.Dynamic,
Text = "*",
ValidationGroup = "standard",
ID = "val" + txField.ColumnName,
Visible = true
};
pn.Controls.Add(rfv);
additionalDataPanel.Controls.Add(pn);
}
protected void ClickOK(object sender, EventArgs e) {
if (Page.IsValid){
return true;
}
else{
return false;
}
}
delete
ValidationGroup = "standard"
from RequiredFieldValidator
or add to text box
ValidationGroup = "standard"

Create dynamic dragpanel in asp.net with c#

I want to create ajax dragpanel dynamically and add the controls and panel dynamically.I used the below code for create the control dynamically.But I can`t able to drag it.
enter code here
protected void Page_PreInit(object sender, EventArgs e)
{
DragPanelExtender drg = new DragPanelExtender();
drg.ID = "drg_1";
drg.DragHandleID = "pnl_1";
drg.TargetControlID = "pnl_2";
Panel p1 = new Panel();
p1.ID = "pnl_1";
Panel p2 = new Panel();
p2.ID = "pnl_2";
Label l1 = new Label();
l1.Text = "First";
TextBox t = new TextBox();
t.Text = "Enter text";
p2.Controls.Add(l1);
p2.Controls.Add(t);
p1.Controls.Add(p2);
Page.Controls.Add(p1);
}
How to I create drag controls inside the panel

Trouble with Gridview

I am using a template to have create my gridview. I have have basically created a check box when once select creates a session variable and I then redirect the user to a separate page. The problem is the that the event is not firing off creating the wrapper.
The event:
void cmd1_Click(object sender, EventArgs e)
{
Button txtdata = (Button)sender;
inventoryBLL inv = new inventoryBLL();
GridViewRow gvr = (GridViewRow)txtdata.NamingContainer;
Label myControl = new Label();
TableCell tc = gvr.Cells[0];
// where GridView1 is the id of your GridView and indexOfCell is your index
foreach (Control c in tc.Controls)
{
if (c is Label)
{
myControl = (Label)c;
}
}
Label myControl1 = new Label();
List<string> shipmentnames = new List<string>();
List<string> asinlist = new List<string>();
List<string> fnskulist = new List<string>();
List<string> productlist = new List<string>();
shipmentnames.Add(inv.shipmentname(_ShipmentID));
asinlist.Add(myControl.Text);
asinwrapper asin1 = new asinwrapper(asinlist, fnskulist, productlist, 0);
asinwrapper.CreateSessionWrapper(asin1);
ShipmentWrapper.CreateSessionWrapper(new ShipmentWrapper(shipmentnames));
}
The code that I create the checkbox:
CheckBox cmd1 = new CheckBox();
cmd1.Text = "Change";
cmd1.CheckedChanged += new EventHandler(cmd1_Click);
cmd1.AutoPostBack = true;
container.Controls.Add(cmd1);
The code calling the template
bfield.HeaderTemplate = new GridViewTemplateShipmentItems(ListItemType.Header, "Change", FieldType.Label, ddlShipments.SelectedValue.ToString());
bfield.ItemTemplate = new GridViewTemplateShipmentItems(ListItemType.Item, "Change", FieldType.ButtonAdd, ddlShipments.SelectedValue.ToString());
grvList.Columns.Add(bfield);
bfield = new TemplateField();
Ok, so if I understood correctly, you have the checkbox embedded in a row of the Gridview, correct?
If so, you have to work with the gridview selected row event, (the checkbox events are now hidden and will not function as expected)
next find the checkbox
determine if the checkbox is checked
redirect the user.
I can get you more precise syntax if you like.

Multiview has Views added programmatically disappear when trying to change view

I have this code which adds a x number of views to a Multiview control. The Multiview control exist on the page with only one view. on page init I create x number of views with a GridView control added to each of these views when I come to loop through to find which one I want to show the Multiview control says it has only 1 view.
protected void variantRepeat_ItemCommand(object source, RepeaterCommandEventArgs e)
{
if (e.CommandSource.GetType() == typeof(LinkButton))
{
string theID = ((LinkButton)e.CommandSource).CommandArgument.ToString();
ViewCollection views = prodView.Views; //this has only 1 view the one that has been added on the source view of the .aspx page
foreach (View toDisplay in views)
{
if (toDisplay.ID == theID)
prodView.SetActiveView(toDisplay);
}
}
}
The code above loops to find the view and display it. Why do all the views disappear, I've stepped through and at init and after it has finished processing database queries it has x number of views > the 1 in source view.
Why does this control "lose" the views?
Init code:
protected void Page_Load(object sender, EventArgs e)
{
if (Request.QueryString == null || Request.QueryString.Count < 1)
Response.Redirect(Server.MapPath("~/Packages/"));
if (!Page.IsPostBack)
{
if (Request.QueryString["id"].ToString() == string.Empty)
Response.Redirect(Server.MapPath("~/Packages/"));
var id = Server.HtmlEncode(Request.QueryString["id"].ToString());
Guid packID = Guid.Parse(id);
using (var context = new GaleEntities())
{
var thePackage = context.PackageEnts.First(p => p.packageID == packID);
var theVariants = thePackage.Variants;
var mydatasource = new List<PackageEnt> { thePackage };
var myVariantDataSource = new List<Variant>();
foreach (Variant single in theVariants)
{
myVariantDataSource.Add(single);
}
packageForm.DataSource = mydatasource;
variantRepeat.DataSource = myVariantDataSource;
RenderProductGridviews(theVariants);
prodView.SetActiveView(prodView.Views[0]);
}
packageForm.DataBind();
variantRepeat.DataBind();
Page.DataBind();
}
}
protected void RenderProductGridviews(System.Data.Objects.DataClasses.EntityCollection<Variant> variantCol)
{
foreach (Variant packVar in variantCol)
{
View newView = new View();
GridView prodGrid = new GridView();
var myProdDataSource = new List<vw_VariantProduct>();
using (var context = new GaleEntities())
{
var singleProd1 = context.vw_VariantProduct.Where(vp => vp.variantID == packVar.variantID);
foreach (vw_VariantProduct extProd in singleProd1)
{
myProdDataSource.Add(extProd);
}
}
prodGrid.DataSource = myProdDataSource;
BoundField _column = new BoundField();
_column.DataField = "product_title";
_column.HeaderText = "Product";
prodGrid.Columns.Add(_column);
_column = new BoundField();
_column.DataField = "product_title";
_column.HeaderText = "Product";
prodGrid.Columns.Add(_column);
_column = new BoundField();
_column.DataField = "product_desc";
_column.HeaderText = "Description";
prodGrid.Columns.Add(_column);
_column = new BoundField();
_column.DataField = "product_time";
_column.HeaderText = "Time (mins)";
prodGrid.Columns.Add(_column);
_column = new BoundField();
_column.DataField = "quantity";
_column.HeaderText = "Quantity";
prodGrid.Columns.Add(_column);
prodGrid.DataBind();
newView.ID = packVar.variantID.ToString();
newView.Controls.Add(prodGrid);
prodView.Views.Add(newView);
}
}
Now, as usual almost all questions with the dynamic controls in ASP.Net words share the same common problem...
You need to create the dynamic controls on every post, you are only creating them the first time the page is loaded. Follow this simple rules:
Dynamic controls should be created in the PreInit event when you are not working with a master page, if you are, then create the controls in the Init event
Avoid setting properties that can be changed in each post in these events because when the view state is applied (in a post event) the properties will be overridden
Dynamic controls must be created every time the page is posted, avoid this if(!this.IsPostBack) this.CreatemyDynamicControls();
When you create the controls in the PreInit or Init events, their states will be automatically set in a post event, which means in the LoadComplete event your controls will contain their state back even when you create them again in each post and even when you did not explicitly set their state. Note this behavior is different when you are dealing with controls created at design time, in that case, the event where the state has been set is the Load event
Event subscription should occur before the PageLoadComplete or they will not be raised
I have posted several answers about dynamic controls:
https://stackoverflow.com/a/11127064/1268570
https://stackoverflow.com/a/11167765/1268570
Click events on Array of buttons
Button array disappears after click event
Dynamically create an ImageButton
This piece of code creates dynamic controls on-demand, and each control keeps its state on each post
public partial class DynamicControlsOnDemand : System.Web.UI.Page
{
public int NumberOfControls
{
get
{
if (this.ViewState["d"] == null)
{
return 0;
}
return int.Parse(this.ViewState["d"].ToString());
}
set
{
this.ViewState["d"] = value;
}
}
protected void Page_PreLoad(object sender, EventArgs e)
{
this.CreateDynamicControls();
}
protected void addControl_Click(object sender, EventArgs e)
{
this.NumberOfControls = this.NumberOfControls + 1;
this.myPanel.Controls.Add(this.CreateTextbox(this.NumberOfControls));
}
private void CreateDynamicControls()
{
for (int i = 0; i < this.NumberOfControls; i++)
{
var t = this.CreateTextbox(i + 1);
t.TextChanged += (x, y) => this.lblMessage.Text += "<br/>" + (x as TextBox).ID + " " + (x as TextBox).Text;
this.myPanel.Controls.Add(t);
}
}
private TextBox CreateTextbox(int index)
{
var t = new TextBox { ID = "myTextbox" + index.ToString(), Text = "de" };
return t;
}
}
ASPX
<asp:Panel runat="server" ID="myPanel">
</asp:Panel>
<asp:Button Text="Add Control" runat="server" ID="addControl" OnClick="addControl_Click" />
<asp:Label ID="lblMessage" runat="server" />
Output
You first code block where you are setting the active View is based on an ItemCommand event, so I'm assuming this fires during a PostBack?
Your code which adds the additional views within Page_Load is only running if not a post back. Try removing the conditional if(!Page.IsPostBack) statement. You need to add dynamic controls on every page lifecycle.

Categories