C# dynamically created control issue - c#

i'm having issues retreiving the values out of a dynamically created dropdownlist. all controls are created in the Page_Init section. the listitems are added at that time as well from an array of listitems. (the controls are named the same so should be accessable to the viewstate for appropriate setting.)
here is the function that attempts to retrieve the values:
protected void Eng98AssignmentComplete_Click(object sender, EventArgs e)
{
String myID = "0";
Page page = Page;
Control postbackControlInstance = null;
// handle the Button control postbacks
for (int i = 0; i < page.Request.Form.Keys.Count; i++)
{
postbackControlInstance = page.FindControl(page.Request.Form.Keys[i]);
//Response.Write(page.Request.Form.Keys[i].ToString());
if (postbackControlInstance is System.Web.UI.WebControls.Button)
{
myID = Convert.ToString(
postbackControlInstance.ID.Replace("button_", ""));
}
}
String txtholder = "ctl00$ContentPlaceHolder$Eng098Instructors_" + myID;
Response.Write("MYID: " + myID + "<br/>");
DropDownList ddInstructorCheck = (DropDownList)Page.FindControl(txtholder);
Response.Write("Instructor Selected: "
+ ddInstructorCheck.SelectedValue + "<br/>");
}
here is the output I get, no matter which instructor was selected.....
MYID: 1_1
Instructor Selected: 0
ctl00$ContentPlaceHolder$Eng098Instructors_1_1
the name of the control is correct (verified via view source)....
ideas?

You're going to a lot of work to build this fancy string:
ctl00$ContentPlaceHolder$Eng098Instructors_1_1
That is the client ID of your control, not the server id. This code is running on the server side, and so you need the server id. To get that control using the server id, you need to do this:
ContentPlaceHolder.FindControl("Eng08Instructors_1_1");
Notice I didn't look in the page, because your content place holder created a new naming container.
Also, the way your loop is set up the myID variable will always end up holding the last button in the Keys collection. Why even bother with the loop?
Based on your comments, a better way to find the id of the dropdownlist is like this:
string id = ((Control)sender).ID.Replace("button_", "Eng098Instructors_");

why not just save the control in an instance in your class so that you don't have to use FindControl?

Do you also re-create the controls during the postback? Dynamically generated/added controls must be re-created with every request, they are not automatically re-created.

Why don't you cast the sender? This should be the button that caused the postback:
string myId = "0";
Button btn = sender as Button;
if (btn != null)
myId = btn.ID
...

You need to perform something like this because the UniqueID property is the key in Request.Form.
List<Button> buttons = new List<Button>();
List<DropDownList> dropdowns = new List<DropDownList>();
foreach (Control c in Controls)
{
Button b = (c as Button);
if (b != null)
{
buttons.Add(b);
}
DropDownList d = (c as DropDownList);
if (d != null)
{
dropdowns.Add(d);
}
}
foreach (String key in Request.Form.Keys)
{
foreach (Button b in buttons)
{
if (b.UniqueID == key)
{
String id = b.ID.Replace("button_", "");
String unique_id = "ctl00$ContentPlaceHolder$Eng098Instructors_" + id;
Response.Write("MYID: " + id + "<br/>");
foreach (DropDownList d in dropdowns)
{
if (d.UniqueID == unique_id)
{
Response.Write("Instructor Selected: " + d.SelectedValue + "<br/>");
break;
}
}
}
}
}

I'm not sure why you are generating the control in code (you can still add items dynamically if you do), but the code that generates the controls would probably be a huge help here. I'm guessing you are not setting the list item value, and instead just setting the list item text. Try seeing what you get from the SelectedText field and post your control creation function.
EDIT:
In response to your comment on #Martin's post, you said "yes I recreate the controls in the Page_Init function each time the page is created (initial or postback)". Are you also setting the selected value when you create them?
You can also use controls on the page even if your data comes from a database, the controls themselves don't have to be dynamically generated.

How about this?
((Button)sender).Parent.FindControl(myid)
Edit:I misunderstood your question. But i think you should follow page lifecycle. it is common issue for dynamically created controls.
I did some research and here is some info about Dynamically Created Controls may help you...

