Creating Dynamic controls when changing the dropdown list items. - c# - c#

I have to show a ModalPopupExtender when changing the items of dropdownlist. The controls showing inside the ModalPopupExtender are dynamic controls including buttons. To fire the button click event for this dynamic buttons, I have introduced view state in the code.
Now when changing the item of dropdown list, ModalPopupExtender will come for first item correctly. And then, when changing the item, it throws error like below. How can I clear the previous dynamic controls when changing the dropdown list items?
Multiple controls with the same ID 'lbl1' were found. FindControl requires that controls have unique IDs.
protected async void Page_Load(object sender, EventArgs e)
{
if (ddl_Forms.SelectedItem.Value != "-1")
if (ViewState["viewstate_dynamic"] != null)
CreateDynamicControls();
}
protected void ddl_Forms_SelectedIndexChanged(object sender, EventArgs e)
{
CreateDynamicControls();
}
private async void CreateDynamicControls()
{
if (ddl_Forms.SelectedItem.Value != "-1")
{
url = baseUrl + "GetStructureJson?form_id=" + ddl_Forms.SelectedItem.Value.ToString();
using (var objClient = new HttpClient())
{
objClient.DefaultRequestHeaders.Add("Authorization", "Bearer " + objVariables.login_token);
using (var response = await objClient.GetAsync(url))
{
if ((int)response.StatusCode == 401)//unauthorised or token expired
{
Response.Redirect("Default.aspx");
}
if (response.IsSuccessStatusCode)
{
var jsonString = await response.Content.ReadAsStringAsync();
JavaScriptSerializer j = new JavaScriptSerializer();
object a = j.Deserialize(jsonString, typeof(object));
dict_values = JsonConvert.DeserializeObject<Dictionary<string, string>>(a.ToString());
int flag = 0;
foreach (KeyValuePair<string, string> entry in dict_values)
{
flag++;
TableRow row = new TableRow();
TableCell cell1 = new TableCell();
Label lbl = new Label();
lbl.ID = "lbl" + flag;
lbl.Text = entry.Key;
cell1.Controls.Add(lbl);
row.Cells.Add(cell1);
tbl_forms.Rows.Add(row);
}
TableRow row3 = new TableRow();
TableCell cell3 = new TableCell();
Button btn = new Button();
btn.ID = "btnSubmit2";
btn.Text = "Submit";
btn.Click += new System.EventHandler(this.ButtonsubmitForm2_Click);
btn.CssClass = "button_green";
cell3.Controls.Add(btn);
Button btn2 = new Button();
btn2.ID = "btnCancel2";
btn2.Text = "Cancel";
btn2.Click += new EventHandler(btn_Cancel_allocate2_Click);
btn2.Style.Add("margin-left", "20px");
cell3.Controls.Add(btn2);
row3.Cells.Add(cell3);
tbl_forms.Rows.Add(row3);
**ViewState.Add("viewstate_dynamic", true);**
mp2.Show(); //modalpopuextender
}
}
}
}
}

Related

FindControl() returns null when searching for dynamic control

