I'm pretty stuck here and I need help.
I got a lot of text boxes in my form, some visible and some invisible.
I want that Button2 will be active only when all text boxes (that are not hidden) are not empty (At least one character or number)
I saw all kinds of codes, but I could not figure out how to do it. (and it's not working for me)
For example here's a code that I tried, but it did not work out.
bool invalid = this.Controls.OfType<TextBox>()
.Where(t => t.Visible)
.Any(t => string.IsNullOrWhiteSpace(t.Text));
if (invalid)
button2.Enabled = false;
I would also like an explanation if it possible.
Thank you!
Well, I would use this procedure to set the button's availability (imagine there are only three textboxes):
private void SetButton()
{
button2.Enabled = (textBox1.Text != "" || textBox1.Visible == false) && (textBox2.Text != "" || textBox2.Visible == false) && (textBox3.Text != "" || textBox3.Visible == false);
}
For each textbox, it returns a true boolean if the textbox is filled or is invisible. In order to make sure it takes effect immediately, I would double click each textbox on the designer file to get the "textBox(number)_TextChanged" eventhandler, and then call the procedure that I just made. For example:
private void textBox1_TextChanged(object sender, EventArgs e)
{
SetButton();
}
Hope this helps ^_^
A recursive method that iterates over all controls on the form and looks for visible / enabled Textboxes is how I'd do it:
private void AreControlsValid(Control.ControlCollection controls)
{
foreach (Control c in controls)
{
if (c is Textbox && c.Visible)
{
if (String.IsNullOrEmpty(((Textbox)c).Text))
return false;
}
if (c.HasChildren)
AreControlsValid(c.Controls);
}
return true;
}
*Didn't test, this is an adaptation of an answer I posted in another thread: Ability to find WinForm control via the Tag property
edit: Also you'd probably want an generic event that all your textboxes subscribe to along the lines of:
textbox_TextChanged(object sender, EventArgs e)
{
button2.Enabled = AreControlsValid(this.Controls);
}
As Steve mentioned in a comment, the problem with MyForm.Controls is that it only gets direct children controls on your form, it does not get those children's children. So if you have a form, with a groupbox, with textboxes, MyForm.Controls will get you the groupbox and not the textboxes. That's why mine is recursive; it goes all the way down.
Related
This question already has answers here:
How to get ALL child controls of a Windows Forms form of a specific type (Button/Textbox)?
(28 answers)
Closed 2 years ago.
I created a form with multiple panel over it and I use panel control to display relevant information. Third panel have 20 text boxes and I want to check whether all the details are filled. So I simply used this code below.
private void Calculatebutton_Click(object sender, EventArgs e)
{
foreach(Control c in Controls)
{
if(c is TextBox)
{
Console.Beep();
if (!String.IsNullOrWhiteSpace(textbox.Text) &&
!String.IsNullOrEmpty(textbox.Text))
{
SaveToDatabaseButton.Enabled = true;
}
}
}
}
The problem is that the condition in the if statement is getting false, I cannot hear any beep sound or the other button enabled. if I changed from "c is TextBox" to "c is Panel" i can hear the beep sound for three times. I also tried the code like this
if(c is TextBox)
{
c.Text = " ";
}
But nothing works. Please help me to overcome this problem. Thanks in advance.
I tested your code and it entered the beep just fine, consider Ahmed's comments about the text boxes being in another container or form.
Not related to your question directly but, the logic of when to enable the button is incorrect as far as I can tell, because only one of the text boxes being not empty will suffice to enable the button to save to database, I assume you want all text boxes not empty for that to happen.
I would suggest something like this if that's the case:
private void Calculatebutton_Click(object sender, EventArgs e)
{
var isThereEmptyTextBox = false;
foreach(Control c in Controls)
{
if(c is TextBox)
{
Console.Beep();
if (!String.IsNullOrWhiteSpace(textbox.Text) &&
!String.IsNullOrEmpty(textbox.Text))
{
isThereEmptyTextBox = true;
}
}
}
SaveToDatabaseButton.Enabled = !isThereEmptyTextBox;
}
As soon as just one text box is empty that flag will be set to true and will stay that way whether more empty text boxes appear or not, then you use that flag to enable/disable the button.
I am trying to disable the thin and crispy checkbox when traditional checkbox is clicked. I have these in a group due to me enabling the whole group when the numericUpDown value is set to 1. When I click traditional checkbox, it doesn't disable the thin and crispy checkbox. I am using windows form application
Code
private void NudQuantity1_ValueChanged(object sender, EventArgs e)
{
if (NudQuantity1.Value == 0)
{
gbCheesePizza.Enabled = false;
}
else
{
gbCheesePizza.Enabled = true;
}
if (CBXTraditional1.Checked == true)
{
CBXthinandcrispy1.Enabled = false;
}
}
When I run this code outside of a groupbox, it works perfectly.
I don't think this block should be inside the event handler
if (CBXTraditional1.Checked == true)
{
CBXthinandcrispy1.Enabled = false;
}
It means that, provided you've got no other event handling for the checkboxes, this code will only be executed when you change the value of NudQuantity1 so it won't execute anything when you click the checkboxes afterwards.
Try use radio buttons as Steve mentioned. They do this for you.
I'm trying to do a validation wherein if a checkbox has been ticked, the corresponding textbox would no longer be in ReadOnly mode and should not be empty. For example, if I checked CheckBox1, if TextBox1 did not have any input, a MessageBox would pop up to say that "Please fill up the entire form!". Else, it would display "Done!".
This is what I have so far:
if ((CheckBox1.Checked && TextBox1.Text == "")
|| (CheckBox2.Checked && TextBox2.Text == ""))
MessageBox.Show("Please fill up the entire form!");
else if (CheckBox1.Checked && TextBox1.Text != "")
MessageBox.Show("Done!");
else if (CheckBox2.Checked && TextBox2.Text != "")
MessageBox.Show("Done!");
I've made a couple of checkboxes/textboxes that would require this validation and I find that it gets kind of lengthy so I was wondering if there's a simpler/better approach.
(not sure if relevant) Note: I got the toggling the ReadOnly mode when the CheckChanged event is triggered part down
There could be some enhancements for your code, for example:
You can use this criteria !textBox.ReadOnly && string.IsNullOrEmpty(textBox.Text) rather than what you have.
You can avoid using those else if parts and just return from the method if there is a validation error and just put the code after the validation block.
A better solution - Using Validating Event
But I'd rather to change the whole style of validation and use Validating event of those TextBox controls. To do so, you need to follow these instructions:
1) Set AutoValidate property of form to EnableAllowFocusChange in design mode or using code in Load event of form.
2) Handle Validating event of all TextBox controls using single a method and set e.Cancel = true; when there is validation error:
private void textBox_Validating(object sender, CancelEventArgs e)
{
var textBox = (TextBox)sender;
if (!textBox.ReadOnly && string.IsNullOrEmpty(textBox.Text))
e.Cancel = true;
}
3) In the save button of your form, using ValidateChildren method of the form, check if there is any validation error, show a message, otherwise do what the button is supposed to do:
private void button1_Click(object sender, EventArgs e)
{
if (!this.ValidateChildren())
MessageBox.Show("Please correct validation errors.")
else
MessageBox.Show("Done!")
}
Note
To read more about validation options in Windows Forms, take a look at this post:
Validating user input / Give .NET controls status OK or NOK
Also if you want to enhance the user experience by showing a validation error/icon near the control using an ErrorProvider, take a look at this post:
Validation using Validating event and ErrorProvider - Show Error Summary
Now imagine I have ten controls all bound inside a stackpanel.
By default, when TAB is pressed, the focus will move from control 1 subsequently to control 10.
Now what I want is, after focus moving from control 1 to control 2, when the user press TAB again, the focus will go back to control 1. So far I can only mess around with the sequence by using KeyboardNavigation.TabIndex="N" where N = "0,1,2,3,..", but what I ultimately want is skipping the remaining 8 controls.
Please do not suggest TabNavigation="NONE" or IsTabStop="False" to skip the control, I don't want to mess with other controls and yea, I'm fine with hardcode sequence.
Override the preview key down event on the controls that you want to have control over and if its tab then do what you want.
Here is an example if it was something like a textbox you could use something like this. Atach the event handlers either in c# or in the xaml.
btn1.PreviewKeyDown += new KeyEventHandler(btn1_KeyDown);
btn2.PreviewKeyDown += new KeyEventHandler(btn2_KeyDown);
then
private void btn1_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Tab && (Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift)))
{
//do what you want when shift+tab is pressed.
e.Handled = true;
}
else
{
btn2.Focus();
e.Handled = true;
}
}
private void btn2_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Tab && (Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift)))
{
//do what you want when shift+tab is pressed.
e.Handled = true;
}
else
{
btn1.Focus();
e.Handled = true;
}
}
I'm writing a simple application with several controls on a Windows form. I need to monitor the state of buttons (enabled/disabled) according to the state of a textbox and a listbox.
For example, when the listbox is empty, buttons Delete, Delete All and Edit are to be disabled, or when either the textbox or the listbox is empty button Forward is disabled, and so on.
So, I put the change of these properties on Application.Idle event, so it goes something like this:
private void MainForm_Load(object sender, EventArgs e)
{
Application.Idle += new EventHandler(Application_Idle);
}
public void Application_Idle(object sender, EventArgs e)
{
CheckFillingFields(forwardBtn);
CheckFillingList(deleteBtn);
CheckFillingList(deleteAllBtn);
CheckFillingList(editBtn);
}
private void CheckFillingFields(object sender)
{
if (questionTxt.Text == "" || answersLst.Items.Count == 0)
(sender as Button).Enabled = false;
else
(sender as Button).Enabled = true;
}
private void CheckFillingList(object sender)
{
if (answersLst.Items.Count == 0)
(sender as Button).Enabled = false;
else
(sender as Button).Enabled = true;
}
So, the question is - is it acceptable to use Application.Idle in this case? Or should I make these properties dependable on user actions? (For example, when the user deletes an item from the listbox, I should check if it was the last one, and disable the corresponding buttons.)
Thanks a lot in advance, I really appreciate your help!
The simple answer is that, yes, the idle checking is bad and you should re-check the state of your controls on their change events, not "whenever possible".