I had 2 catches.... here's what they were.
1. I didn't clear the table I was adding to before re-creating the controls.
apparently my attention to detail was off yesterday, i'm pretty sure the ctlXX frontrunner of the control was some different number upon postback due to how I was recreating the controls.
2. I was assigning the same list to all the dropdownlist controls.
once I called the lookup upon each creation a dropdownlist control, all works well.
anyway for what it's worth....

Related

ASP.net web page update issue ( Postback?)

Greeting of the day everyone.
Hoping you are all well. I need your help to solve a simple issue ( I an new to C# + ASP.net).
I have created a ASp.net portal. When a user open that portal (web page). the Webpage give him a list of Groups whose he is the member of and the list of group whose he can add to himself..
It also contain two Drop Downs. One contains the list of groups, whose use can add to themselves. The second one contains the list of groups , whose the user is member of, and he can remove it from those groups.
Adding and removing code is working fine. But I have to refresh the page manually to show the updated information. After clicking the Add or Remove Button page is not refreshing with the updated information.
I tried to use redirected to main page using Response.Redirect("Success.aspx")
But nothing working,
protected void Page_Load(object sender, EventArgs e)
{
string uN = "domain\\michael.jackson";
//SystemResources sr = new SystemResources();
//ActiveUser usr = sr.GetUserDetails(uN).FirstOrDefault();
LabelUserName.Text = "michael.jackson";
// Getting the list of groups using of praticular OU the classOrgUnitGroup
string sdomain = ClassGroupPortalSettings.getDomainName();
string sInterstOU = "OU=testing,DC=analysys,DC=com";
classOrgUnitGroup a = new classOrgUnitGroup();
List<string> allGroups = a.GetGroupFromOu(sdomain, sInterstOU);
string grouplist = "<ul>";
foreach (string group in allGroups)
{
grouplist = grouplist + "<li><a href='showgroupmembers.aspx?group=" + group + "'>" + group + "</a></li>";
}
grouplist = grouplist + "</ul>";
lblOpenGroups.Text = grouplist;
//// 4. Finding users group membership.
string sDomain = ClassGroupPortalSettings.getDomainName();
classUserGroupMembership myMembership = new classUserGroupMembership();
List<string> myGroupsMem = myMembership.getMyGroupMembership(sDomain, "domain\\michael.jackson");
string glList = "<ul>";
string openlList = "<ul>";
string otherGroup = "<ul>";
foreach (string grp in myGroupsMem)
{
//BulletedListMyGroups.Items.Add(grp);
glList = glList + "<li>" + grp + "</li>";
if (allGroups.Contains(grp))
{
DropDownListMyGroups.Items.Add(grp);
openlList = openlList + "<li>" + grp + "</li>";
}
else
{
otherGroup = otherGroup + "<li>" + grp + "</li>";
}
}
glList = glList + "</ul>";
openlList = openlList + "</ul>";
otherGroup = otherGroup + "</ul>";
LabelOtherGrp.Text = otherGroup;
LabelOpenGrp.Text = openlList;
// LabelMyGroup.Text = glList;
foreach (string emailGroup in allGroups)
{
if (!myGroupsMem.Contains(emailGroup))
{
DropDownListOpenGroups.Items.Add(emailGroup);
}
}
}
This is code which run when a page reload.
The issue is : When I click on Remove Button or Add Button, it run the code to add or remove user from selected group. when page reload after clicking on button. The Group membership labels. and Dropdown box is not updating with code :(
I'm assuming your scenario like this, you're having two Drop down. One is full of records and the items can be select. Once items are selected, user will submit the button then records will save into database/xml. Later you're retrieving the items from db/xml and showing that in second Drop down.
Now you're issue is that the records are not showing in second Drop down after clicking the submit button,
If it so, you have two options.
1) You can pull your records as soon as insert things made into db.
2) You can pull your records in Page load itself as I mentioned below,
If(Postback) // Or If(PostBack == true)
{
// Pull your records and display in Drop down.
}
It is just the order of events which causing confusion IMO. Page_Load is called first and then control events(click, change etc). So on add/delete you need to rebind the items.
https://msdn.microsoft.com/en-gb/library/ms178472%28v=vs.100%29.aspx
Move out the data bind logic to a function and call function at the end of click event as well. Then you can reuse the function in page load and put logic to bind in page load only of its not postback because you might be rebinding unnecessarily in page load.
protected void Page_Load(object sender, EventArgs args)
{
if(!IsPostBack)
{
DataBindLogic();
}
}
private void DataBindLogic()
{
/*Put databind code here */
}
protected void RemoveBtn_Click(Object sender,Eventargs args)
{
/*Do db update */
DataBindLogic();
}
Thanks a lot everyone and and each of you for your time and help and energy, thanks a ton.
The issue is resolved, I have added another lines of code in the Postback, which checks the action of the User.
For example, if used Remove from the Group,
Then get the name of the Group and use action REMOVE
Then Update the DropDown box and Current membership box.
I did the same for the add group too, and it resolved the issue for me.
Thanks again , and whishing you a great day ahead.
Regards and Best wishes
Aman