In my requirement I am creating dynamic controls by two events
Dropdownlist OnSelectedIndexChanged event
Onclick button event
In OnSelectedIndexChanged event i have created number of dynamic textbox.
Here I have create two dynamic textboxes.
I am getting all enquiry product list based on enquiry number from the dynamic textboxes on button click event
All are dynamic controls
While saving the productlist the checkbox control return null value
protected void ddlenqChaged(object sender, EventArgs e)
{
getenqTextbox();
}
protected void btnSearchClick(object sender, EventArgs e)
{
tblbill.Visible = true;
if (Convert.ToString(ViewState["Generated"]) != "true")
{
CreateDynamicControls();
ViewState["Generated"] = "true";
}
}
protected void getenqTextbox()
{
enqPanel.Controls.Clear();
if (Convert.ToInt32(ddlNoofEnq.SelectedValue) > 0)
{
for (int i = 1; i <= Convert.ToInt32(ddlNoofEnq.SelectedValue); i++)
{
TextBox _txtCode = new TextBox();
_txtCode.ID = "txtEnqqNo" + i;
_txtCode.Attributes.Add("ClientIDMode", "Static");
_txtCode.Width = 75;
_txtCode.CssClass = "AtCompleteByEnq";
enqPanel.Controls.Add(_txtCode);
}
}
}
protected void CreateDynamicControls()
{
int m = 1;
//int encount = click.buttonclick;
if (Convert.ToInt32(ddlNoofEnq.SelectedValue) > 0)
{
Table tbldynamic = new Table();
for (int k = 1; k <= Convert.ToInt32(ddlNoofEnq.SelectedValue); k++)
{
Panel1.Controls.Clear();
TextBox tb = (TextBox)enqPanel.FindControl("txtEnqqNo" + k);
if (tb != null)
{
if (!String.IsNullOrEmpty(tb.Text))
{
List<Enquiry_ProductListBLL> objlst = Enquiry_ProductListBLL.GetEnquiry_ProductListBLLs(tb.Text);
foreach (Enquiry_ProductListBLL item in objlst)
{
TableRow tr = new TableRow();
TableCell tc = new TableCell();
TableCell tc1 = new TableCell();
TableCell tc2 = new TableCell();
TableCell tc3 = new TableCell();
TableCell tc4 = new TableCell();
TableCell tc5 = new TableCell();
TableCell tc6 = new TableCell();
Master_ProductBLL objpdt = Master_ProductBLL.GetMaster_ProductBLL(item.ProductId);
CheckBox _chkRowNo = new CheckBox();
_chkRowNo.ID = "chkRowNo" + m;
_chkRowNo.Text = m.ToString();
_chkRowNo.Attributes.Add("ClientIDMode", "Static");
_chkRowNo.Attributes.Add("onclick", "getEnable(this);");
_chkRowNo.Checked = true;
TextBox _txtCode = new TextBox();
_txtCode.ID = "txtCodeRow" + m;
_txtCode.Attributes.Add("ClientIDMode", "Static");
_txtCode.Enabled = false;
_txtCode.Width = 75;
_txtCode.Attributes.Add("autocomplete", "off");
_txtCode.Text = objpdt.Code;
HiddenField _hdnPdtId = new HiddenField();
_hdnPdtId.ID = "hdnPdtId" + m;
_hdnPdtId.Value = item.ProductId.ToString();
HiddenField _hdEnqNo = new HiddenField();
_hdEnqNo.ID = "hdEnqNo" + m;
_hdEnqNo.Value = item.EnqNo;
_hdnPdtId.Value = item.ProductId.ToString();
TextBox _txtPdtName = new TextBox();
_txtPdtName.ID = "txtPdtNameRow" + m;
_txtPdtName.Attributes.Add("ClientIDMode", "Static");
_txtPdtName.Enabled = false;
_txtPdtName.Width = 150;
_txtPdtName.CssClass = "AtCompleteByName";
_txtPdtName.Text = objpdt.Name;
TextBox _txtQty = new TextBox();
_txtQty.ID = "txtQtyRow" + m;
_txtQty.Width = 80;
_txtQty.MaxLength = 8;
_txtQty.Attributes.Add("ClientIDMode", "Static");
//_txtQty.Attributes.Add("onblur", "GetTotal(this)");
//_txtQty.Enabled = false;
_txtQty.Text = item.Count.ToString();
DropDownList ddlUnits = new DropDownList();
ddlUnits.ID = "ddlUnits" + m;
ddlUnits.CssClass = "dropdowncss";
ddlUnits.Width = 100;
Bindings.BindUnitName(ddlUnits);
ddlUnits.Items.FindByText(item.PP).Selected = true;
tc.Controls.Add(_chkRowNo);
tc1.Controls.Add(_txtCode);
tc2.Controls.Add(_txtPdtName);
tc2.Controls.Add(_hdnPdtId);
tc2.Controls.Add(_hdEnqNo);
tc3.Controls.Add(_txtBrand);
tc4.Controls.Add(_txtThickness);
tc5.Controls.Add(ddlUnits);
tc6.Controls.Add(_txtQty);
tc.Attributes.Add("Width", "50px");
tr.Attributes.Add("id", "Rowid" + m);
tr.Attributes.Add("class", "paidRw");
tr.Cells.Add(tc);
tr.Cells.Add(tc1);
tr.Cells.Add(tc2);
tr.Cells.Add(tc3);
tr.Cells.Add(tc4);
tr.Cells.Add(tc5);
tr.Cells.Add(tc6);
tbldynamic.Rows.Add(tr);
m++;
}
}
}
}
Panel1.Controls.Add(tbldynamic);
}
}
Here I have override OnLoad event
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
CreateDynamicControls();
getenqTextbox();
}
My problem is i cannot find controls from Panel1
CheckBox chk = (CheckBox)Panel1.FindControl(chkId);
if (chk != null)
{
if (chk.Checked == true)
{
//my process
}
}
FindControl returns null value.
Here I have create dynamic controls two times.
I cannot have any problem with enquiry textbox, it was created first, but the second time button click event controls are return null.
FindControl does not walk the hierarchy.
See doc Control.FindControl()
This method will find a control only if the control is directly contained by the specified container; that is, the method does not search throughout a hierarchy of controls within controls.
Since your CheckBox is not a first-level child of the Panel, it cannot be retrieved this way. If you need a generic solution, I suggest to implement a recursive FindControl.

