Array of buttons, textboxes and labels with their properties - c#

Is it possible to store in the same array - list of different type elements declaring in the same array different property value (bool)? For exampe list of those elements:
GV1_BTNEdit.Visible = false;
GV1_BTNCancel.Visible = true;
GV1.Columns[3].Visible = true;
GV1.Columns[5].Visible = true;
GV1.Columns[4].Visible = true;
Lbl1_GV1.Visible = true;
Edit: (pseudo-code)
This is how funcionality should look like:
Declares a list/array of elements with a simultaneous declaration of parameters / properties of these elements:
list/element array (list_name)
{
textbox1.visible = true;
label1.visible = false;
button1.visible = true;
}
Calling a list/array, i.e. simultaneous assignment to the elements of the list - the property resulting from their declaration in the list:
list_name[];
Calling the list with the same property change, i.e. simultaneous assigning to all elements of the list the property visible = false:
list_name[i].visible = false;
Calling the list with changing the property of visible elements to the opposite (i.e. what was true will change to false, and what was false - to true):
list_name[i].visible != list_name[i].visible;
If, after all, it cannot be done in this particular way, is there another similar possibility?

As a general rule, often it is better to place a group of controls say inside of div, and then simple hide/show the div to show/hide the group of controls.
so say this:
<div id="BillAddress" runat="sever">
Text address, and more controls here
</div>
Then in code, you can hide/show the whole mess with
BillAddress.Style("display") = "none";
Or to show that group of controls, then this:
BillAddress.Style("display") = "normal";
So, web land, and web markup lends itself to MUCH better using span's, or div's, or whatever to group controls.
And the beauty of above, is then you can also often wirte client side code in JavaScript to hide/show groups of controls inside that div 100% with client side code.
Having stated + suggested the above?
You can also say cook up your "own" attributes on a group of controls.
Say:
<asp:TextBox ID="TextBox1" runat="server"
MyGroup="Billing" >
</asp:TextBox>
<asp:TextBox ID="txtNewCity" runat="server"
MyGroup="Billing>
</asp:TextBox>
So, note how in above I just made up a attribute for the control.
Then, in code, can do this:
For Each c As System.Web.UI.Control In Page.Controls
If c.Attributes("MyBilling") IsNot Nothing Then
// hide/show the control
So, in web land, I don't really think it makes a whole lot of sense to attempt to group some controls in a array - just drop all those controls inside of some div, and hide/show that div. But, you can use "tag" or even cook up + add your own attributes to controls, and then loop the controls in that page, or div or whatever.
For example, I cooked up my own "data binder" routine.
I simple will place a group of controls say inside of a "div" with a "id" and runat server.
Then, to load data into that "div" and set of controls?
I place controls in a div, and then I can do this:
int intPK = (int)ViewState[this.ID + "_MyPk"];
string strSQL = "SELECT * FROM " + this.MyTable + " WHERE ID = " + intPK;
DataTable rstData = General.MyRst(strSQL);
General.FLoader(this.EditRecord, rstData.Rows[0]);
In above, EditRecord is my "div"
The markup looks like:
<asp:TextBox ID="txtHotel" runat="server" f="HotelName" width="280"></asp:TextBox> <br />
<asp:TextBox ID="tFN" runat="server" f="FirstName" Width="140"></asp:TextBox> <br />
etc. etc.
So, I use a made up attribute called "f", where f="database column name"
So, with that simple idea, then I can load up a whole data form with about 3 lines of code.
So, say I click edit on a grid.
I pop this form:
but, the form data is done with my fLoader routine. All it does is look for "f" attributes, and fills out the control from the database.
And then for save, I have Fwriter. Does the same thing, but in reverse.
So, save button code for above is this:
protected void cmdSave_ServerClick(object sender, EventArgs e)
{
int intPK = (int)ViewState[this.ID + "_MyPk"];
string strSQL = "SELECT * FROM tblHotels WHERE ID = " + intPK;
DataTable rstData = General.MyRst(strSQL);
General.FWriterUpdate(this.EditRecord, rstData.Rows[0]);
}
So, Fwriter again just loops the controls inside of that div, and transfers back from the controls their values into the table.
So, in above, we see two examples of grouping controls, and then being able to "operate" on that group of controls.
No arrays required here. so, I used these concepts for my own data binding system, and thus I NEVER have to write code to load up each individual control from the database. Nor do I have to write code to send + save the data back to the database.
I means I quite much have ms-access like drag + drop of controls, and the shuffle from database to the form is done for me. And this all works due to the requiring to "group" and identify controls on the page, and what I want to do with that group of controls.
Edit: Processing conrols in an array or list
In all of the above "div" and control processing routines, we REALLY are doing the same as if we placed the controls into an array, or list.
For example, the floader routine does this: (we can pass it the current web page, or as more often a "div".
So, it looks like this:
foreach (System.Web.UI.Control c in F.Controls)
{
if (c.GetType() == typeof(TextBox))
{
TextBox ctlC = c as TextBox;
ctlC.Text = "zoo";
ctlC.Visible = true;
}
else if (c.GetType() == typeof(Label))
{
Label ctlC = c as Label;
}
else if (c.GetType() == typeof(DropDownList))
{
DropDownList ctlC = c as DropDownList;
}
else if (c.GetType() == typeof(CheckBox))
{
CheckBox ctlC = c as CheckBox;
}
I removed most of the code, but above shows how you can pass/have a bunch of controls in a page, or div or whatever.
So, my WHOLE post and narrative been based on the above approach - which I assumed was obvious here.
However, lets code up a collection, and thus make this even more obvious.
so this markup:
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
<br />
<asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>
<br />
<asp:CheckBox ID="CheckBox2" runat="server" />
So, our code behind can then do this:
List<Control> mycontrols = new List<Control>();
mycontrols.Add(TextBox1);
mycontrols.Add(CheckBox2);
mycontrols.Add(Label1);
foreach (Control myC in mycontrols)
{
myC.Visible = false;
}
// set text value of controls
foreach (Control myC in mycontrols)
{
myC.Visible = false;
if (myC.GetType() == typeof(TextBox))
{
TextBox ctlC = myC as TextBox;
ctlC.Text = "zoo";
ctlC.Visible = true;
}
else if (myC.GetType() == typeof(Label))
{
Label ctlC = c as Label;
ctlC.Text = "zoo zoo";
}
else if (myC.GetType() == typeof(CheckBox))
{
CheckBox ctlC = c as CheckBox;
ctlC.Checked = true;
}
}
So, for visible, we can use visible property. but, for other features of the control, say like Text or whatever? We cast the control into its type, and thus can use say checked of the checkbox, and it does not even have a .text property.

Related

How to add class CssClass and its attributes to RadioButtonList in code-behind

In my scenario, there is a UserControl(Day) containing RadioButtonList and this UserControl is contained in another 5 UserControls(Monday, Tuesday...Friday) and this UserControls are placed in aspx page.
In the code behind of Day UserControl, the following code is present.
rdlUser.DataTextField = "Description";
rdlUser.DataValueField = "Value";
rdlUser.DataSource = userTypes;
rdlUser.DataBind();
rdlUser.Items[0].Enabled = false;
The markup for rdlUser in Day UserControl is as below...
<asp:RadioButtonList ID="rdlUser" AutoPostBack="true" OnSelectedIndexChanged="rdlUser_SelectedIndexChanged"></asp:RadioButtonList>
There are 4 userTypes that are getting created as rdlUser in Day UserControl from Database. The userTypes are given below...
rdlUser_0 - Normal User
rdlUser_1 - Supervisor
rdlUser_2 - Admin
rdlUser_3 - Super User
How can I apply class NormalUser to "Normal User" and rest as SpecialUser class from code behind with relevant attributes.
You can loop all the ListItem elements.
foreach (ListItem item in rdlUser.Items)
{
if (item.Text == "Normal User")
{
item.Attributes.Add("class", "NormalUser");
}
else
{
item.Attributes.Add("class", "SpecialUser");
}
}
Note that this will wrap a <span class="NormalUser"> around the RadioButton, so you may need to change the css.
.SpecialUser label { color:red; }
RadioButtonList generates HTML output containing input and labels.
<input id="rdlUser_0" type="radio" name="rdlUser_0" value="0">
<label for="rdlUser_0">Normal User</label>
Best practice, add your option's style to the css file.
#rdlUser input[value='0'] + label {color:red}
Or
#rdlUser label:nth-child(1){color:red}

Create checkbox next to each label

I need this page to be very easily maintained, so I need most of the stuff to be programmatically generated. I need to create checkboxes next to normal Labels, without touching the .aspx file. right now I generate a list with all labels on my page called labels. Each label on my site has an ID beginning with lbl_, but the ones that are supposed to have a checkbox begin with lblx_. I then want to use something like this to create said checkboxes:
foreach (Label label in labels)
{
if (label.ID.Contains("lblx_"))
{
CheckBox cb = new CheckBox();
cb.ID = "cb_statistikname_" + label.ID;
label.Controls.AddAt(0, cb);
}
}
Right now this code replaces the labels, the same happens when I use label.Control.Add(cb)
You can use Page.Controls.AddAt() with combination of page.Page.Controls.IndexOf()
if(label.Parent != null && label.Parent.Controls.IndexOf(label) >= 0)
label.Parent.Controls.AddAt(label.Parent.Controls.IndexOf(label) + 1, cb);
Note :This should be done in Page PreInit events.
If you set the Text property in your Label control, basically all child controls get wiped out. See this answer: asp:label doesn't render children

Controls property and FindControl function C#

I'm coding a calendar that displays some events. Each day has a button for morning, afternoon and night events, when there are events to show the button is enabled and its color is changed. I am displaying these buttons in an html table and when someone changes the month being displayed the program has to "cleanup" the buttons by disabling all of them and setting their colors to white again. Thing is I was able to enable them by using the FindControl method on the table containing the buttons this way:
string butControl = /* id of the button */
Button block = mainTable.FindControl(butControl) as Button;
block.BackColor = Color.Gray;
block.Enabled = true;
And it works fine. In my cleanup method I don't want to call all the names of the buttons because there are 105, instead I used this method:
private void CleanUp()
{
foreach (Control c in mainTable.Controls)
{
Button bot = c as Button;
if (bot != null)
{
bot.BackColor = Color.White;
bot.Enabled = false;
}
}
}
But this does not change the color or enabled property of any of the buttons. My question is: Are not the controls in the Controls property of the table the same that can be found via the FindControl method? Or am I doing something wrong when retrieving the controls?
Isn't the problem that in you're iterating a list of controls rather than the hierarchy? FindControl uses the hierarchy. You can loop the controls as follows:
public IEnumerable<T> EnumerateRecursive<T>(Control root) where T : Control
{
Stack<Control> st = new Stack<Control>();
st.Push(root);
while (st.Count > 0)
{
var control = st.Pop();
if (control is T)
{
yield return (T)control;
}
foreach (Control child in control.Controls)
{
st.Push(child);
}
}
}
public void Cleanup()
{
foreach (Button bot in EnumerateRecursive<Button>(this.mainTable))
{
bot.BackColor = Color.White;
bot.Enabled = false;
}
}
You can implement it using recursion as well, but I usually prefer a stack because it is much faster.
I assume that you're using an ASP table, as that would certainly not work. You could get around it in other ways, but if it doesn't matter to you to use some HTML, I would suggest that you restructure it to look like this:
<form id="form1" runat="server">
<asp:Panel ID="mainTable" runat="server">
<table>
<tr>
<td>
<asp:Button ID="Button1" runat="server" Text="Button" />
</td>
</tr>
</table>
</asp:Panel>
</form>
Note the use of only html controls inside the asp:Panel except for the actual buttons. Using ASP, you would have to recursively look for children.
EDIT:
Speaking of recursively looking for children, Stefan made that exact suggestion and provided code before I finished writing, and I would definitely recommend his method; he's evidently much less lazy than me.
==================================
Stefan's approach has a slight error in that you can't explicitly typecast without knowing a type, and you can't know a type if you use generics, as he has. Here is a lazy adaptation for use purely with buttons, as you are using it for.
Do not give this "answer" status. It is a corruption of someone else's work.
public IEnumerable<Button> EnumerateRecursive(Control root)
{
// Hook everything in Page.Controls
Stack<Control> st = new Stack<Control>();
st.Push(root);
while (st.Count > 0)
{
var control = st.Pop();
if (control is Button)
{
yield return (Button)control;
}
foreach (Control child in control.Controls)
{
st.Push(child);
}
}
}
public void Cleanup()
{
foreach (Button bot in EnumerateRecursive(this.mainTable))
{
bot.BackColor = Color.White;
bot.Enabled = false;
}
}

How can I find the selected RadioButton's value in ASP.NET?

I have two asp:RadioButton controls which are having the same GroupName which essentially makes them mutually exclusive.
My markup:
<asp:RadioButton ID="OneJobPerMonthRadio" runat="server"
CssClass="regtype"
GroupName="RegistrationType"
ToolTip="125"/>
<asp:RadioButton ID="TwoJobsPerMonthRadio" runat="server"
CssClass="regtype"
GroupName="RegistrationType"
ToolTip="200"/>
My intention was to find the tooltip / text of the RadioButton that is checked. I have this code-behind:
int registrationTypeAmount = 0;
if (OneJobPerMonthRadio.Checked)
{
registrationTypeAmount = Convert.ToInt32(OneJobPerMonthRadio.ToolTip);
}
if (TwoJobsPerMonthRadio.Checked)
{
registrationTypeAmount = Convert.ToInt32(TwoJobsPerMonthRadio.ToolTip);
}
I find that code ugly and redundant. (What if I have 20 checkboxes?)
Is there a method that would get the checked RadioButton from a set of RadioButtons with the same GroupName? And if not, what are the pointers on writing one?
P.S: I cannot use a RadioButtonList in this scenario.
You want to do this:
RadioButton selRB = radioButtonsContainer.Controls.OfType<RadioButton>().FirstOrDefault(rb => rb.Checked);
if(selRB != null)
{
int registrationTypeAmount = Convert.ToInt32(selRB.ToolTip);
string cbText = selRB.Text;
}
where radioButtonsContainer is the container of the radiobuttons.
Update
If you want to ensure you get RadioButtons with the same group, you have 2 options:
Get them in separate containers
Add the group filter to the lamdba expression, so it looks like this:
rb => rb.Checked && rb.GroupName == "YourGroup"
Update 2
Modified the code to make it a little more fail proof by ensuring it won't fail if there's no RadioButton selected.
You may try writing down a similar method to the one below:
private RadioButton GetSelectedRadioButton(params RadioButton[] radioButtonGroup)
{
// Go through all the RadioButton controls that you passed to the method
for (int i = 0; i < radioButtonGroup.Length; i++)
{
// If the current RadioButton control is checked,
if (radioButtonGroup[i].Checked)
{
// return it
return radioButtonGroup[i];
}
}
// If none of the RadioButton controls is checked, return NULL
return null;
}
Then, you can call the method like this:
RadioButton selectedRadio =
GetSelectedRadioButton(OneJobPerMonthRadio, TwoJobsPerMonthRadio);
It will return the selected one (if there is) and it will work for no matter how many radio buttons you have. You can rewrite the method, so that it returns the SelectedValue, if you wish.

Dynamic Controls - C# - CheckBoxList Parent - Children

First I understand the need to build dynamic controls in the OnInit Section.
However, I read a document from Scott Guthrie?
http://scottonwriting.net/sowblog/archive/2004/10/08/162998.aspx
So I got the impression from these blogs that if you add the control to the container then modify the properties, you can get at the control in the Page_Load.
In a nutshell, I have a table with a fk back to the table creating a hierarchy.
I load 3 usercontrols the page with checkbox lists that relate back through the parent key.
Table like this:
create table myTbl
(
id int identity,
par_id int,
item_desc varchar(25)
other_desc_flag bit
)
What my clients need is the ability to make a checkbox selection.
The child set of textboxes will display based on the parent.
If the txt_flag is set, a checkbox entry will not be populated.
Instead, they want the desc label printed out with a textbox for response.
The user data is not kept in the table above by the way.
So the issue I have is these text responses can be at any level of the custom control.
So I created a class with a 3 items ( id, literal control, and a textbox ).
I then dynamically create the controls based on the selection at any particular level.
I read each level into a dataset, I iterate through the dataset looking for that flag.
I capture an index variable in the rows with this flag and I create a List class to hold the
id, text_desc. I then remove the row from the table in the dataset and bind the remaining items to the checkboxlist.
I then go back to my control and write out dynamically the controls.
But like all those before me, I am doing evil battle against the Page Cycle...lol.
I cannot see the controls. I plan to DataBind() my controls separately on load as I have not gotten to the point where I'm getting the clients reponses from the database. That's for another day. The placeholder with my dynamic controls is OtherPlaceHolder. I have tried setting the Viewstate to true and false.
Any pointers on how to get the # of items on postback into a session variable so I can create the controls on the OnInit section.
Here is the code. This is being run from a Master Page...
On the controls, I changed the < & > to [ ] because this page that attempts to put code into
a controlbox with scrollbars was cutting off that code.
[asp:UpdatePanel ID="UpdPanel" runat="server" EnableViewState="true" UpdateMode="Always"]
[ContentTemplate]
[asp:Table runat="server" ID="ContainerTbl"]
[asp:TableHeaderRow]
[asp:TableHeaderCell ColumnSpan="2" CssClass="tdCell"][asp:Literal ID="LitDesc" runat="server" Text="Level" /][/asp:TableHeaderCell]
[/asp:TableHeaderRow]
[asp:TableRow]
[asp:TableCell runat="server" ID="tblItems" VerticalAlign="top"]
[asp:PlaceHolder runat="server" ID="CtrlPlaceHolder"]
[asp:CheckBoxList ID="cboItems" Visible="false" runat="server" AutoPostBack="true"][/asp:CheckBoxList]
[asp:HiddenField ID="otherCnt" runat="server" /]
[/asp:PlaceHolder]
[asp:PlaceHolder runat="server" ID="OtherPlaceHolder" EnableViewState="false"]
[/asp:PlaceHolder]
[/asp:TableCell]
[/asp:TableRow]
[asp:TableRow]
[asp:TableCell VerticalAlign="top"]
[asp:Label ID="LabMsg" runat="server" CSSClass="tdCell" Font-Bold="true" Visible="false"/]
[/asp:TableCell]
[/asp:TableRow]
[/asp:Table]
[asp:HiddenField ID="hLevel" runat="server" Value="" /]
[/ContentTemplate]
[/asp:UpdatePanel]
private void WriteOutQuestions(List<Questions> qList)
{
int itemCnt = 1;
// clear any controls in other place holder first.
OtherPlaceHolder.Controls.Clear();
Table OTD = new Table();
foreach (Questions qst in qList)
{
// we're going to create the new control and add to
// the placeholder - OtherPlaceholder
// we'll then reference those controls and add the data to those
// controls.
// see dynamic control article: http://scottonwriting.net/sowblog/archive/2004/10/08/162998.aspx
HiddenField hItemId = new HiddenField();
TextBox txtItem = new TextBox();
LiteralControl ltcItem = new LiteralControl();
// add the new controls
string strItemId = "hItem" + Convert.ToString(itemCnt);
string strTxtItem = "txtItem" + Convert.ToString(itemCnt);
string strLtcItem = "ltcItem" + Convert.ToString(itemCnt);
hItemId.ID = strItemId;
hItemId.EnableViewState = true;
txtItem.ID = strTxtItem;
txtItem.EnableViewState = true;
ltcItem.ID = strLtcItem;
ltcItem.EnableViewState = true;
OTD.Controls.Add(OtherDescAddControl(OtherPlaceHolder, hItemId, ltcItem, txtItem));
// now reference the new added controls and set values from Question object...
++itemCnt;
}
OtherPlaceHolder.Controls.Add(OTD);
// now post data to controls...
itemCnt = 1;
foreach (Questions qst in qList)
{
string strItemId = "hItem" + Convert.ToString(itemCnt);
string strTxtItem = "txtItem" + Convert.ToString(itemCnt);
string strLtcItem = "ltcItem" + Convert.ToString(itemCnt);
HiddenField hfld = (HiddenField)OtherPlaceHolder.FindControl(strItemId);
TextBox txtBox = (TextBox)OtherPlaceHolder.FindControl(strTxtItem);
LiteralControl ltx = (LiteralControl)OtherPlaceHolder.FindControl(strLtcItem);
hfld.Value = qst.HFld.ToString();
txtBox.Text = qst.TxtBox;
txtBox.Attributes.Add("class", "txtBox");
ltx.Text = qst.Ltc.ToString();
++itemCnt;
}
//decrement itemCnt and populate box here...
--itemCnt;
HiddenField hfldCnt = (HiddenField)CtrlPlaceHolder.FindControl("otherCnt");
hfldCnt.Value = Convert.ToString(itemCnt);
hfldCnt.Visible = true;
}
On the assumption that when you say "I cannot see the controls" you mean that you're getting null references when you try to access them in the postback (rather than that the HTML doesn't contain them), have you tried using Page.EnsureChildControls()?
Ok If I understood your question right, you want to save your controls and load them back on postbacks. Here is what you can do:
List<HiddenField> HiddenFields = new List<HiddenField>{};
List<TextBox> TextBoxs = new List<TextBox>{};
List<LiteralControl> LiteralControls = new List<LiteralControl>{};
OTD.Controls.Add(OtherDescAddControl(OtherPlaceHolder, hItemId, ltcItem, txtItem));
// do this for all your items that you load to page (add them to your list).
HiddenFields.Add(hItemId);
// when you are done with loading all your controls to page, add your populated Lists to session.
Session["HiddenFields"] = HiddenFields;
//On Page_Init or Page_Load, simpy load them back IF **page is postback**.
If(Page.IsPostBack)
{
LoadControlsFromSession();
}
private void LoadControlsFromSession()
{
HiddenFields = Session["HiddenFields"] as List<HiddenFields>;
// Load all your List objects from session like above.
int counter = 0;
if(HiddenFields != null)
{
foreach(HiddenField hdnField in HiddenFields)
{
//load your objects with the same method you have from your List.
OTD.Controls.Add(OtherDescAddControl(OtherPlaceHolder, HiddenFields[counter], LiteralControls[counter], TextBoxs[counter]));
counter++;
}
}
}
I apologize for lack of clarity.
I believe I did try setting Session variables in my classes when I created the controls and they were null on postback. I tried to access the session variable in the page init and preload and zip.
I did find an interesting workaround to this problem. On page_unload I parsed through the controls into an arraylist of hashtables of the database id & user'sentered text answer.

Categories