The calculator I have made is a combination of textboxes and radiobuttons and when 'calculate' is clicked, I would like a message box to check the whole program and then (if necessary) display a message box saying something like 'the following areas still need completing' and then list those areas.
I know how to code a basic if lI have made is a co't know how to get it to check multiple textboxes and radiobuttons in one go.
The current code for the button is:
private void button4_Click(object sender, EventArgs e)
{
DrawForce = (Area2 * (StrengthCoeff / (WorkHardExp + 1)) * (Math.Pow(Math.Log(Area1 / Area2), WorkHardExp + 1)));
DrawForce = Math.Round(DrawForce, 2);
textBox7.Text = DrawForce.ToString() + " N";
}
I don't wish to copy the enter code onto here so I hope that will suffice
Thanks
If I understand you correctly, you're looking for a way to check many controls on the form in a loop. There are a couple of ways to do this.
One way would be to create a class-level collection on the form which holds references to the controls. For example, something like this:
private IEnumerable<TextBox> textBoxes = new List<TextBox>
{
TextBox1,
TextBox2,
TextBox3
};
Then you can examine it in a loop:
var errors = new List<string>();
foreach (var textBox in textBoxes)
if (string.IsNullOrWhitespace(textBox.Text))
errors.Add(string.Format("{0} is empty.", textBox.Name));
// errors now contains the list of validation messages
The downside to this is that you'd need to manually keep the collection updated if you change the form. If there aren't going to be many changes, that shouldn't be a problem.
Another option could be to loop through the Controls collection of the form. Something like this:
var errors = new List<string>();
foreach (var control in Controls)
if (control is TextBox)
if (string.IsNullOrWhitespace((control as TextBox).Text))
errors.Add(string.Format("{0} is empty.", (control as TextBox).Name));
// errors now contains the list of validation messages
This is more dynamic, but a little more brittle as well. If there are any text boxes nested in other controls then this won't find those, you'd need to make this more recursive to loop through control.Controls as well. That could get a little ugly, and might not be worth it if the form isn't likely to change. But either way, it might look something like this:
private IList<string> GetErrorsForControls(ControlCollection controls)
{
var errors = new List<string>();
foreach (var control in controls)
{
if (control is TextBox)
if (string.IsNullOrWhitespace((control as TextBox).Text))
errors.Add(string.Format("{0} is empty.", (control as TextBox).Name));
errors = errors.Concat(GetErrorsForControls(control.Controls));
}
return errors;
}
Then in your code you'd just invoke that method:
var errors = GetErrorsForControls(Controls);
To add validation for other types of controls besides text boxes, simply add other class-level collections or add other type checks in the loops.
Related
I have a list of checkbox controls
public List<CheckBox> _checkBoxes = new List<CheckBox>();
I add a certain amount during runtime using a switch case with the properties such as location and visibility.
This all works fine, but if I want the checkboxes to disappear or become checked at some point the GUI doesn't get updated, the list is updated with the new data but just not visually.
* I ended up doing this*
I created a bunch of checkboxes on the winfrom.Created a method which you can choose which ones are visible. Then created a method to fill a list of type checkbox. Then you can search the panel for control types, once you found the control, it can be manipulated. This isn't elegant and probably isn't the best way, but i am new to custom controls and winforms.
//search panel for checkboxes
foreach (Control c in panel1.Controls)
{
if (c is CustomControls.RoundedCheckBox)
{
CustomControls.RoundedCheckBox checkBox = c as CustomControls.RoundedCheckBox;
//if it is checked add to list
if(checkBox.Checked)
{
_checkBoxes.Add(checkBox);
}
}
}
If you have something like this:
_checkBoxes.Add(new CheckBox());
_checkBoxes[0].Parent = this;
then you should be able to manipulate your checkboxes from the list:
_checkBoxes[0].Checked = false;
But, the problem may occur if you do it in some kind of loop and want to see the results immediately.
In Windows there is something called message loop. Application simply works like that (pseudocode: TL;DR)
while(true)
{
message = GetFirstMessage();
if(message != null)
{
if(message.Id == CloseApplication)
break;
DispatchMessage(message);
RemoveFirstMessage();
}
}
So, application takes message from queue, then process it. A message is everything - button click, mouse move, paint... Everything.
So when a message is dispatched it looks for the control that should receive this message and then it does some work.
So, for example if you have something like that:
foreach(var ch in _checkBoxes)
{
ch.Checked = false;
DoSomeWorkThatTakesTime();
ch.Checked = true;
}
You won't see the change, because you are "trapped" in DispatchMessage. When you set Checked, you really sending a message. But this message cannot be Dispatched right now, because you are inside the foreach loop.
So the only thing you can do here is to tell your application - now, please DO READ message queue. In WinForms it's called "DoEvents", so this will do the work:
foreach(var ch in _checkBoxes)
{
ch.Checked = false;
Application.DoEvents();
DoSomeWorkThatTakesTime();
ch.Checked = true;
Application.DoEvents();
}
I have a panel that contains 5 textboxes, I am trying to loop through the Panel and insert the value of the textbox into the database if it is not 0.
my panel name is Panel1
I honestly do not know from where to start or how to loop in a Panel that contains textfields, any suggestions are appreciated:
Here is my try which it does not compile (I am not sure how to write a loop that loops through a panel)
const string query = "INSERT INTO deductible (number) VALUES (#yes)";
using (var command = new SqlCommand(query, conn))
{
foreach (Panel1 c in this.Controls)
{
if (c.ToString() != "0")
{
command.Parameters.AddWithValue("#yes", c.Text);
command.ExecuteNonQuery();
}
}
I also attached a screenshot of my Panel1.
Thank you.
The simple answer is
foreach(Control control in this.Controls) {
if (control is TextBox) {
// The code here ...
}
}
The problem though is that you then need to make sure that the order the textboxes are looped over is correct, which adds more maintenance work that is entirely unnecessary. A better approach would be to learn about data binding. Or even more simply, just name your textboxes and assign them directly. Either of those is preferable to using a loop I think.
One way is to iterate each control within your Panel that is a TextBox.
foreach (TextBox tb in Panel1.Controls.OfType<TextBox>())
{
if (tb.Text != "0")
{
}
}
You're trying to loop through items of type Panel1 in this.Controls. What you want to do is loop through items of type TextBox in Panel1.Controls.
foreach(Control c in Panel1.Controls) {
var textbox = Control As TextBox;
if(textbox != null){
// do stuff...
}
}
You also want to look at the Text property of the TextBox, not call ToString on it.
if(textbox.Text != "0"){ //do stuff... }
And you add a #yes parameter to the same command multiple times within the loop, without clearing out the parameters list. I'm not certain if that will work, but if it causes a problem, you should just be able to call command.Parameters.Clear to clear the old parameter before adding the new one.
I have a form where I have lots of textboxes and all of them are required to be filled out. In C# how do I actually if check there are group of fields having a null or whitespace?
I am familiar with string.isNullOrWhiteSpace(string here) but I don't want to do multiple if statements of that, it would result in a bad code.
I am trying to avoid something like this
if(string.isNullOrWhiteSpace(string here)
|| string.isNullOrWhiteSpace(string here)
|| string.isNullOrWhiteSpace(string here))
{
// do something
}
Are there fix for this type of bad code?
You can query the controls collection of the form (or relevant container) and filter for textboxes and further query to see if any are empty (none should really have null values). Example:
var emptyTextboxes = from tb in this.Controls.OfType<TextBox>()
where string.IsNullOrEmpty(tb.Text)
select tb;
if (emptyTextboxes.Any())
{
// one or more textboxes are empty
}
You can do effectively the same thing using the fluent syntax.
bool isIncomplete = this.Controls.OfType<TextBox>().Any(tb => string.IsNullOrEmpty(tb.Text));
if (isIncomplete)
{
// do your work
}
For this code, you should be working with at least Visual Studio 2008 / C# 3 / .NET 3.5. Your project needs to have a reference to System.Core.dll (should have one by default) and you need a using System.Linq; directive in the class file.
Based upon your comments, consider another method if you are having trouble understanding or working with the linq version. You can certainly do this in an explicit loop (the Linq code will ultimately be a loop as well). Consider
bool isIncomplete = false;
foreach (Control control in this.Controls)
{
if (control is TextBox)
{
TextBox tb = control as TextBox;
if (string.IsNullOrEmpty(tb.Text))
{
isIncomplete = true;
break;
}
}
}
if (isIncomplete)
{
}
Finally, this code is written as if all of the textboxes are in a single container. That container might be the form, a panel, etc. You will need to point to the appropriate container (eg., instead of this (the form) it might be this.SomePanel). If you are working with controls that are in multiple and perhaps nested containers, you will need to do more work to find them programmatically (recursive searching, explicit concatenation, etc.) or you might just preload the references into an array or other collection. For example
var textboxes = new [] { textbox1, textbox2, textbox3, /* etc */ };
// write query against textboxes instead of this.Controls
You said you have multiple GroupBox controls. If each GroupBox is loaded onto the form and not nested in another control, this may get you started.
var emptyTextboxes = from groupBox in this.Controls.OfType<GroupBox>()
from tb in groupBox.Controls.OfType<TextBox>()
where string.IsNullOrEmpty(tb.Text)
select tb;
That depends on what you consider "bad code." Depending on your requirements what text boxes are required to be filled out can vary. Further, even if all of the fields are required all of the time you still want to give friendly error messages letting people know which field they didn't fill out. There a variety of approaches to solving this issue depending on how you are rendering your form. Since you haven't specified any here's a very direct method for doing so.
var incompleteTextBoxes = this.Controls.OfType<TextBox>()
.Where(tb => string.IsNullOrWhiteSpace(tb.Text));
foreach (var textBox in inCompleteTextBoxes)
{
// give user feedback about which text boxes they have yet to fill out
}
Yet another solution.
This will recursively travel the whole control Tree , and Check for null or empty text in all of the textboxes.
caveat -
If you have some fancy controls not inheriting from the standard Winforms textbox - check will not be performed
bool check(Control root,List<Control> nonFilled)
{
bool result =true;
if (root is TextBox && string.isNullOrEmpty(((TextBox)root).Text) )
{
nonFilled.Add(root);
return false;
}
foreach(Control c in root.Controls)
{
result|=check(c,nonFilled)
}
return result;
}
Usage :
List<Control> emptytextboxes=new List<Control>()
bool isOK=check(form, emptytextboxes);
I have seen many others with similar problems but I cannot find the flaw in my logic here. Any help would be greatly appreciated.
I have a Panel which I have added numerous label and textbox controls to, ie:
myPanel.Controls.Add(txtBox);
These controls are created and added in a method called previous to the iteration method.
I want to iterate through each textbox and use its Text property as a parameter in another method but I am not having any luck. Here is my attempt to iterate:
public void updateQuestions()
{
try
{
foreach (Control c in editQuestionsPanel.Controls)
{
if (c is TextBox)
{
TextBox questionTextBox = (TextBox)c;
string question = questionTextBox.Text;
writeNewQuestionToTblQuestions(question);
}
}
}
catch (Exception err)
{
Console.WriteLine(err.Message);
}
}
The problem I am having is that the controls are not in the Panel when I arrive at this updateQuestions() method. Here is the process involved:
A commandButton is clicked and the questions are read from a DB, for each question a method is called which adds 2 labels and a textbox to editQuestionsPanel.Controls. This panel is inside a PlaceHolder which is then made visible.
When a button inside the PlaceHolder is clicked, the updateQuestions() method is called and the editQuestionsPanel.Controls.Count = 1. As there are approx 12 questions in the DB it should be around 36. The one control inside the Panel is of type:
System.Web.UI.LiteralControl
It contains no controls.
I am sure that somwhere in the lifecycle the Panel's controls are being cleared but I do not know how to step thru the life cycle. I have a Page_load method which is called as soon as a button is clicked but once the button which calls updateQuestions() is clicked the editQuestionsPanel.Controls.Count is already back to 1 so it must be cleared before this but I do not know how to correct this...
Any help you can give to help me solve this would be greatly appreciated - its killing me!
This selects from collection controls only that which are of type TextBox.
(the same as control is TextBox or (control as TextBox) != null)
If controls are contained in editQuestionsPanel.Controls:
using System.Linq;
IEnumerable<TextBox> textBoxes = editQuestionsPanel.Controls.OfType<TextBox>();
foreach (TextBox textBox in textBoxes)
{
// do stuff
}
To select all child controls use next extension method:
public static IEnumerable<T> GetChildControls<T>(this Control control) where T : Control
{
var children = control.Controls.OfType<T>();
return children.SelectMany(c => GetChildControls<T>(c)).Concat(children);
}
Using:
IEnumerable<TextBox> textBoxes = editQuestionsPanel.GetChildControls<TextBox>();
When you add controls dynamically, you need to do that on every request - asp.net doesn't do that for you!
Add the controls in the Init or Load phase, then they will get populated with the postback values.
A frequently made mistake: Container.Controls only contains the first level child controls in this container. That is: TextBox1 in PanelA, PanelA in PanelB, you can't get TextBox1 in PanelB.Controls.
My solution is to write an extension method:
public static IEnumerable<Control> AllControls(this Control ctl)
{
List<Control> collection = new List<Control>();
if (ctl.HasControls())
{
foreach (Control c in ctl.Controls)
{
collection.Add(c);
collection = collection.Concat(c.AllControls()).ToList();
}
}
return collection;
}
Now TextBox1 is in PanelB.AllControls(). To filter all controls with type, using PanelB.AllControls().OfType<TextBox>()
If the other answers don't help, try doing your code but add recursivity. Your code would not work if it's editQuestionsPanel => Panel => Textbox
You can do something like this instead:
var questions = from tb in editQuestionsPanel.Controls.OfType<TextBox>()
select tb.Text;
foreach(var question in questions)
{
writeNewQuestionToTblQuestions(question);
}
Try this
int Count = 0;
foreach (Control ctr in Panel1.Controls)
{
if (ctr is TextBox)
Count++;
}
I am looking for a way to loop through controls on a particular tab of a tabcontrol. For example, I have a tabcontrol with the following tabs:
Cars,
Pets,
Admin
On each of these tabs are several controls to display/edit/save data, etc. On the "Save" button, I would like to loop through the controls for that particular tab to check whether all required fields have been filled in.
So, if I am on the Cars tab and click "Save," I want to loop ONLY through the controls on the Cars tab and NOT the Pets or Admin tabs.
How can achieve this result?
As for looping through a TabControl's controls, you need to use the Controls property.
Here's an MSDN article on the TabControl.
Example:
TabPage page = aTabControl.SelectedTab;
var controls = page.Controls;
foreach (var control in controls)
{
//do stuff
}
I feel it's important to note that, in general, you should take a more structured approach to your application. E.g., instead of having all the controls on three tab pages, include exactly one UserControl on each tabpage. A CarUserControl, PetUserControl, and AdminUserControl e.g. Then each user control knows how to create the proper respective data structure so you don't have to manually munge it all together at the same level of abstraction using inter-tab loops and whatnot.
Such a separation of concerns will make it much easier to reason about your program and is good practice for writing maintainable code for your future career.
Example where I wanted to get the DataGridView in a particular tab for an application I wrote.
TabPage pg = tabControl1.SelectedTab;
// Get all the controls here
Control.ControlCollection col = pg.Controls;
// should have only one dgv
foreach (Control myControl in col)
{
if (myControl.ToString() == "System.Windows.Forms.DataGridView")
{
DataGridView tempdgv = (DataGridView)myControl;
tempdgv.SelectAll();
}
}
The Controls property is the way to go...
foreach(Control c in currentTab.Controls)
{
if(c is TextBox)
// check for text change
if(c is CheckBox)
//check for check change
etc...
}
TabControl has a SelectedTab property, so you'd do something like this:
foreach(Control c in tabControl.SelectedTab.Controls)
{
//do checks
}
foreach (Control c in this.tabControl1.SelectedTab.Controls)
{
// Do something
}
I had the need to disable or enable controls of a tab as well. I had to go a bit more generic though. Hope it helps people and I didn't make a mistake
private void toggleControls(Control control, bool state)
{
foreach (Control c in control.Controls)
{
c.Enabled = state;
if (c is Control)
{
toggleControls(c, state);
}
}
}