Creating dynamic controls on Page_LoadComplete

I have three drop down lists and depending on the values selected in the lists I create dynamic controls accordingly. Everything displays properly but when I click on the dynamically created button the events are not firing. I am using the Page_LoadComplete to create the dynamic controls because I need to the values from the DDL's. Is this the reason for my button events not firing?
protected void Page_LoadComplete(object sender, EventArgs e)
{
queries = new clsFormQueries();
if (HttpContext.Current.User.IsInRole("Admin"))
{
if (!Page.IsPostBack)
{
List<Sport> sports = ComboBoxOptions.getSports();
DropDownList temp = (DropDownList)loginView2.FindControl("Sport");
temp.DataSource = sports;
temp.DataTextField = "Name";
temp.DataValueField = "id";
temp.DataBind();
DropDownList teamsDD = (DropDownList)loginView2.FindControl("Team");
List<Team> teamsList = ComboBoxOptions.getTeamsBySportId(Convert.ToInt32(temp.SelectedValue));
teamsDD.DataSource = teamsList;
teamsDD.DataTextField = "fullName";
teamsDD.DataValueField = "teamId";
teamsDD.DataBind();
DropDownList existingPlayers = (DropDownList)loginView2.FindControl("ExistingPlayers");
List<Player> players = ComboBoxOptions.getPlayersBySport(Convert.ToInt32(temp.SelectedValue), Convert.ToInt32(teamsDD.SelectedValue));
existingPlayers.DataSource = players;
existingPlayers.DataTextField = "fullName";
existingPlayers.DataValueField = "playerid";
existingPlayers.DataBind();
//if (existingPlayers.SelectedValue != "" && temp.SelectedValue != "")
//{
// DataTable updates = queries.GetPlayerUpdate(Convert.ToInt32(existingPlayers.SelectedValue), Convert.ToInt32(temp.SelectedValue));
// if (updates.Rows.Count > 0)
// CreateUpdatesHTML(updates);
//}
}
DropDownList temp2 = (DropDownList)loginView2.FindControl("Sport");
DropDownList existingPlayers2 = (DropDownList)loginView2.FindControl("ExistingPlayers");
if (existingPlayers2.SelectedValue != "" && temp2.SelectedValue != "")
{
DataTable updates = queries.GetPlayerUpdate(Convert.ToInt32(existingPlayers2.SelectedValue), Convert.ToInt32(temp2.SelectedValue));
if (updates.Rows.Count > 0)
CreateUpdatesHTML(updates);
}
}
}
private void CreateUpdatesHTML(DataTable updates)
{
foreach (DataRow update in updates.Rows)
{
int playerUpdateId = (int)update["playerUpdateId"];
string updateText = update["PlayerUpdate"].ToString();
TextBox tb = new TextBox();
tb.ID = "UpdateText" + playerUpdateId;
tb.TextMode = TextBoxMode.MultiLine;
tb.Rows = 5;
tb.Text = updateText;
tb.CssClass = "span5";
Button btnDelete = new Button();
btnDelete.Click += new EventHandler(btnDelete_Click);
btnDelete.ID = "Delete"+playerUpdateId.ToString();
btnDelete.Text = "Delete";
btnDelete.CssClass = "btn btn-info";
Button btnUpdate = new Button();
btnUpdate.Click += new EventHandler(btnUpdate_Click);
btnUpdate.ID = "Update"+playerUpdateId.ToString();
btnUpdate.Text = "Update";
btnUpdate.CssClass = "btn btn-info";
HtmlGenericControl div2 = new HtmlGenericControl("div");
div2.Attributes.Add("class", "pull-right span5");
div2.Controls.Add(btnDelete);
div2.Controls.Add(btnUpdate);
HtmlGenericControl hr = new HtmlGenericControl("hr");
HtmlGenericControl br = new HtmlGenericControl("br");
existingUpdates.Controls.Add(tb);
existingUpdates.Controls.Add(div2);
existingUpdates.Controls.Add(br);
existingUpdates.Controls.Add(hr);
}
}
My guess is that since you have wrapped the logic for your Page_LoadComplete event inside of a n if(!Page.IsPostBack), since the click of the button causes a postback, your dynamically created controls are not recreated properly (read: no click event handling is wired up). You need to have logic on every invocation of Page_LoadComplete (non-postback or postback) that recreates the dynamic controls and wires up their events.