Can we dynamically reference element (Server Side)

Say I have the elements with the ID's of "Input1", "Input2" and "Input3".
Is there a way to loop through them rather then having to write:
Input1.Value = 1;
Input2.Value = 1;
Input3.Value = 1;
in jquery you can just refrence an element like $('#Input'+i) and loop through i, something similar would be very useful in ASP code behind.
Edit: Duh, I searched again for finding all "x" controls on page and came up with the following source code:
foreach(Control c in Page.Controls)
{
if (c is TextBox)
{
// Do whatever you want to do with your textbox.
}
}
Kind of ... based on your example naming scheme you can do something like the following:
private void Button1_Click(object sender, EventArgs MyEventArgs)
{
string controlName = TextBox
for(int i=1;i<4;i++)
{
// Find control on page.
Control myControl1 = FindControl(controlName+i);
if(myControl1!=null)
{
// Get control's parent.
Control myControl2 = myControl1.Parent;
Response.Write("Parent of the text box is : " + myControl2.ID);
}
else
{
Response.Write("Control not found");
}
}
}
This will let you loop through numerically named controls but otherwise it is somewhat clunky.
If you know the parent container you can loop though its .Controls() property. If you start at the Page level and work recursively, you can eventually reach all controls on the page.
See the answer from this question for more details.
I like to keep things strongly typed, so I store them in a list. This makes the code more resilient to refactoring and there's no need to cast. It takes a slight bit more upfront work to put all your controls into the list, but to me it's often worth it.
I'm not sure what type your controls are, so I'm going to pretend they're of type Input.
var InputControls = new List<Input>(){Input1, Input2, Input3};
foreach(var input in InputControls)
{
input.Value = 1;
}

RequiredFieldValidator not working in a repeater

