iterate through ASP:Buttons - c#

I am kind of newbie and I have an issue with ASP:Button controls.
There is about 60 buttons on the page, typical XAML looks like this:
<asp:Button class="tile" ID="Button1" runat="server" Text="Domains"/>
I need to iterate through all of the buttons on the page to change properties and I don't want to do it one by one.
I've found many suggestions here and there, but nothing works. My code behind is:
for (int i = 1; i < 59; i++)
{
String butt = String.Format("Button{0}", i);
var btn = FindControl(butt);
btn.Visible = false;
}
Error is that there is no object reference. btn is null.
I tried to inspect element in running application and it says ID of element is "MainContent_Button1" - tried that too, does not work. Other thing I tried is
foreach(var button in this.Controls.OfType<Button>())
{
button.Visible = false;
}
I came to conclusion that asp:button is a) not a control of button type b) its ID is somehow generated when the application is run and therefore there is no control with id Button1 to be found.
Can anyone please explain that to me? I'd really like to understand why is it behaving like that and what exactly is the purpose of this behavior.
Thanks
Edit: I even tried to remove the loop completely and modify one specific button using FindControl method. Does not work either.
var btn = FindControl("Button1");
btn.Visible = false;
result: System.NullReferenceException: 'Object reference not set to an instance of an object.'

It looks like you are using a Master Page. Using FindControl on a Master Page works slightly different than on a normal page.You first need to find the correct ContentPlaceHolder in which the Buttons are located and use FindControl on that ContentPlaceHolder.
ContentPlaceHolder cph = Master.FindControl("MainContent") as ContentPlaceHolder;
for (int i = 1; i < 9; i++)
{
String butt = String.Format("Button{0}", i);
var btn = cph.FindControl(butt);
btn.Visible = false;
}

Related

Difficulty with tabControl/tabitem refresh

I have a WPF window with a maintabWindow and several tabitems.
It normally works fine and the layout is this:
but when I BEFORE add the following window:
the result is this:
So the problem is related with the tabControl/tabItem refresh.
This is fairly obvious but even more because if I move the window or pass with the mouse on the a tabItem they get refreshed one by one.
I searched and found that here is a solution: http://geekswithblogs.net/NewThingsILearned/archive/2008/08/25/refresh--update-wpf-controls.aspx
so I added:
this.MainTab.Refresh();
this.tabItem1.Refresh();
this.tabItem2.Refresh();
this.tabItem3.Refresh();
this.tabItem4.Refresh();
this.tabItem5.Refresh();
but that didn't change a thing.
Thanx for any help
Ok so in the end it has a quite a weird behavious. If I do
for (int i = 0; i < tbcMain.Items.Count; i++)
{
tbcMain.SelectedIndex = i;
tbcMain.UpdateLayout();
}
it works. But I have to set the 1st tabitem so if I add
tbcMain.SelectedIndex = 0;
it doesn't.
So the solution was put a sleep and it works again.
for (int i = 0; i < tbcMain.Items.Count; i++)
{
tbcMain.SelectedIndex = i;
tbcMain.UpdateLayout();
}
System.Threading.Thread.Sleep(250);
tbcMain.SelectedIndex = 0;
But that is not elegant at all. If anyone has a better solution pls let me know it.
Btw adding the tbcMain.SelectedIndex = 0; on the loaded event of the mainWindow is of no use.
You should be able to set your SelectedIndex first, and without having to include it in your loop:
tbcMain.SelectedIndex = 0;
Then, basing it off of your response, you should be able to either just do .UpdateLayout() on each of your TabItems:
MainTab.UpdateLayout();
tabItem1.UpdateLayout();
tabItem2.UpdateLayout();
tabItem3.UpdateLayout();
tabItem4.UpdateLayout();
tabItem5.UpdateLayout();
Or you should be able to do something like this in your loop:
MainTab.UpdateLayout();
for (int i = 0; i < tbcMain.Items.Count; i++)
{
TabItem tbi = (TabItem)this.FindControl("tabItem"+i);
tbi.UpdateLayout();
}
Updating/refreshing should have nothing to do with setting the selected one. Including the selection of the tab within the loop to i was your problem - not a race condition. Set the tbcMain.SelectedIndex = 0 outside of your loop and you should be fine. Sometimes, however, this doesn't work and you need to set it with Dispatcher:
Dispatcher.BeginInvoke((Action)(() => this.tbcMain.SelectedIndex = 0));
There's a write up/comments on a separate thread regarding why it needs to be sent to Dispatcher:
How to programmatically select a TabItem in WPF TabControl
Though, unfortunately for me, I had a similar issue where I was trying to refresh a ListView on a subtab. Neither .UpdateLayout(), nor .InvalidateVisual() (as I saw on this thread) worked. I just had to rebind my grid in the button event I was using on my main page, so that when the tab was clicked, it was refreshed manually. I added an x:Name property on the tab so I could call it using "dot" syntax, and it exposed the ListView. I simply added the DataTable of results back to that ListView's DataContext.