add text box dynamically and capture data on button click

I am adding text boxes dynamically and trying to capture data entered in text box on button click. but what is happening is , though I entered the data in the text box, when I clicked the button, the page is getting loaded and the control is getting created again. As a result , I am loosing the data in the text box. Can you tell me how can I capture this data entered to the dynamically created text boxes.
My sample code is as follows:
protected void Page_Load(object sender, EventArgs e)
{
Table tblTextboxes = new Table();
for(int i=0;i<10;i++)
{
TableRow tr=new TableRow();
TableCell tc=new TableCell();
TextBox tb=new TextBox();
tb.ID=i.ToString();
tc.Controls.Add(tb);
tr.Cells.Add(tc);
TableCell tc1=new TableCell();
LinkButton lnk=new LinkButton();
lnk.ID=i.ToString()+tb.Text+"lnk";
lnk.Text = "Show";
lnk.Click+=new EventHandler(lnk_Click);
tc1.Controls.Add(lnk);
tr.Cells.Add(tc1);
tblTextboxes.Rows.Add(tr);
}
placeTest.Controls.Add(tblTextboxes);
}
void lnk_Click(object sender, EventArgs e)
{
LinkButton lnk=sender as LinkButton;
Label lbl=new Label();
lbl.Text="The text is"+lnk.ID;
placeTest.Controls.Add(lbl);
}
LinkButton ID is changed every time you enter text into TextBox and post back.
One thing you want to make sure when creating control dynamically is - you want to recreate them with same ID when post back.
Updated Solution (to retrieve text from TextBox)
protected void Page_Load(object sender, EventArgs e)
{
var tblTextboxes = new Table();
for (int i = 0; i < 10; i++)
{
var tr = new TableRow();
var tc = new TableCell();
var tb = new TextBox {ID = i.ToString()};
tc.Controls.Add(tb);
tr.Cells.Add(tc);
var tc1 = new TableCell();
// This is a fix for - lnk.ID=i.ToString()+tb.Text+"lnk";
var lnk = new LinkButton {ID = i + "lnk", Text = "Show"};
lnk.Click += lnk_Click;
tc1.Controls.Add(lnk);
tr.Cells.Add(tc1);
tblTextboxes.Rows.Add(tr);
}
placeTest.Controls.Add(tblTextboxes);
}
void lnk_Click(object sender, EventArgs e)
{
var lnk = sender as LinkButton;
var lbl = new Label();
lbl.Text = "LinkButton ID: " + lnk.ID;
// Get number value from string
string id = Regex.Replace(lnk.ID, #"[^\d]", "");
// Retrieves a TextBox control by ID
var control = FindControlRecursive(Page, id);
if (control != null)
{
var textbox = control as TextBox;
lbl.Text += "; TextBox Text: " + textbox.Text;
}
placeTest.Controls.Add(lbl);
}
public Control FindControlRecursive(Control root, string id)
{
if (root.ID == id)
return root;
return root.Controls.Cast<Control>()
.Select(c => FindControlRecursive(c, id))
.FirstOrDefault(c => c != null);
}
Based on the MSDN, I would recommend to use Page class's Init event. Look in to the title View State and Dynamically Added Controls for explanation. Also, I would recommend to add dynamic controls at the end of all existing controls. Create table first, and then add the text boxes.
I modified your code. It worked for me. I used VS 2012, .Net 4.5
protected void Page_Load(object sender, EventArgs e)
{
Response.Write(DateTime.Now.ToString());
}
protected void Page_Init(object sender, EventArgs e)
{
Table tblTextboxes = new Table();
for (int i = 0; i < 10; i++)
{
TableRow tr = new TableRow();
TableCell tc = new TableCell();
TextBox tb = new TextBox();
tb.ID = i.ToString();
tc.Controls.Add(tb);
tr.Cells.Add(tc);
//TableCell tc1 = new TableCell();
//LinkButton lnk = new LinkButton();
//lnk.ID = i.ToString() + tb.Text + "lnk";
//lnk.Text = "Show";
//lnk.Click += new EventHandler(lnk_Click);
//tc1.Controls.Add(lnk);
//tr.Cells.Add(tc1);
tblTextboxes.Rows.Add(tr);
}
placeTest.Controls.Add(tblTextboxes);
}
protected void Button1_Click(object sender, EventArgs e)
{
}

GridView RowCommand Events not firing when button created with an external class

Ok The problem is I have a grid that I need to have paging on it with pages shown as numbers
I want to add two link button to the paging section to alow user to navigate to next page prev page
Here is my code
protected void CustomerGridView_RowCreated(object sender, GridViewRowEventArgs e)
{
var grid = sender as GridView
if (e.Row.RowType == DataControlRowType.Pager)
{
var prvLink = new LinkButton();
prvLink.Text = "<";
prvLink.CommandName = "Page";
prvLink.CommandArgument = "Prev";
prvLink.EnableViewState = true;
var nextLink = new LinkButton();
nextLink.Text = ">";
nextLink.CommandName = "Page";
nextLink.CommandArgument = "Next";
nextLink.EnableViewState = true;
var prvCell = new TableCell();
var nextCell = new TableCell();
prvCell.Controls.Add(prvLink);
nextCell.Controls.Add(nextLink);
Table pagerTable = e.Row.Controls[0].Controls[0] as Table;
TableRow row = pagerTable.Rows[0];
row.Cells.AddAt(0, prvCell);
row.Cells.AddAt(row.Cells.Count, nextCell);
if (grid.PageIndex == 0)
{
prvCell.Enabled = false;
}
if (grid.PageIndex == grid.PageCount - 1)
{
nextCell.Enabled = false;
}
}
}
its perfectly working and users are able to navigate back and forward (and I can see grid RowCommand event getting fired)
The problem is I do not want to put the code inside my page (to make my page tiny and put the responsibility to an other class )
here is my class
public class GridStyler
{
private GridView _grid;
public GridStyler(GridView grid)
{
_grid = grid;
}
public void AddNextPreviousOnPager()
{
_grid.RowCreated += _grid_RowCreated;
}
void _grid_RowCreated(object sender, GridViewRowEventArgs e)
{
var grid = sender as GridView;
if (e.Row.RowType == DataControlRowType.Pager)
{
var prvLink = new LinkButton();
prvLink.Text = "<";
prvLink.CommandName = "Page";
prvLink.CommandArgument = "Prev";
prvLink.EnableViewState = true;
var nextLink = new LinkButton();
nextLink.Text = ">";
nextLink.CommandName = "Page";
nextLink.CommandArgument = "Next";
nextLink.EnableViewState = true;
var prvCell = new TableCell();
var nextCell = new TableCell();
prvCell.Controls.Add(prvLink);
nextCell.Controls.Add(nextLink);
Table pagerTable = e.Row.Controls[0].Controls[0] as Table;
TableRow row = pagerTable.Rows[0];
row.Cells.AddAt(0, prvCell);
row.Cells.AddAt(row.Cells.Count, nextCell);
if (grid.PageIndex == 0)
{
prvCell.Enabled = false;
}
if (grid.PageIndex == grid.PageCount - 1)
{
nextCell.Enabled = false;
}
}
}
}
then I should be able to call a code like that in my page load and it should create the link buttons and response to click of them
var g = new GridStyler(CustomerGridView);
g.AddNextPreviousOnPager();
what happens is the link buttons are created just fine but when user clicks them page get refreshed but RowCommand never get fired (they get fired of course when user clicks other buttons but not this two dynamically created buttons)
Any suggestion is really appreciated

Cant fire dropDownList selectionChange event from Backend

I'm not able to fire the method on Selection-change. I'm adding the DropDownList itself from code behind. Code :
private TableCell CreateMTPLTypeCell(int insurerId, string MTPLType)
{
TableCell rg = new TableCell();
rg.ID = string.Concat("rg_", insurerId);
rg.CssClass = "formItem";
//if (insurerId == 14)
//{
DropDownList ddl = new DropDownList();
ddl.ID = "MTPLTypes";
ddl.Items.Add(new ListItem("Standard", "1")); // add list items
ddl.Items.Add(new ListItem("DubultOCTA", "2"));
ddl.Items.Add(new ListItem("DubultOCTA+vējst", "3"));
//ddl.SelectedIndex =
// ddl.Items.IndexOf(ddl.Items.
// FindByValue(MTPLType));
ddl.SelectedIndexChanged += new EventHandler(MTPLType_selectedIndexChange);
ddl.AutoPostBack = true;
rg.Controls.Add(ddl);
//}
return rg;
}
void MTPLType_selectedIndexChange(object sender, EventArgs e)
{
DropDownList ddl = (DropDownList)sender;
int insurerId = Int32.Parse(ddl.ID.Replace("rg_", ""));
MTPLQuotes quotes = proposal.Properties.MtplQuotes[insurerId];
if (quotes == null) return;
proposal.GetSingleMTPLQuote(insurerId, Helpers.PortalUtilities.CurrentUser, BrokerInfo.GetBrokerInfo().Country.ID);
DrawMtplQuotes(mtplPaymentMappingsCount > 0);
}
Do I miss some extra parameters on DropDownList object ?
Atm it works like that: After selectionChange it starts "loading" but it dosnt reach to the method. :/
In same class i have antoher tableCell with onChange event (Text_Change) -> this works ok.
private TableCell CreateInsurerMtplDiscountCell(int insurerId, decimal discount)
{
TableCell c = new TableCell();
c.CssClass = "formItem";
c.Style[HtmlTextWriterStyle.PaddingLeft] = "25px";
TextBox txt = new TextBox();
txt.ID = string.Format("ins_disc_{0}", insurerId);
txt.Text = discount > 0 ? discount.ToString() : "";
txt.TextChanged += new EventHandler(insurerDiscountPercent_TextChanged);
txt.AutoPostBack = true;
txt.Width = new Unit(40);
c.Controls.Add(txt);
Literal l = new Literal();
l.Text = "%";
c.Controls.Add(l);
return c;
}
void insurerDiscountPercent_TextChanged(object sender, EventArgs e)
{
TextBox txt = (TextBox)sender;
int insurerId = Int32.Parse(txt.ID.Replace("ins_disc_", ""));
MTPLQuotes quotes = proposal.Properties.MtplQuotes[insurerId];
if (quotes == null) return;
decimal discountPercent;
if (!Decimal.TryParse(txt.Text, out discountPercent))
discountPercent = 0;
quotes.InsurerDiscountPercent = discountPercent;
foreach (MTPLQuote quote in quotes.Quotes)
ApplyMtplInsurerDiscount(quote, discountPercent);
DrawMtplQuotes(mtplPaymentMappingsCount > 0);
}
Got it fixed - The problem was about TableCell.ID (rg.ID = string.Concat("rg_", insurerId);) . After removing it everything worked fine. Anyone know why is that so ?
I think you have to refresh your Website after creating a new control.
i would suggesst you to use AJAX-updatepanels (so you dont have to refresh the whole site).
to add the OnChanged-Event Name you should also be able to add a string Name instead of the eventhandler itselfe.
ddl.SelectedIndexChanged = "MTPLType_selectedIndexChange";
I think you have to use "protected void" instead of "private void" its not reachable for the control cause of the permission restriction.
You should be binding your SelectedIndexChanged event to the dropdown list on the Page_PreInit event.
Then it should work.

Categories

Resources