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);
}
}
}
Related
I have code that creates a ListBoxItem for each of the first 100 values in query, and holds data such as ID, Address, etc. I also have an event so that when the ListBoxItem is created, it displays the address in a textbox so that a search can be done with the address(not included in code)
foreach (var item in query)
{
if (i < 100)
{
var listboxitem = new ListBoxItem();
listboxitem.Content = item.Address_Full;
listboxitem.Selected += Address_Clicked;
listboxitem.Tag = new AddressInfo(item.ID, item.Nickname, item.Address_Full, item.Units,
item.RegionID, item.Notes, item.RecordSource);
AddressListBox.Items.Add(listboxitem);
}
else
break;
i++;
}
private void Address_Clicked(object sender, RoutedEventArgs e)
{
var source = e.OriginalSource.ToString().Replace("System.Windows.Controls.ListBoxItem: ", "");
GeocodeAddressTbx.Text = source;
}
So when I put a breakpoint in the code, I can see that e has "Original Source" and under it it has the "Tag" that I set earlier in the first code box.
I know the information's there, but I do not know how to call on it, as e.OriginalSource.Tag would just give me a "does not contain a definition for 'Tag'" error. I think this is a kind of a general problem not that specific to my case so I hope that's enough information. Thanks.
use sender parameter. it should be ListBoxItem, because event handler is attached to listBoxItem event
private void Address_Clicked(object sender, RoutedEventArgs e)
{
GeocodeAddressTbx.Text = ((ListBoxItem)sender).Content.ToString();
}
but you can also use the power of bindings and do this:
1 - use ItemsSource instead of loop:
AddressListBox.ItemsSource = query.Take(100).ToList();
AddressListBox.DisplayMemberPath = nameof(AddressInfo.Address_Full);
/*foreach (var item in query)
{
if (i < 100)
{
var listboxitem = new ListBoxItem();
listboxitem.Content = item.Address_Full;
listboxitem.Selected += Address_Clicked;
listboxitem.Tag = new AddressInfo(item.ID, item.Nickname, item.Address_Full, item.Units,
item.RegionID, item.Notes, item.RecordSource);
AddressListBox.Items.Add(listboxitem);
}
else
break;
i++;
}*/
2 - bind TextBox to selected item:
<TextBox Name="GeocodeAddressTbx"
Text="{Binding ElementName=AddressListBox, Path=SelectedItem.Address_Full}"/>
I have a web application asp.net.
I am creating 54 text boxes dynamically in Page_Load
Here is the code
protected void Page_Load(object sender, EventArgs e)
{
for(i = 0, i<54, i++)
{
Textbox TestTextbox = new texbox();
TestTextBox.ID = "Reg" + i ;
TestTextBox.Attributes.add("runat","server");
TestTextBoxAttributes.Add("AutoPostBack", "true");
//display to a table called table1 created in the aspx page
}
}
On the page I have a button, called button1, and a on click event called "OnClickEvent", i want to capture the ID and the values of all the textboxes.
I have used Page.Controls.Count and I get only 1, the table that I have added to the aspx page, I get the IDs by using Request.Form but I`m not getting the values.
I am adding all the text boxes to a Table that I have created in the aspx file.
You can loop through the controls and check if they are of type TextBox:
for(int i = 0, i<54, i++)) {
var control = Page.FindControl("Reg" + i);
//get the value of the control
}
You are not adding the TextBox to the Page, so you cannot find it anyway. Second, adding runat=server and AutoPostBack=true as a string would not work either. (not to mention your snippet is full of errors)
//a loop uses ';', not ','
for (int i = 0; i < 54; i++)
{
//declare a new dynamic textbox = CaSe SeNsItIvE
TextBox TestTextbox = new TextBox();
TestTextbox.ID = "Reg" + i;
//if you want to add attibutes you do it like this
TestTextbox.AutoPostBack = true;
TestTextbox.TextChanged += TestTextbox_TextChanged;
//add the textbox to the page
PlaceHolder1.Controls.Add(TestTextbox);
}
And if you want to loop all the controls you can do something like this
//loop all the controls that were added to the placeholder
foreach (Control control in PlaceHolder1.Controls)
{
//is it a textbox
if (control is TextBox)
{
//cast the control back to a textbox to access it's properties
TextBox tb = control as TextBox;
string id = tb.ID;
}
}
I am getting this error
"Failed to load viewstate. The control tree into which viewstate is
being loaded must match the control tree that was used to save
viewstate during the previous request. For example, when adding
controls dynamically, the controls added during a post-back must match
the type and position of the controls added during the initial
request. "
when I try to submit a page where I applied some logic on GridView rowdatabound to alter the RowSpan. On commenting this event there is no error.
here is the code :
int firstRow;
string previousCat;
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
var drv = e.Row.DataItem as QCParameters;
if (previousCat == drv.AuditTypeValue)
{
//If it's the same category as the previous one
//Increment the rowspan
if (GridView1.Rows[firstRow].Cells[0].RowSpan == 0)
{
GridView1.Rows[firstRow].Cells[0].RowSpan = 2;
GridView1.Rows[firstRow].Cells[5].RowSpan = 2;
}
else
{
GridView1.Rows[firstRow].Cells[0].RowSpan += 1;
GridView1.Rows[firstRow].Cells[5].RowSpan += 1;
}
//Remove the cell
if (e.Row.Cells.Count > 5)
e.Row.Cells.RemoveAt(5);
e.Row.Cells.RemoveAt(0);
}
else //It's a new category
{
e.Row.VerticalAlign = VerticalAlign.Top;
//Maintain the category in memory
previousCat = drv.AuditTypeValue;
firstRow = e.Row.RowIndex;
}
}
}
The problem is that you remove cells and than during postback (when the control tree is recreated) it does not match and the ViewState cant be loaded.
One possible solution would be to "hide" the cells instead by setting: e.Row.Cells[5].Visible = false;
Not Visible controls will not be rendered but will still be part of the page control tree.
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 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?