Adding EventHandler for dynamically added control

I've got a problem with adding some controls into a Panel(which gets "PopUpped" by a ModalPopupExtender) and add a CheckedChanged-EventHandler.
First of all, when user clicks on a button, this happens inside the CreatePanelChoose() function:
foreach (ListItem item in lbSupplier.Items)
{
string cbid = "cb" + i;
CheckBox cb = new CheckBox();
cb.ID = cbid;
cb.Text = item.Text;
cb.AutoPostBack = true;
AjaxControlToolkit.MutuallyExclusiveCheckBoxExtender mecbe = new AjaxControlToolkit.MutuallyExclusiveCheckBoxExtender();
mecbe.ID = "mecbe" + cbid;
mecbe.TargetControlID = cbid;
mecbe.Key = "SupplierKEY";
mecbe.BehaviorID = mecbe.ID + i;
//Also adding a Label
phModalPopupExtender.Controls.Add(new LiteralControl("</br>")); //phModalPopupExtender is a PlaceHolder
phModalPopupExtender.Controls.Add(cb);
phModalPopupExtender.Controls.Add(mecbe);
phModalPopupExtender.Controls.Add(lbl);
AsyncPostBackTrigger trigger = new AsyncPostBackTrigger();
trigger.ControlID = cbid;
trigger.EventName = "CheckedChanged";
UpdatePanelMatrix.Triggers.Add(trigger);
i++;
ButtonOK.Enabled = false;
}
lblText.Text = "Select one Supplier";
ModalPopupExtender1.Show();
Then i add the EventHandler in the Page_LoadComplete:
As you can see it also gets asigned to the control (I think).
The ModalPopup shows up correctly, but if I click one of the CheckBox, then it just closes it without going into cb_CheckedChanged, but it makes a Async postback ...
If I check Request.Form["__ASYNCPOST"] its true and Request.Form["__EVENTTARGET"] is also correct. (It gives me the unique id!)
Request.Form["__EVENTARGUMENT"] is empty.
I think I also need to say that I use a masterpage.
The problem shouldn't be the lifecycle of the page, because msdn says:
LoadComplete
Raised at the end of the event-handling stage.
Use this event for tasks that require that all other controls on the page be loaded.
Its the onliest place it makes me think it would be right.
Btw: yes i looked trough the topics here allready, but nothing helped me ... (google fo sure also)
Edit 1:
if (IsPostBack)
{
if (recreating == true)
{
CreatePanelChoose();
}
}
In CreatePanelChoose i do the foreach now everytime when its a postback! But it still doesnt fire cb_ChangedChecked ...
Edit 2:
MSDN-Page-Lifecycle also says:
PreInit
Raised after the start stage is complete and before the initialization
stage begins.
Use this event for the following:
Create or re-create dynamic controls.
So i tried to recreate the Panel there. But i dont have the ListItems there to get the values ... ?!
Okay, gave up ...
If someone would still have an answer, it would be great!
Right now I dont use the OnCheckedChanged-Event of the CheckBoxes anymore.
I just let them select a CheckBox and on the OnClick of the ButtonOk I loop through the CheckBoxes and check which one is selected.

FindControl returns null

