I have a very dynamic web app that is dynamically created controls at run-time.
Here is the first needed part of my code to solve my issue.
This is in a for loop, essentially it creates multiple checkbox's with ID's and event handlers.
// All I am doing here is incrementing our session counter so we can increment our ID
int id = Convert.ToInt32(Session["id"]);
id++;
Session["id"] = id;
// Now I create my checkbox
chkDynamic = new CheckBox();
chkDynamic.Text = "hey";
string chk = "chk" + id.ToString();
chkDynamic.ID = chk;
chkDynamic.CheckedChanged += new EventHandler(chkDynamic_CheckedChanged);
Panel1.Controls.Add(chkDynamic);
This next section is our custom even handler
protected void chkDynamic_CheckedChanged(object sender, EventArgs e)
{
if (((CheckBox)sender).Checked)
Response.Write("you checked the checkbox :" + this.chkDynamic.ID);
else
Response.Write("checkbox is not checked");
}
The thing that strikes me as ODD. Is that this will work perfectly fine if I change:
string chk = "chk" + id.ToString();
To:
string chk = "chk";
But then of course we run into "multiple controls with the same ID"
My problem is getting this to work with unique ID's! Another bit of ODD information that may help. If I take it out of a loop, and manually add a checkbox with a different ID it works as well. This is mind boggling :(
chkDynamic = new CheckBox();
chkDynamic.Text = "hey";
// string chk = "chk" + id.ToString();
chkDynamic.ID = "hey1";
chkDynamic.CheckedChanged += new EventHandler(chkDynamic_CheckedChanged);
Panel1.Controls.Add(chkDynamic);
chkDynamic = new CheckBox();
chkDynamic.Text = "hey";
// string chk = "chk" + id.ToString();
chkDynamic.ID = "hey2";
chkDynamic.CheckedChanged += new EventHandler(chkDynamic_CheckedChanged);
Panel1.Controls.Add(chkDynamic);
I have also debugged my program, and the values stored in the Session["id"] are not null nor corrupt. Always holding value 0 and up!
Thanks for looking guys / gals. I'm really stuck on this!
PS - Sorry. There are no errors. The events just do not fire unless I hard code the ID's.
Maybe you forget to reset the sesssion("ID"), so when the page posts back the checkboxes are recreated with new ids. Since the checkbox-es are recreated on every postback, they need to have the same ID every time and if they don't they are percepted as new controls and therefor the event handler is not called.
Have you tried setting the AutoPostBack property of your checkboxes to true?
Related
I have generated checkboxes dynamically and added them to a panel on a button click with below code.
foreach (string filename in filepaths)
{
CheckBox chk = new CheckBox();
chk.Text = Path.GetFileName(filename.ToString());
Panel1.Controls.Add(chk);
Panel1.Controls.Add(new LiteralControl("<br>"));
}
Now the problem is I couldn't access the checked values on another button with below code
if (!IsPostBack) {
foreach(Control c in Panel1.Controls) {
if ((c is CheckBox) && ((CheckBox) c).Checked) {
lblerr.Text = c.ToString();
}
}
}
What I found is on button click the page getting loaded so controls in panel returns null. Can anyone explain how to get the checked values.
Thanks in advance.
When creating any kind of System.Web.UI.WebControl class problematically, it does not implicitly get re-created when the page is rebuilt during post back. You must call the method that creates the controls again in PageLoad:
protected void Page_Load(object sender, EventArgs e)
{
if(!this.IsPostback)
BuildCheckBoxes();
}
private void BuildCheckBoxes()
{
foreach (string filename in filepaths)
{
CheckBox chk = new CheckBox();
chk.Text = Path.GetFileName(filename.ToString());
Panel1.Controls.Add(chk);
Panel1.Controls.Add(new LiteralControl("<br>"));
}
}
This must be done in PageLoad, so that the controls exist when the ViewState is restored. Otherwise, .NET will discard the view state for the controls that "no longer exist".
Keep in mind that this will create overhead on your PageLoad event, if you are building a large number of controls. One way to mitigate this is to stuff controls into the server's cache, but there are a couple of very important things to note when using this method:
The property this.Page.Cache is NOT local to the page. Anything you put in here is shared across the whole of the App Pool (even the MSDN page on this property is misleading).
Each value that you put in must be referenced by a specific key that is unique for each user's session (since, as #1 points out, this cache is global across all sessions). This means the key should include something that uniquely identifies the current session, such as the session key.
private int DynCheckBoxCount
{
get { return (int)this.ViewState["DynCheckBoxCount"]; }
set { this.ViewState["DynCheckBoxCount"] = value; }
}
private void BuildCheckBoxes()
{
if (!this.IsPostBack)
{
int i = 0;
foreach (string filename in filepaths)
{
CheckBox chk = new CheckBox();
chk.Text = Path.GetFileName(filename); // Don't do a .ToString() on a string. It's unnecessary, ugly code, and opens the door for NullReferenceExceptions.
chk.Style.Add(HtmlTextWriterStyle.Display, "block");
Panel1.Controls.Add(chk);
string key = string.Format("{0}_{1}", this.Session.SessionID, i++);
this.Page.Cache[key] = chk;
}
this.DynCheckBoxCount = i;
}
else
{
for (int i = 0; i < this.DynCheckBoxCount; i++)
{
string key = string.Format("{0}_{1}", this.Session.SessionID, i);
CheckBox chk = (CheckBox)this.Page.Cache[key];
this.Panel1.Controls.Add(chk);
}
}
}
I have a asp.net page that has two controls on it, A placeholder and a submit button. During the Page_Load I create a checklist of tasks dynamically. Each row consists of a description, link to a tutorial, and a checkbox. All of the information in the row is kept in a database. If the database says the task has been checked, the code sets the checked property to true. The problem I'm having is that when the submit button is clicked I cannot find what the value is of the checked property for all of the checkboxes on the page(about 23 total).
Here is the code to create the checkboxes...
checkbox = new CheckBox();
phChecklist.Controls.Add(checkbox);
if (item.Attributes.Contains("ree_completed"))
checkbox.Checked = (bool)item.Attributes["ree_completed"];
checkbox.EnableViewState = true;
checkbox.ClientIDMode = System.Web.UI.ClientIDMode.Static;
checkboxId = "checkbox" + (string)item.Attributes["ree_sectionnumber"].ToString() + (string)item.Attributes["ree_sequencenumber"].ToString();
checkbox.ID = checkboxId;
Here is the code to try and find the value of the checkbox...
foreach (Entity item in checklistCollection.Entities)
{
checkboxId = "checkbox" + (string)item.Attributes["ree_sectionnumber"].ToString() + (string)item.Attributes["ree_sequencenumber"].ToString();
itemChecked = (bool)ViewState[checkboxId];
if (itemChecked == "true")
** update database **
//CheckBox checkbox = (CheckBox)phchecklist.FindControl(checkboxId);
}
I think I've read every post on this subject and have tried most of them. I have also read about the ViewState but the suggestions that I have read about have not worked. As you can see I also tried finding the checkbox in the controls collection by the id and that also did not work.
I do not recreate the checkboxes when posting back to the page. Some posts mention that you have to recreate the controls but when I tried to do that I received an error message saying it was a duplicate id. The other reason I would prefer not to have to recreate the page is the performance hit. The database is in a Microsoft Dynamic CRM database that is remote.
How do I retain the value of checked property across a post back?
UPDATE: I changed my logic around and fixed the duplicate id error. The page will now recreate all of the controls during the post back. I still cannot find the value of any of the checkbox controls when the submit button is clicked.
Gary
You need to provide an ID for the checkbox control when you create it. Since you are creating multiple checkboxes; one for each row in the database ... you need to add the unique row identifier to the ID. So you need to build the checkbox ID from the row ID (usually the IDENTITY). Example: ">
Then on postback while you are post-processing each row in the table, you can query the request for that specific key value pair. Something similar to this:
foreach (DataRow dr in dataTable.Rows)
Response["chk_" + dr("ID")];
Use Page Init as opossed to page_Load event. As per https://msdn.microsoft.com/en-us/library/ms178472.aspx "Use this event to read or initialize control properties"
In case for that to work you need to add an event handler to dynamically added controls
in your case
checkbox = new CheckBox();
phChecklist.Controls.Add(checkbox);
checkbox.CheckedChanged += checkBox_CheckedChanged;
and then what you need to do in the method
private void CheckBox_CheckedChanged(object sender, System.EventArgs e)
{
...
}
As I commented, you certainly need to create your controls during the Init event, Load is too late. Check out the asp.Net page life's cycle for details.
On a side note, you might want to let ASP.NET handle the controls's ID. You say you need to keep some value in order to get back to the database, you can wrap your checkboxes in a table. You will then be able to iterate through your controls without having to guess their names.
For instance, if your row has a HiddenField followed by your actual CheckBox:
//Please call me during Init
protected void createTheControls() {
TableRow tr;
TableCell td;
CheckBox cb;
HiddenField section, sequence;
foreach (Object item in someList)
{
section = new HiddenField();
section.Value = item.Attributes["ree_sectionnumber"].ToString();
sequence = new HiddenField;
sequence.Value = item.Attributes["ree_sequencenumber"].ToString();
cb = new CheckBox();
cb.ID = String.Concat("checkbox", (String)sequence.Value);
if (item.Attributes.Contains("ree_completed"))
cb.Checked = (bool)item.Attributes["ree_completed"];
td = new TableCell();
td.Controls.Add(section);
td.Controls.Add(sequence);
td.Controls.Add(cb);
tr = new TableRow();
tr.Cells.Add(td);
}
}
protected void readTheControls()
{
foreach (TableRow tr in myTable.Rows)
{
HiddenField section = (HiddenField)tr.Cells[0].Controls[0];
HiddenField sequence = (HiddenField)tr.Cells[0].Controls[1];
CheckBox cb = (CheckBox)tr.Cells[0].Controls[2];
}
}
I notice you try to use the ViewState explicitly, which I believe is not going to be of any help here. The solution above may look cumbersome, but it will ensure you dont need to mess with ID's when fetching the controls.
Here's a thorough explanation from MSDN, and here are a few short and sweet SO answers explaining ViewState's purpose.
My task is to read entries from a database and put a Checkbox corresponding to each entry
I have opened a database connection and have created the checkboxes but am unable to check the setting of the checkbox. I am storing my checkboxes using a static array ck[]
int count = 0;
while(dr.Read()) //Reading the Database
{
CheckBox temp = new CheckBox(); //Creating a temprory checkbox
temp.Text = dr[1].ToString();
temp.Checked = false; //Making the checkbox intitally empty
temp.ID = dr[0].ToString();
ck[count] = temp; //inserting the checkbox's references into the array
ck[count].CheckedChanged += new EventHandler(temp_CheckedChanged); //Adding the even handler
Panel1.Controls.Add(ck[count]); //Adding the checkbox to panel
LiteralControl lc = new LiteralControl("<br>");
Panel1.Controls.Add(lc);
count++;
}
void temp_CheckedChanged(object sender, EventArgs e) //handling the checking and unchecking of the checkbox
{
CheckBox ckb = (CheckBox)sender;
ck[index].Checked = !ck[index].Checked;
}
The problem arises in the fact that there is no update in the .Checked entry of the checkboxes.
I have read many posts here and tried to implement them too but nothing has worked out so far. I have even tried reading the data from the pane on which I am showing it in.
Better to use checkboxlist. Because you can add items at run time and works like list.
I have created a Checkbox dynamically by this button code
private void btn_add_record_Click(object sender, EventArgs e)q2
{
CheckBox DeleteCheckBox = new CheckBox();
Point P_request = new Point(nXCheckBox, nYCheckBox);
DeleteCheckBox.Location = P_request;
DeleteCheckBox.Name = "CH"+Record_ID+"";
}
Then i Checked it manually
Then i need to check a specific checkbox its name is "CH"+Record_ID+" to be checked or not dynamically using this code
string ChechBoxName = "CH1";
CheckBox DeleteChechBox = new CheckBox();
DeleteChechBox.Name = ChechBoxName;
if (DeleteChechBox.Checked)
{
// To Do Code
}
When i debug this code, it doesn't enter the if statement .. WHY ?
You're checking if the box is checked before it gets checked. Add
DeleteChechBox.CheckedChanged += DeleteChechBoxCheckedChanged;
and add the method DeleteChechBoxCheckedChanged where you can test whether or not it's been checked. You can also use
DeleteChechBox.Checked = true;
to check the box through code.
Edit:
To get a certain checkbox by it's name you have to either store it as a global variable or look through the controls array in the form.
foreach (Control control in this.Controls)
{
if (control.Name == "CH1")
{
CheckBox DeleteChechBox = (CheckBox)control;
if (DeleteChechBox.Check)
{
//To Do Code
}
}
}
When you create a new CheckBox, the default Checked value is false. Therefore if (DeleteChechBox.Checked)
returns false which is why you don't enter the block. You're not checking any existing Checkboxes, you're checking the new one you created.
In WPF you can accomplish it like shown in the following code snippet (pertinent to your example):
string _strCheckBoxName = "CH1";
CheckBox DeleteCheckBox= new CheckBox();
DeleteCheckBox.Name = _strCheckBoxName ;
DeleteCheckBox.Checked+=(s,e)=>CheckBox_Change(s,e);
DeleteCheckBox.Unchecked+=(s,e)=>CheckBox_Change(s,e);
DeleteCheckBox.IsChecked = true;
private void CheckBox_Change(object sender, RoutedEventArgs e)
{
if ((sender as CheckBox).Name=_strCheckBoxName && (bool)(sender as CheckBox).IsChecked)
{
// To Do Code
}
}
In suggested solution, you essentially subscribe the newly created CheckBox control to a single event handler proc, which looks at the control name and if checked runs some code. If more CheckBox added, then use the same event-subscription technique pointed to the same handler, and extend it with another if statement (or if-else if, or switch statement).
Hope this will help. Rgds,
Your problem is that you are creating one CheckBox in your btn_add_record_Click handler and then creating a new one in your second code fragment, which just happens to have the same Name as the first. That notwithstanding, it is not the same check box, so will not have the same value for its Checked property.
The way to fix that is to create the checkbox in the form's constructor as a class member, and then discover it when you need it by searching the components, using the code which Xylorast showed:
foreach (Control control in this.Controls)
{
if (control.Name == "CH1")
{
CheckBox DeleteChechBox = (CheckBox)control;
if (DeleteChechBox.Check)
{
//To Do Code
}
}
}
This is what I meant. Maybe you already checked it..?
string ChechBoxName = "CH1";
CheckBox DeleteChechBox = new CheckBox();
DeleteChechBox.Name = ChechBoxName;
DeleteChechBox.Checked = true;
if (DeleteChechBox.Checked)
{
// To Do Code
}
Edit:
Here is another way of accessing the control instead of enumerating over all the controls on the form for each control you would like to access:
Dictionary<string, CheckBox> checkBoxCollection = new Dictionary<string, CheckBox>();
And in your method where you create the checkbox add it to the dictionary:
checkBoxCollection.Add("CH1",DeleteCheckBox);
Access the checkbox from wherever you want like this:
CheckBox checkBox;
bool success = controls.TryGetValue("CH1"), out checkBox);
if (success)
{
// To Do Code
}
Or in your CheckedEvent you can get the CheckBox being checked like this:
CheckBox checkBox = sender as CheckBox;
I have some code that create a few components on the click of a button. Something like this.
CheckBox chk = new CheckBox();
chk.Top = 50;
chk.Left = 50;
chk.Text = "Check Box Test";
chk.Name = "chkTest"
this.Controls.Add(chk);
So how do I use this component. For example I tried this but got and error saying the component didn't exist. I just want to get their values.
if(chkTest.Checked)
{
//Do this
}
Please help.
Thanks in adv.
Either create a member variable in your class called chkTest that you can use later, or retrieve it on the fly from the Controls collection when needed, like so:
CheckBox chkTest = (CheckBox)Controls["chkTest"];
if(chkTest.Checked) {
// ...
}
If you only care about the control when it is checked or unchecked, use an event.
chk.Checked += new RoutedEventHandler(CheckBox_Checked);
chk.Unchecked += new RoutedEventHandler(CheckBox_Checked);
private void CheckBox_Checked(object sender, RoutedEventArgs e)
{
CheckBox chkBox = sender as CheckBox;
if (chkBox.IsChecked.Value)
{
// Do this...
}
}
Make sure to unsubscribe from the event handlers when you are finished with them.
You're referencing chkTest but you created chk.
You could declare the Checkbox as a member variable of your page. Then you would be able to access it more easily.
Class MyPage
{
CheckBox chkTest;
// then in page load
// chkTest = new CheckBox(); ...
}
if ((Controls.Items["chkTest"] as CheckBox).Checked)
{
// Do this
}
should work, but it's not pretty to look at. :)
You could declare it as a variable, then use it like you did:
CheckBox chkTest = Controls.Items["chkTest"] as Checkbox;
if (chkTest.Checked)
{
// Do this
}
Look on this handy page for ways to manipulate and access your Control's collection of items:
http://msdn.microsoft.com/en-us/library/system.windows.forms.control.controlcollection_members.aspx