I'm trying to dynamically add a RequiredFieldValidator to a RadioButtonList in a repeater, but it fails with the error:
Unable to find control id 'rblAccessory_40' referenced by the 'ControlToValidate' property of ''.
The code for this section is:
if ((e.Item.ItemType != ListItemType.Header) && (e.Item.ItemType != ListItemType.Footer))
{
Label lblAccID = (Label)e.Item.FindControl("lblAccID");
RadioButtonList rblCondition = (RadioButtonList)e.Item.FindControl("rblCondition");
rblCondition.ID = "rblAccessory_" + lblAccID.Text;
if (conditionList.Count() > 0)
{
RequiredFieldValidator rfv = new RequiredFieldValidator();
rfv.ControlToValidate = "rblAccessory_" + lblAccID.Text;
rfv.ErrorMessage = "Please complete the accessories section";
pnlValidation.Controls.Add(rfv);
rblCondition.DataSource = conditionList;
rblCondition.DataValueField = "id";
rblCondition.DataBind();
}
foreach (ListItem li in rblCondition.Items)
{
li.Text = "";
li.Value = "AccessoryID_" + lblAccID.Text + "-ConditionID_" + li.Value;
}
}
}
It is definitely finding the RadioButtonList (rblCondition) because the data is binding correctly at this point:
rblCondition.DataSource = conditionList;
rblCondition.DataValueField = "id";
rblCondition.DataBind();
So I don't understand why the error says it is unable to find the control ID.
I've tried specifying the control ID manually, as below:
rfv.ControlToValidate = "rblAccessory_" + lblAccID.Text;
and have also tried:
rfv.ControlToValidate = rblCondition.ID;
lblAccID is a hidden text field used to store the ID of the row in the repeater.
Assign the control to validate property AFTER the ItemCreated event. I know this sounds weird, how would you still have the reference to the dynamically created control? I've gotten around this by keeping a reference to a List<Action> reference which I add things to during ItemCreated to be executed later.
In your control class you'll declare your List<Action> object:
List<Action> deferringControlToValidateUntilPreRender = new List<Action>();
Inside the ItemCreated event you'll have a line that looks like:
deferringControlToValidateUntilPreRender.Add(() => rfv.ControlToValidate = rblCondition.UniqueID);
And then, later, perhaps in PreRender:
foreach(var deferredAction in deferringControlToValidateUntilPreRender) action();
Since the RequiredFieldValidator is client-side code, you need to use the client id of the control. Like this:
rfv.ControlToValidate = rblCondition.ClientID;
Some more information from MSDN if you are interested:
Control.ClientIDMode Property
Also, an SO discussion on the differences between ClientID and UniqueID (as referenced in #MushinNoShin's answer, which, IMHO, is incorrect):
Why is there a difference between ClientID and UniqueID?

Asp.Net Get Control Values from PlaceHolder

I have defined a placeholder in my page like this;
<asp:PlaceHolder ID="attrPlaceHolder" runat="server"></asp:PlaceHolder>
I am populating this place holder from a database table using query string productId like this;
// obtain the attributes of the product
DataTable attrTable = CatalogAccess.GetProductAttributes(productId);
// temp variables
string prevAttributeName = "";
string attributeName, attributeValue, attributeValueId;
// current DropDown for attribute values
Label attributeNameLabel;
DropDownList attributeValuesDropDown = new DropDownList();
// read the list of attributes
foreach (DataRow r in attrTable.Rows)
{
// get attribute data
attributeName = r["AttributeName"].ToString();
attributeValue = r["AttributeValue"].ToString();
attributeValueId = r["AttributeValueID"].ToString();
// if starting a new attribute (e.g. Color, Size)
if (attributeName != prevAttributeName)
{
prevAttributeName = attributeName;
attributeNameLabel = new Label();
attributeNameLabel.Text = "<li class=\"txt\">" + attributeName + ":</li>";
attributeValuesDropDown = new DropDownList();
attrPlaceHolder.Controls.Add(attributeNameLabel);
attrPlaceHolder.Controls.Add(attributeValuesDropDown);
}
// add a new attribute value to the DropDownList
attributeValuesDropDown.Items.Add(new ListItem(attributeValue, attributeValueId));
}
However, when inside a button click event, when I loop through this place using visual studio debugging, I saw that the visual studio studio debugger first hit the "attrPlaceHolder.Controls" word in my foreach loop, then secondly comes to 'in' keyword (in foreach loop) but it isn't hitting the first two words (i-e 'Control cnt' in my foreach loop. Here it looks;
protected void ButtonBuyNow_Click(object sender, EventArgs e)
{
// Retrieve the selected product options
string options = "";
foreach (Control cnt in attrPlaceHolder.Controls)
{
if (cnt is Label)
{
Label attrLabel = (Label)cnt;
options += attrLabel.Text;
}
if (cnt is DropDownList)
{
DropDownList attrDropDown = (DropDownList)cnt;
options += attrDropDown.Items[attrDropDown.SelectedIndex] + "; ";
}
}
// Add the product to the shopping cart
ShoppingCartAccess.AddItem(productId, options);
}
Basically I need 'options' variable to be populated but it isn't hitting the foreach loop inside, therefore I am not able to get the 'options' variable populated.
This is a serious problem in my application. Please tell me why I can't get the inside the foreach loop.
NOTE:
please note that this isn't the complete code of my entire page. My rest of the code executes correctly.
why I can't get the inside the foreach loop
Because the list is empty.
Why is the list empty? (Would be the next logical question)
Because, at ASP.Net, dynamically created controls must be re-created at Page_Init in order to exist. When you create them at this stage, the page lifecycle will bind the viewstate and will be ready for use.
If you receive a postback (from the button, for example) and don't recreate them, they simply don't exist.

Get values from dynamic controls with c#?

I created a few radiobuttonlist controls on my project, they're created every time the page is loaded, i want to get the value of the radiobutton that the user has selected, but since my radiobuttons were created dynamically, i don't know how to acces to their values nor how to create their event handlers. Is there a way to assign a name or id to the control when i create it?
i hope you can help me.
I create a seires of radiobuttlist on the page_load event, with the text and their values been pulled out of a database. now, the user has to choose one of the options from that radiobuttlist and i want to get the value of the radiobutton the user checked. how do i do that if i don't know the name nor the id of the radiobuttlist since they're created dynamically.
this is what i've got:
for (int i = 3; i < numfields; i++) {
if (dr[i].ToString() != "" && dr[i] != null){
r.Items.Add(new ListItem(dr[i].ToString(), dr[i].ToString()));
//r.SelectedIndexChanged += new EventHandler(rowSelectedIndex);
}
}
so basically i use my datareader to loop through the data in the database, if the value from the field isn't empty or null, then i add an item to the radiobuttlist called "r"
i tried to create an eventhandler for that too, but since i have never worked with them i really don't know what to do. :(
I'm so sorry if i seem way too pathetic.
Taking a quick look at your code:
for (int i = 3; i < numfields; i++) {
if (dr[i].ToString() != "" && dr[i] != null){
r.Items.Add(new ListItem(dr[i].ToString(), dr[i].ToString()));
//r.SelectedIndexChanged += new EventHandler(rowSelectedIndex);
}
}
The most obvious thing that jumps out is your if statement. You should first check for null:
if (dr[i] != null && dr[i].ToString() != ""){
As if dr[i] is null, you'll get an exception (as you'll be trying to call the ToString() method on a null object.
If the contents of dr are always going to be strings, you might consider writing:
if(!String.IsNullOrEmpty(dr[i]){
I also note you start your indexing at 3 - is this because you want to skip the first 3 fields?
Wherever you create your variable, 'r', you can set the name and ID properties. You can use the ID property to look for the control on PostBack. So if you created your radiolist like so:
RadioButtonList r = new RadioButtonList();
r.Id = "MyRadioButtonList";
r.SelectedIndexChanged += MyRadioButton_SelectedIndexChanged;
Which would point at the following event handler:
private void MyRadioButton_SelectedIndexChanged(Object sender, EventArgs e) {
... Do Stuff ...
}
There are several ways of finding your control when you post back; you can look in the Request.Forms collection for a control matching the name of the control you submitted, or, more appropriately, you can use the FindControl method with the ID you gave the control. See C#, FindControl for a post with a method (by Jeff Atwood!) that will search the entire hierarchy of controls for your control.
When you add a dynamic control is important, too. If you add it too late in the page lifecycle then it will not be available on PostBack. See http://support.microsoft.com/kb/317515 for more details on just when to add a control. There are plenty of resources for Dynamic ASP.Net controls around too.
You could put your RadioButton into a list as you create them. This is also when you want to add your handlers.
RadioButton rb;
for (int i = 1; i < 5; i++)
{
rb = new RadioButton();
rb.AutoSize = true;
rb.Location = new System.Drawing.Point(25, (i*25) + 25);
rb.Name = "radioButton" + i.ToString();
rb.Text = "radioButton" + i.ToString();
//Add some event handler?
this.Controls.Add(rb);
lstRadioButton.Add(rb);
}
Whenever you want to know which one is selected you can do a foreach loop of your list and look if your RadioButton is checked.
foreach (RadioButton rButton in lstRadioButton)
{
if (rButton.Checked == true)
{
//Do something
}
}
You are maybe searching for TagName property if the programmatic name isn't enough for you.
The problem is that you are creating the controls in page_load. In order for their values to be posted back into the controls correctly, you must move this creation into the page_init method and recreate them every time.
Then, in page_load, you can access the values in the controls correctly. If you give them IDs using a consistent naming convention, you will be able to find them using the FindControl method or, in page_init, you can store them in a collection at the page or user control level.

Categories

Resources