I got a windows form with around 140 numericUpDown elements and want all of them to do this:
private void numericUpDown_B1_RS_LS_Leave(object sender, EventArgs e)
{
if (numericUpDown_B1_RS_LS.Value < 1 || numericUpDown_B1_RS_LS.Value > 6)
{
numericUpDown_B1_RS_LS.BackColor = Color.Red;
}
else
{
numericUpDown_B1_RS_LS.BackColor = Color.White;
}
}
Is there a more comfortable way of doing this than just adding 140 functions to the form manually?
Assuming you want the same method for all NUDs on your form this will do it:
public Form1()
{
InitializeComponent();
foreach (Control ctl in this.Controls)
if (ctl.GetType() == typeof(NumericUpDown) ) ctl.Leave += numericUpDown_Leave;
}
private void numericUpDown_Leave(object sender, EventArgs e)
{
NumericUpDown NumericUD = (NumericUpDown) sender ;
if (NumericUD.Value < 1 || NumericUD.Value > 6)
{
NumericUD.BackColor = Color.Red;
}
else
{
NumericUD.BackColor = Color.White;
}
}
You can just as easily iterate over the Controls collection of another container, say a Panel or a GroupBox if the NUDs are not directly sitting on the Form. And if some NUDs should be excepted from that behaviour you could mark them in some way, maybe in their Tag or Name and check for that before adding their handlers ..
You should not write multiple functions for same code. Instead you can create just one function and assign it to the event method of your numericUpDown element i.e. "UpDown" event.
So whenever any of the element's "UpDown" event will fire, your same function will be executed. And as far as you want to write different methods for different elements, then consider that in your method
Method(object sender, EventArguments e)
sender is the actual sender object of your updownElement type, and that code will be executed for that particular object only.
You can take for loop to iterate your all 140 elements and assign this function to the "UpDown" element.
maybe you could write a static method to handle the adding of event handler recursively, something like:
private void frmMain_Load(object sender, EventArgs e)
{
AddHandleNumericUpdownLeave(this);
}
public static void AddHandleNumericUpdownLeave(Control theContrl)
{
if (theContrl.Controls != null && theContrl.Controls.Count > 0)
{
foreach (Control cControl in theContrl.Controls)
{
AddHandleNumericUpdownLeave(cControl);
}
}
else
{
NumericUpDown nudCtrl = theContrl as NumericUpDown;
if (nudCtrl != null)
{
nudCtrl.Leave += (object senderT, EventArgs eT) =>
{
var tmpCtrl = senderT as NumericUpDown;
if (tmpCtrl != null)
{
if (tmpCtrl.Value < 1 || tmpCtrl.Value > 6)
{
tmpCtrl.BackColor = Color.Red;
}
else
{
tmpCtrl.BackColor = Color.White;
}
}
}
}
}
}
but this might be costly if you have too many controls in a form...
Related
How can I make button property set to enabled=true after all my textboxes are not empty?
I'm learning programming and my apps are simple.
I know how to enable this property when one of my textboxes have text but this is not the case.
Use case is that user need to put data in both textboxes and after that will be able to click btn.
How in most simple way can I validate all form and then enable button?
There are just 2 tb:
https://i.imgur.com/JUslNWE.png
You need to create a TextBox_TextChanged event and subscribe to all text boxes.
private void TextBox_TextChanged(object sender, EventArgs e)
{
int notEmptyTextBoxCount = 0;
int textBoxCount = 0;
foreach (var item in Controls)
{
if (item is TextBox txtb)
{
textBoxCount++;
if (txtb.Text != String.Empty)
notEmptyTextBoxCount++;
}
}
if (textBoxCount == notEmptyTextBoxCount)
button.Enabled = true;
else
button.Enabled = false;
}
Thanks guys for all feedback.
I have managed to do this this way:
private void ValidateTextBoxes()
{
if (loginTextBox.Text.Length != 0 && passTextBox.Text.Length != 0)
{
generateHashBtn.Enabled = true;
}
else
{
generateHashBtn.Enabled = false;
}
}
private void TextBox1_TextChanged(object sender, EventArgs e)
{
ValidateTextBoxes();
}
private void TextBox2_TextChanged(object sender, EventArgs e)
{
ValidateTextBoxes();
}
I've not touched C# in some time, was trying to help a new programmer friend of mine and became utterly stumped by the following:
private void textBox1_TextChanged(object sender, EventArgs e)
{
activateEnterButton();
TextBox t = (TextBox)sender;
string theText = t.Text;
MessageBox.Show("text: " +theText);
}
private void activateEnterButton()
{
bool allGood = true;
foreach (Control control in Controls )
{
if (control is TextBox)
{
string test = ((TextBox)control).Text;
if (test.Length == 0)
{
MessageBox.Show("text: " +test);
allGood = false;
break;
}
}
}
btnEnter.Enabled = allGood;
}
Our goals is utterly simple: We have 5 textboxes and each needs to have some text in them before a button is enabled. When each has text, button is enabled.
When I walk through the code while debugging everything is called okay but no matter how much text I put in the textbox the activateEnterButton never knows it's there. The two MessageBoxes show different output as well: the one in the activateEnterButton never has any, the one in the event handler always does.
Any assistance would be greatly appreciated. Thank you.
I have removed the calls to the activateEnterButton(), I have put guts of that code inside the event handler for textBox5 but the button is still not being enabled.
The answer I accepted didn't give me the functionality I wanted (entering data into textbox5 would make the button active)the following code gave me all the functionality I wanted. And lastly, the reason for my errors were because A) foreach iterates from the last control to the first, and B) the last textbox control I have on the form is a ReadOnly textbox control, its text is always "", hence I was always getting dumped out of my earlier code. At any rate, new code:
private void checkMe()
{
bool allGood = true;
foreach (Control control in Controls)
{
// Make sure the ReadOnly textbox doesn't cause false
if (control.Name.Equals("ReadOnlyTextBox"))
{
// MessageBox.Show("hidden textbox: " + ((TextBox)control).Text);
allGood = true;
}
else if (control is TextBox)
{
string test = ((TextBox)control).Text;
//MessageBox.Show("test: " + test);
if (test.Length < 1)
{
allGood = false;
// MessageBox.Show("All textboxes need input");
break;
}
else
{
allGood = true;
}
}
}
btnEnter.Enabled = allGood;
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
checkMe();
}
private void textBox2_TextChanged(object sender, EventArgs e)
{
checkMe();
}
private void textBox3_TextChanged(object sender, EventArgs e)
{
checkMe();
}
private void textBox4_TextChanged(object sender, EventArgs e)
{
checkMe();
}
private void textBox5_TextChanged(object sender, EventArgs e)
{
checkMe();
}
In your activateEnterButton() method you looping through the controls and if control is textbox; checking whether it has text or not.
Say if textbox1 has fired the textchanged event; how does that guarantee that other textbox has text in it?
You said in your post The two MessageBoxes show different output as well: .. that should be.
say textbox1 have fired textchanged event and so does in textchanged event you have the text displayed in messagebox but in method activateEnterButton() where you are looping through all controls in form there is no guarantee of order like textbox1 .. 5 (in that order loop will check them) and you are breaking out pf loop once it has no text. So does, in your method you don't see any text in messagebox.
Best way of doing it would be as below (consider that you have TextBox 1..5; have the textchanged on TextBox5 only.)
private void textBox5_TextChanged(object sender, EventArgs e)
{
bool allGood = false;
foreach (Control control in Controls )
{
if (control is TextBox)
{
string test = ((TextBox)control).Text;
if (test.Length > 0)
{
allGood = true;
}
else
{
MessageBox.Show("Fill all textbox first");
break;
}
}
}
btnEnter.Enabled = allGood;
}
Hope this helps.
I'm writing a fairly simple application in which a user can select certain inputs and it processes data. I am having a problem in when a user selects a specific string from one of the combo-boxes, it doesn't disable other controls. Basically when the user selects the combo-box and selects 'Initiate' all other controls should be disabled.
private void cbalpha_SelectedIndexChanged(object sender, EventArgs e)
{
var operatorcheckbox = (CheckBox)sender;
foreach (Control cb in this.Controls)
if ((StringtDataChoiceorSelect.SelectedItem != "(Initiate)")
{
continue;
}
else
{
cb.Enabled = operatorcheckbox.Checked;
}
}
if you want to diable all the controls why are you using checkbox value to enable disable. It should be simply this
private void cbalpha_SelectedIndexChanged(object sender, EventArgs e)
{
bool isEnabled = string.Compare(StringtDataChoiceorSelect.SelectedItem.ToString(),"(Initiate)",StringComparison.OrdinalIgnoreCase) == 0;
foreach (Control cb in this.Controls)
cb.Enabled = !isEnabled ;
}
try
private void cbalpha_SelectedIndexChanged(object sender, EventArgs e)
{
var operatorcheckbox =(CheckBox)sender;
foreach (Control cb in this.Controls)
{
if ((StringtDataChoiceorSelect.SelectedItem != "(Initiate)")
{
if(!cb.Enabled)
{
cb.Enabled = true;
}
}
else
{
cb.Enabled = false;
}
}
}
on SelectedIndexChanged event check if the selected objected is same on which you want to disable other control and then disable it.
protected void ddltext_SelectedIndexChanged(object sender, EventArgs e)
{
if (ddlPerc.SelectedValue.Equals("0.01"))
{
txtbox.Enabled = false;
}
}
I'd use delegates and events for this.
if(operatorcheckbox.Checked &&
StringtDataChoiceorSelect.SelectedItem == "(Initiate)")
{
EventHandler -= checkboxdelegate;
}
else
EventHandler += checkboxdelegate;
You can add a method if there's controls you do not want to keep enabled.
Have a tab page with 2 panels, a data grid view and a 'clear' button.There are only textboxes in the panels and the grid is unbound. Data input is by user. The clear btn is disabled by default. My requirement is to enable it only if any of the textboxes is not empty or there is more than 1 row in the grid. This code isn't working. Please help.
public Form1()
{
InitializeComponent();
foreach (Control c in InvoiceTab.Controls)
{
if (c is DataGridView)
{
DataGridView dgv = c as DataGridView;
if (dgv.RowCount > 1)
{
EnableClearBtnBool = true;
btnClear.Enabled = true;
break;
}
else
{
EnableClearBtnBool = false;
btnClear.Enabled = false;
break;
}
}
}
foreach (Control c1 in panel1.Controls)
{
if (c1 is TextBox)
{
if (c1.Text != "")
{
EnableClearBtnBool = true;
c1.TextChanged -= EnableClearBtn;
c1.TextChanged += EnableClearBtn;
break;
}
else
EnableClearBtnBool = false;
}
}
foreach (Control c2 in panel2.Controls)
{
if (c2 is TextBox)
{
if (c2.Text != "")
{
EnableClearBtnBool = true;
c2.TextChanged -= EnableClearBtn;
c2.TextChanged += EnableClearBtn;
break;
}
else
EnableClearBtnBool = false;
}
}
}
bool EnableClearBtnBool = false;
private void EnableClearBtn(object sender, EventArgs e)
{
if (EnableClearBtnBool == true)
btnClear.Enabled = true;
else
btnClear.Enabled = false;
}
That code is almost certainly not working because of its location first and foremost. However, there are some fundamental changes we should be able to make as well. First we're going to need this code in a method that can be called frequently:
private void RefreshClearButton()
{
btnClear.Enabled = textBox1.Text.Length > 0 ||
textBox2.Text.Length > 0 || ...
dataGridView.RowCount > 1;
}
but, we also need to leverage the TextChanged event on all of the text boxes:
private void textBox_TextChanged(object sender, EventArgs e)
{
RefreshClearButton();
}
so you need to hook all of them up to this event handler. Now, we have two more events we need to consume, on the DataGridView, RowsAdded and RowsRemoved:
private void dataGridView_RowsAdded(object sender, DataGridViewRowsAddedEventArgs e)
{
RefreshClearButton();
}
private void dataGridView_RowsRemoved(object sender, DataGridViewRowsRemovedEventArgs e)
{
RefreshClearButton();
}
and so now we're notified every time something changes. If you must iterate through the panels rather than naming every single text box along the way then you might want to do something like this:
private bool HasTextBeenEntered(ControlCollection controls)
{
foreach (var c in controls)
{
if (c is TextBox && ((TextBox)c).Text.Length > 0) { return true; }
else if (c is Control && HasTextBeenEntered(((Control)c).Controls)) { return true; }
}
return false;
}
which would change the RefreshClearButton method slightly:
private void RefreshClearButton()
{
btnClear.Enabled = HasTextBeenEntered(this.Controls) || dataGridView.RowCount > 1;
}
DISCLAIMER: none of this code is compiled so don't be surprised if you have to tweak it, but it will get you more than 90% of the way.
with a form like this:
I wrote this piece of code to take care of enable/disable logic for moveup/down buttons when they click on at item ( we don't care about Avaiable list on the left, we just care about Selected list on the right)
private void SelectedLV_SelectedIndexChanged(object sender, EventArgs e)
{
// what to do wth move up button
if (SelectedLV.SelectedIndices.Count == 1 && SelectedLV.SelectedItems[0].Index > 0)
{
MoveUpBtn.Enabled = true;
}
else
{
MoveUpBtn.Enabled = false;
}
//what to do with move down button
if (SelectedLV.SelectedIndices.Count == 1 && SelectedLV.SelectedItems[0].Index < SelectedLV.Items.Count - 1)
{
MoveDownBtn.Enabled = true;
}
else
{
MoveDownBtn.Enabled = false;
}
}
I think it works fine for that scenario but my question is what about when we click off of Selected Listview, What is good logic to handle that and Disable Both Moveup/Down buttons?
I don't want them be enabled when we are not inside SelectedListView...
Also if you notice any issue with the code I pasted please let me know.
Thanks
You are about to shoot your foot with the focus requirement. These kind of UI updates are best done with the Application.Idle event, it only runs when nothing important is happening. And can help to eliminate a lot of event handlers. Like this:
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
Application.Idle += Application_Idle;
this.FormClosed += delegate { Application.Idle -= Application_Idle; };
}
void Application_Idle(object sender, EventArgs e) {
bool focusOk = this.ActiveControl == SelectedLV;
bool selectOk = SelectedLV.SelectedIndices.Count == 1;
int index = selectOk ? SelectedLV.SelectedIndices[0] : -1;
MoveUpBtn.Enabled = focusOk && selectOk && index > 0;
MoveDownBtn.Enabled = focusOk && selectOk && index < SelectedLV.Items.Count-1;
}
}
Don't forget to set the focus back in the buttons' Click event handler. And don't forget about the ListView.HideSelection property. Set it to False so that focus doesn't matter anymore.
The problem is once you click on the Move buttons, then you are outside of the SelectedListView control, so the logic should really be based on if you have a correct index value or not:
private void SelectedLV_SelectedIndexChanged(object sender, EventArgs e)
if (SelectedLV.SelectedIndicies.Count == 0) {
MoveUpBtn.Enabled = false;
MoveDownBtn.Enabled = false;
} else {
// normal processing
}