I'm just wondering really.
I have series of if statements that check
if textboxes are empty (or have results strings) after i pass SQL
results to then
.
if (IncidentData.Tables[0].Rows[0]["Property Category"].ToString()
== "RoadVehicle")
{
lbl_alarmOperated.Visible = false; tb_alarmOperated.Visible = false;
}
else
{
lbl_alarmOperated.Visible = true;
tb_alarmOperated.Visible = true;
}
I have been looking into controls and seeing if i can do a check on all textboxes and hide them if they are empty (instead of writing loads of if statements)
i have this at the moment:
public void ChecknHide()
{
HideTextBoxes(this);
}
protected void HideTextBoxes(Control ctrl)
{
foreach (var c in ctrl.Controls)
{
if (c is TextBox) ((TextBox)c).Text = String.Empty;
{
((TextBox)c).Visible = false;
}
}
}
Its mostly put together from reading posts on here. But I've ran into an issue. When i compile and go to view the page i get this:
Unable to cast object of type 'ASP.masterpage_master' to type
'System.Web.UI.WebControls.TextBox'.
Any ideas whats going wrong?
The statement after the if isn't part of the condition. This causes all controls to be casted to a TextBox. You should be able to fix it like so:
protected void HideTextBoxes(Control ctrl)
{
foreach (var c in ctrl.Controls)
{
if (c is TextBox && ((TextBox)c).Text == String.Empty)
{
((TextBox)c).Visible = false;
}
}
}
Weird code line:
if (c is TextBox) ((TextBox)c).Text = String.Empty;
Try something like:
protected void HideTextBoxes(Control ctrl)
{
//Iterate over controlls
foreach (var c in ctrl.Controls)
{
//Check for Textbox controls with the .Text property equal to Null or Empty.
if (c is TextBox && string.IsNullOrEmpty(((TextBox)c).Text))
{
//Set visibility of Textbox control to invisible.
((TextBox)c).Visible = false;
}
}
}
You're checking if c is a TextBox, but then trying to cast c as a TextBox and set it to String.Empty in the same line, regardless of whether it actually is a TextBox.
if (c is TextBox) ((TextBox)c).Text = String.Empty;
Related
I would like my application to to check if all 5 textboxes are numeric, and if the values are all true. Display the Talley. If not, I don't want my method to execute and right now it is. The way I have IsValid method coded, to me seems like it should work. I guess if someone could point me in the right direction, I'm sure there is a simple way of doing something such as this but I haven't found it. Thanks in advance to anyway that takes their time to look at this.
I have tried several variations of the example here, but haven't been able to do what it needs to do.
private void btnCalculate_Click(object sender, EventArgs e)
{
if (IsValid()) // if everything passes it will hit this
{
double total;
double hospitalCharge;
hospitalCharge = CalcStayCharges() * Convert.ToDouble(txtDays.Text);
total = hospitalCharge + CalcMiscCharges();
CalcTotalCharges(total);
lblDisplay.Text = "The total is " + CalcTotalCharges(total).ToString("c");
}
//else return;
// IsNumber(txtDays.Text.ToString()); // testing somehing
}
private double CalcStayCharges()
{
double hosipalCharge = 350;
return hosipalCharge;
}
private double CalcMiscCharges()
{
double Totalcharges;
Totalcharges = Convert.ToDouble(txtLab.Text) + Convert.ToDouble(txtMedication.Text) + Convert.ToDouble(txtRehab.Text) + Convert.ToDouble(txtSurgical.Text);
return Totalcharges;
}
private double CalcTotalCharges(double total)
{
return total;
}
private bool IsNumber(TextBox myNumber)
{
if (double.TryParse(Convert.ToString(myNumber), out double n))
{
// MessageBox.Show("string");
return false;
}
// MessageBox.Show("number"); // this is how you can test a bool value
return true;
}
private bool IsValid()
{
bool validation = false;
foreach (Control ctl in this.Controls)
{
if (ctl is TextBox)
{
TextBox tb = ctl as TextBox;
IsNumber(tb);
if (IsNumber(tb) == true)
{
validation = true;
}
else if (IsNumber(tb) == false)
{
validation = false;
}
}
}
return validation;
}
The problem is that your loop will override validation with whatever value it has last. So, as it stands, you code will only really validate the last text box.
The usual way to handle this is to make an assumption that it is valid. Loop through everything, and only set it if it is invalid. like this.
private bool IsValid()
{
bool validation = true;
foreach (Control ctl in this.Controls)
{
if (ctl is TextBox)
{
TextBox tb = ctl as TextBox;
IsNumber(tb);
if (IsNumber(tb) == false)
{
validation = false;
}
}
}
return validation;
}
Nick, please check this answer and you will understand.
Basically he is getting all controls from the Page of type DropDownList (in your case TextBox). And then he iterates each control and validates them. If you want something more complex, when iterating the list of controls, you can validate its properties and process the controls with the specified properties that you gave to them, when you declared them in the page.
I rephrased your IsValid statement. Please check it out
private bool IsValid()
{
bool validation = true;
foreach (Control ctl in this.Controls)
{
if (ctl is TextBox)
{
TextBox tb = ctl as TextBox;
if (IsNumber(tb) == false)
{
validation = false;
break;
}
}
}
return validation;
}
Improved version (basic syntax)
private bool IsValid()
{
bool validation = true;
foreach (TextBox tb in this.Controls.OfType<TextBox>())
{
if (!IsNumber(tb))
{
validation = false;
break;
}
}
return validation;
}
Another variation of IsValid. It uses a pattern matching if and plays logic games to get rid of the validation variable:
private bool IsValid()
{
foreach (var control in this.Controls)
{
if (control is TextBox textBox)
{
//the first test to fail cause the function to return false
//no need to test the rest of the controls
if (!IsNumber(textBox))
{
return false;
}
}
}
//nothing returned false, so it must be valid
return true;
}
Notice that true and false only appear in the return statements. You don't need to test Booleans for truthiness or falsehood, they are true or false all on their own. If you want to test a bool b for true-ness:
if (b) { /* code goes here */ }
of for false-ness
if (!b) { /* other code */ }
The other thing you might do if you have a lot of controls on the page and only a few of them are text boxes is keep a separate collection of textbox controls. You could have a List<TextBox> and populate it once at page load time.
Why for-each? :) use Linq (more declarative way) programming!
More of a condensed form and readable.
private bool IsValid()
{
return this.Controls.OfType<TextBox>().Where(t =>
IsNumber(t.Text)).ToList().Any();
}
You can use your IsNumber(...) to validate the text box values.
So you can use the validate method as below
if (!IsValid()) return;
Hope this helps.
Cheers!
private bool LoopOverControls(bool reset, bool checkIfEmpty)
{
bool results;
foreach (Control ctrl in this.Controls)
{
if ((ctrl as TextBox) != null)
{
if (reset == true)
(ctrl as TextBox).Text = "";
if (checkIfEmpty == true)
results = true;
}
}
return results;
}
I want to use the method in some places in the code. Instead making loop over the controls over again each time i want to make a method i can call.
The method was before:
private void LoopOvercontrols(bool reset, bool checkIfEmpty)
{
foreach (Control ctrl in this.Controls)
{
if ((ctrl as TextBox) != null)
{
if (reset == true)
(ctrl as TextBox).Text = "";
if (checkIfEmpty == true)
}
}
}
And this is the places i'm using the loop over the controls in my code the first place is in the constructor: I check if the textBoxes are not empty then do something in this case change btnReset enable true.
foreach (Control ctrl in this.Controls)
{
if ((ctrl as TextBox) != null)
{
(ctrl as TextBox).TextChanged += on_TextChanged;
if ((ctrl as TextBox).Text != "")
{
btnReset.Enabled = true;
}
}
}
Then inside another event this time i check if the textboxes are empty and set the btnReset enable to false:
foreach (Control ctrl in this.Controls)
{
if ((ctrl as TextBox) != null)
{
(ctrl as TextBox).TextChanged += on_TextChanged;
if ((ctrl as TextBox).Text == "")
{
btnReset.Enabled = false;
}
}
}
So far i'm looping over the textBoxes in two places but i might want to loop over them again later in other places. The problem is how to make the method LoopOverControls so i can decide with a bool and maybe other properties some cases and using buttons or other controls within the decitions ?
You can write a method that receive the action to be executed as parameter.
The work for this new method is to enumerate all the textboxes and call the action method for each one.
public void TextBoxEnumerateAndAction(Action<TextBox> execute)
{
// Get just the TextBoxes, no need of ugly casts...
foreach(TextBox t in this.Controls.OfType<TextBox>())
{
execute?.Invoke(t);
// This part is common to every textbox, so it can stay inside the
// enumeration loop....
btnReset.Enabled = !string.IsNullOrEmpty(t.Text)
}
}
Now define the Action methods to pass to TextBoxEnumerateAndAction
void AddTextChangedHandler(TextBox t)
{
t.TextChanged += on_TextChanged;
}
void RemoveTextChangedHandler(TextBox t)
{
t.TextChanged -= on_TextChanged;
}
So, everywhere you need to add or remove the TextChanged handler you could call
TextBoxEnumerateAndAction(AddTextChangedHandler);
Or if you have more fancy situations, you could simply define another action to pass to TextBoxEnumerateAndAction
I suggest you just add some comfort methods to contain the looping and type selection logic and allow callers to pass in delegate function to control the applied logic.
for example:
public void ActOn<TControl>(Action<TControl> applyFunction)
where TControl : Control
{
if (applyFunction == null) { throw new ArgumentNullException(nameof(applyFunction)); }
var controlsOfChosenType = this
.Controls
.OfType<TControl>();
foreach (var control in controlsOfChosenType)
{
applyFunction(control);
}
}
Then you can use it like this:
ActOn<TextBox>(textbox => textbox.Text = DateTime.Now.ToString());
I have a form which contains the following types of controls (only):
Button
ComboBox
Label
TextBox
I have a "Clear" button that calls this method:
private void ClearControls()
{
foreach (TextBox txtbx in this.Controls)
{
if (txtbx != null)
{
txtbx.Text = string.Empty;
}
}
foreach (ComboBox cmbx in this.Controls)
{
if (cmbx != null)
{
cmbx.SelectedIndex = -1;
}
}
}
...yet when I call it, the app hangs, and the log file says "Invalid cast" for that method. How could that be? It should deal with the TextBoxes and ComboBoxes, and disregard the rest - where could the invalid cast be?
That's not what foreach does.
Specifying a type in a foreach loop does not skip items of other types; instead, it will cast every item to that type.
You can call .OfType<T>() to get the filtered list that you're looking for.
The foreach will try to cast the control to the specified type which will give that invalid cast exception, what you should do is:
foreach(Control ctrl in this.Controls)
{
if(ctrl as TextBox != null)
{
//Textbox logic
}
if(ctrl as ComboBox!= null)
{
//ComboBox logic
}
}
Based on Gunther's starting point, this works:
foreach (Control ctrl in this.Controls)
{
if (ctrl as TextBox != null)
{
ctrl.Text = string.Empty;
}
if (ctrl as ComboBox != null)
{
((ComboBox)ctrl).SelectedIndex = -1;
}
}
I'm working in VS 2012 using C# and WinForms for my application, and I'm curious what sort of routine I should use to clear all methods of entering data I have, which includes textboxes, comboboxes, and date time pickers. I've Googled and found a few 'answers', but none seem to work or actually prove helpful.
[EDIT]:
I kept researching and actually found a helpful method that I just had to add some ifs to to get what I wanted:
private void ResetFields()
{
foreach (Control ctrl in this.Controls)
{
if (ctrl is TextBox)
{
TextBox tb = (TextBox)ctrl;
if (tb != null)
{
tb.Text = string.Empty;
}
}
else if (ctrl is ComboBox)
{
ComboBox dd = (ComboBox)ctrl;
if (dd != null)
{
dd.Text = string.Empty;
dd.SelectedIndex = -1;
}
}
else if (ctrl is DateTimePicker)
{
DateTimePicker dtp = (DateTimePicker)ctrl;
if (dtp != null)
{
dtp.Text = DateTime.Today.ToShortDateString();
}
}
}
}
Something like this:
void ClearThem(Control ctrl)
{
ctrl.Text = "";
foreach (Control childCtrl in ctrl.Controls) ClearThem(childCtrl);
}
And then:
ClearThem(this);
Another option:
Create a class deriving from Panel, with all of what you need on it, and Dock it in the Form. When you need to "refresh" - simply replace that Panel with a new instance of that Panel.
You could just loop in all the controls of the form and clear depending on the control type
We can clear all Textboxes, Comboboxes but not the DateTimePicker
If you want to clear the DateTimePicker you must set the properties:
Format = Custom, CustomFormat = " " and in time that you want to select a date in DateTimePicker
private void dateTimePicker1_CloseUp(object sender, EventArgs e)
{
dateTimePicker1.Format = DateTimePickerFormat.Short;
}
And this could be the solution:
public static void ClearAll(Control control)
{
foreach (Control c in control.Controls)
{
var texbox = c as TextBox;
var comboBox = c as ComboBox;
var dateTimePicker = c as DateTimePicker;
if (texbox != null)
texbox.Clear();
if (comboBox != null)
comboBox.SelectedIndex = -1;
if (dateTimePicker != null)
{
dateTimePicker.Format = DateTimePickerFormat.Short;
dateTimePicker.CustomFormat = " ";
}
if (c.HasChildren)
ClearAll(c);
}
}
Loop through your form controls, match them to your types and set it to "" or null;
I have a method that finds all the controls, iterates through them, determines if they are a textbox,drop down list, etc.. retrieves their ID name, and depending on the ID name it will set a boolean statement (thus I would know if that section of the form is complete, and will email to a certain group of people) unfortunetly this is done with too many if statements and was wondering if I could get some help making this more manageable
protected void getEmailGroup()
{
Control[] allControls = FlattenHierachy(Page);
foreach (Control control in allControls)
{
if (control.ID != null)
{
if (control is TextBox)
{
TextBox txt = control as TextBox;
if (txt.Text != "")
{
if (control.ID.StartsWith("GenInfo_"))
{
GenInfo = true;
}
if (control.ID.StartsWith("EmpInfo_"))
{
EmpInfo = true;
}
}
}
if (control is DropDownList)
{
DropDownList lb = control as DropDownList;
if (lb.SelectedIndex != -1)
{
if (control.ID.StartsWith("GenInfo_"))
{
GenInfo = true;
}
if (control.ID.StartsWith("EmpInfo_"))
{
EmpInfo = true;
}
}
}
}
}
}
Why not just use the Control.FindControl(string) method?
private void Button1_Click(object sender, EventArgs MyEventArgs)
{
// Find control on page.
Control myControl1 = FindControl("TextBox2");
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");
}
}
from: https://learn.microsoft.com/en-us/dotnet/api/system.web.ui.control.findcontrol
It is hard to understand the logic behind your code, but I'm sure it can be written easier. For example you can do something like this:
DropDownBox box = FlattenHierachy(Page)
.Where(c => c is DropDownList)
.Cast<DropDownList>()
.Where(d => d.SelectedIndex != -1)
.FirstOrDefault();
if (box != null)
{
if (box.ID.StartsWith("GenInfo_"))
{
GenInfo = true;
}
if (box.ID.StartsWith("EmpInfo_"))
{
EmpInfo = true;
}
}
Obviously you can make this generic if you extract the lambda expression from the seconde Where call. So you could reuse it for different types. That's the solution which is as close to your code as possible, but I guess it would be a better idea to use a recursive method traversing the page and giving that method your predicates as lambda expressions.
Cleaned up you code a little to only include each check once.
protected void getEmailGroup()
{
Control[] allControls = FlattenHierachy(Page);
foreach (Control control in allControls)
{
if (control.ID != null &&
((control is TextBox && ((TextBox)control).Text = "" )
|| (control is DropDownList && ((DropDownList)control).SelectedIndex != -1 ))
{
if (control.ID.StartsWith("GenInfo_"))
GenInfo = true;
if (control.ID.StartsWith("EmpInfo_"))
EmpInfo = true;
}
}
}
}
Instead of using the Lambda expression I have created a method that handles the control for me, and depending on the name of the control, it sets that section to be true
public bool setGroup(Control ctrl)
{
isAControl = false;
//set a section to true, so it will pull the html
if (ctrl.ID.StartsWith("GenInfo_"))
{
GenInfo = true;
lstControls.Add(ctrl.ID.Replace("GenInfo_", ""));
isAControl = true;
return isAControl;
}
here is a small snippet of my code I only want to check for certain controls(to speed things up) and I go through each control as each control has a different way to get the value (textbox would use .text where dropdownlist would use .selectedValue)
if(control is TextBox || control is DropDownList || control is RadioButton || control is RadioButtonList
|| control is CheckBox || control is CheckBoxList)
{
if (control is TextBox)
{
TextBox txt = control as TextBox;
if (txt.Text != "" && txt.Text != "YYYY/MM/DD")
{
setGroup(control);
if (isAControl)
{
string controlNoGroup = lstControls.Last();
strHtml = strHtml.Replace("#" + (controlNoGroup.ToString()) + "#", txt.Text);
}
}
}