I am working on a solution in C# and ASP.NET 4.0 I am trying to get the value of a radiobutton from my page that was dynamically created based on some database information.
Here is what gets generated in the page source:
<td>
<input id="masterMain_3Answer_0" type="radio" name="ctl00$masterMain$3Answer"
value="Y" onclick="return answeredyes(3);" />
<label for="masterMain_3Answer_0">Y</label>
</td>
<td>
<input id="masterMain_3Answer_1" type="radio" name="ctl00$masterMain$3Answer"
value="N" onclick="return answeredno(3,'desc');" />
<label for="masterMain_3Answer_1">N</label>
</td>
Inside the OnClick function of my submit button I want to gather wether Y or N has been selected based on the user's input.
Here is what I have written so far:
RadioButton _rbAnswer = new RadioButton();
RadioButtonList _rbList = new RadioButtonList();
ContentPlaceHolder cp = (ContentPlaceHolder)Master.FindControl("masterMain");
_rbAnswer = (RadioButton)Master.FindControl("masterMain_3Answer_0");
HtmlInputRadioButton rb = (HtmlInputRadioButton)Master.FindControl("masterMain_3Answer_0");
_rbAnswer = (RadioButton)cp.FindControl("masterMain_3Answer_0");
_rbList = (RadioButtonList)cp.FindControl("masterMain_3Answer_0");
I am able to get the ContentPlaceHolder without any issues but the rest of the objects are null after it attempts to get the . I have also attempted removing the "masterMain_" but still doesn't want to find the controls.
Here is the code in which the individual radiobuttonlists are added
TableRow _tempRow = new TableRow();
TableCell _cellOK = new TableCell();
RadioButtonList _rbList = new RadioButtonList();
_rbList.ID = r[0].ToString()+"Answer";
_rbList.RepeatDirection = RepeatDirection.Horizontal;
//add options for yes or no
ListItem _liOk = new ListItem();
_liOk.Value = "Y";
ListItem _linotOk = new ListItem();
_linotOk.Value = "N";
_rbList.Items.Add(_linotOk);
//add cell to row
_rbList.Items.Add(_liOk);
_cellOK.Controls.Add(_rbList);
_tempRow.Cells.Add(_cellOK);
//add the row to the table
stdtable.Rows.Add(_tempRow);
To be able to quickly find dynamically created controls, add a dictionary to your page class:
private Dictionary<string, Control> fDynamicControls = new Dictionary<string, Control>();
then when a new control is created in code and its ID is assigned:
fDynamicControls.Add(newControl.ID, newControl);
and when you need control's reference:
Control c = fDynamicControls["controlIdThatYouKnow"];
When using FindControl don't use the id that's generated by the page. Use the ID that you specified inthe aspx.
If this is inside a Repeateror another DataBound control, you have to first find the current record. (GridViewRow or RepeaterItem) first, an use that item's .FindControl function.
See this (different - not duplicate) question to see a code example of how to do it: How to find control with in repeater on button click event and repeater is placed with in gridview in asp.net C#
When you create dynamic controller give specific ids for them. This facilitate to generate controls with our own id. therefore then we can access the controls with this id.
And also use OnInit life cycle event to generate dynamic controllers, this is the best place to generate them.
RadioButton _rbAnswer = new RadioButton();
_rbAnswer.ID="ranswerid";
Given your update, you'll find that your control heirarchy is fairly deep. You have a RadioButtonList inside a cell inside a row inside a table ...
FindControl is a method that needs to be called on a specific object and can only find objects that are actual children of that object. In this case, you either need to build a recursive method or go directly to the control in question. Since so many of these controls are generated dynamically, you'll have no real way of accessing them directly so building the recursive function may be simplest. However, on very large pages this method can be very resource consuming:
public static WebUserControl FindControlRecursive(this WebUserControl source, string name)
{
if (source.ID.Equals(name, StringComparison.Ordinal))
return source;
if (!source.Controls.Any()) return null;
if (source.Controls.Any(x => x.ID.Equals(name, StringComparison.Ordinal))
return source.FindControl(name);
WebUserControl result = null;
// If it falls through to this point then it
// didn't find it at the current level
foreach(WebUserControl ctrl in source.Controls)
{
result = ctrl.FindControlRecursive(name);
if (result != null)
return result;
}
// If it falls through to this point it didn't find it
return null;
}
This is an extension method that would allow you to call this on your ContentPlaceHolder control:
var _cp = (ContentPlaceHolder)Master.FindControl("masterMain");
RadioButtonList _rbList = _cp.FindControlRecursive("3Answer");
if (_rbList != null)
// ... Found it
Note: Treat the above as psuedo-code. It has not be implemented by me anywhere so may (likely) require tweaking to behave exactly right.

Javascript is not called on radiobutton list index change

I have written code for javascript but it is not called any how. I tried to call both form html side and also by assigning attribute from page load event but it is not at all called.
This is the code for my javascript.
function rdbantiplatelet_onClick(thiscontrol, trName) {
alert('hi');
var RB1 = thiscontrol;
var radio = RB1.getElementsByTagName("input");
var trDose = document.getElementById(trName.toString());
// var RB1 = document.getElementById("<%=this.rdbantiplatelet.ClientID%>");
// var radio = RB1.getElementsByTagName("input");
// var tblAntiplatelet = document.getElementById("<%=tblAntiplatelet.ClientID %>");
for (var i = 0; i < radio.length; i++){
if (radio[i].checked){
trDose.style.display = "";
return true;
}
else{
trDose.style.display = "none";
return true;
}
}
return false;
}
This is the code to call javascript written in page_load event..
rdbantiplatelet.Attributes.Add("OnClick", "return rdbantiplatelet_onClick(this,'" + trDose.ClientID.ToString() + "');");
Try an alert() first to make sure your onclick is firing, then try your rdbantiplatelet_onClick() function:
rdbantiplatelet.Attributes.Add("OnClick", "alert('I am working');");
First of all for your reference here is a list of standard html events
http://www.w3schools.com/tags/ref_eventattributes.asp
try adding something like this to the html radiobutton element
onchange="alert('on change fired');"
and
onclick="alert(' on click fired');
so you can make sure you are picking up the right event.
Once you have the right event then replace the alert call to your method
which would be something like this
onchange="rdbantiplatelet_onClick(this, this.parent.id)"
...you might have to change the 'this.parent.id'
Make sure you are running through a good web browser for development FireFox with the firebug plug-in is great for this stuff.
You are add click event to html table that holds radiobuttons. Use script below:
foreach (ListItem item in rdbantiplatelet.Items)
{
item.Attributes.Add("onclick", "return foobar(this);");
}

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