I have a lot of TextBoxes in my single winform application. I am looking for a way to bind a single event method to all those textboxes when the form loads or in its constructor, so I dont add the event to every single textbox in designer.
In the event, I want to detect the ENTER key and then programmatically click on a button:
private void ApplyFilterOnEnterKey(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
btnApplyFilters_Click(this, null);
}
}
Now the problem is how can I loop over all textboxes in my form and bind them to the above method? My textboxes are everywhere, inside nested tablelayoutpanels or nested normal pannels. How this loop will look like and where should I put it? In form constructor or in load event?!
Instead of subscribing to every TextBox's KeyDown event, you have two other options that I think are better:
Set your button as the default button of the form by setting AcceptButton property of the form to the button you want to be clicked by pressing Enter key.
Override ProcessDialogKey on your form and check for pressing the Enter key:
protected override bool ProcessDialogKey(Keys keyData)
{
if (keyData == Keys.Enter)
{
// ... do what you want
return true;
}
else
return base.ProcessDialogKey(keyData);
}
Just use the Controls collection and look if the control is a textbox then append the event
Loop through all textboxes (including nested) like this as shown here: Loop through Textboxes
Then,
var allTextBoxes = this.GetChildControls<TextBox>();
foreach (TextBox tb in this.GetChildControls<TextBox>())
{
tb.Click += ApplyFilterOnEnterKey;
}
private void TextBoxFocusIn(object sender, EventArgs e)
{
TextBox textBox = (TextBox)sender;
if (textBox.Text == "Encrypted value here...")
{
textBox.Text = "";
textBox.ForeColor = Color.Black;
}
}
private void TextBoxFocusOut(object sender, EventArgs e)
{
TextBox textBox = (TextBox)sender;
if (textBox.Text =="")
{
textBox.Text = "Encrypted value here...";
textBox.ForeColor = Color.Gray;
}
}
private void BindPlaceHolderInTextbox(Panel contentPanel)
{
foreach(Control control in contentPanel.Controls)
{
if(control.GetType() == typeof(TextBox))
{
control.Text = "Encrypted value here...";
control.ForeColor = Color.Gray;
control.GotFocus += new System.EventHandler(TextBoxFocusIn);
control.LostFocus += new System.EventHandler(TextBoxFocusOut);
}
}
}
Related
I'm a newbee to C# and I'm trying to write code in Visual Studio. I need your help.
I want to enter numbers to 20pcs textbox in tabpage1 in form by hand held barcode scanner in C#. Cursor must go to next textbox after reading from barcode scanner. And I will check the read data with some conditions (between 2 values numbers etc) for every textbox.
I write some code but it makes code size big. I think it must be easy way I need your comment and help.
The barcode scanner reads the barcode and sends barcode number + enter code. And barcode scanner read and put number to first textbox then pass to next textbox and it repeating for all textbox - how can I do this easily?
Thanks
private void textBox1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
textBox1.SelectAll();
textBox2.Focus();
e.Handled = true;
}
}
private void textBox2_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
textBox2.SelectAll();
textBox3.Focus();
e.Handled = true;
}
}
.
.
.
.
private void textBox20_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
textBox20.SelectAll();
textBox1.Focus();
e.Handled = true;
}
}
The good news is that the sender object is always that control which has triggered the event. In other words the sender is a reference to one of your TextBoxs.
You can take advantage of this fact and you can have a single event handler, which could be reused for multiple events.
private void textBoxN_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
var textBoxCurrent = sender as TextBox;
textBoxCurrent.SelectAll();
//TODO: set focus for next
e.Handled = true;
}
}
So, the next question is how to get a reference to the next TextBox?
You can use the Tag property for this.
In case of WinForms the Control object has a property called Tag.
In case of WPF the FrameworkElement object has a property called Tag.
In both cases this property is an object so we can store anything in that. If we populate that with a reference to the next TextBox then the generic handler would look like this:
private void textBoxN_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
var textBoxCurrent = sender as TextBox;
textBoxCurrent.SelectAll();
var textBoxNext = textBoxCurrent.Tag as TextBox;
textBoxNext.Focus();
e.Handled = true;
}
}
What's left?
Populate the Tag properties
Subscribe to the KeyDown events
private void Init()
{
var textBoxes = new List<TextBox> { TextBox1, TextBox2, ..., TextBox20 };
foreach(var item in textBoxes.Select((textBox, index) => (textBox, index))
{
var nextIdx = (item.index + 1) % textBoxes.Count;
item.textBox.Tag = textBoxes[nextIdx];
item.textBox.KeyDown += textBoxN_KeyDown;
}
}
We have created an iterator here which is deconstructed into a textbox and an index of this TextBox in the textBoxes collection.
We have calculated the next TextBox index into the nextIdx. Then we have wired up everything.
here is an idea for solving
class Program
{
LinkedList<TextBox> _textBoxes;
ctor()
{
_textBoxes = new LinkedList<TextBox>();
_textBoxes.List.AddLast(textbox1);
_textBoxes.List.AddLast(textbox20);
}
private void textBox_KeyDown_justOneCommonHandle(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
var textboxCurrent = _textBoxes.Current;
// make sure that Value is the sender
textboxCurrent.SelectAll();
_textBoxes.MoveNext();
var textboxNext = _textBoxes.Current;
// check the end of list
textboxNext.Focus();
e.Handled = true;
}
}
}
# Peter Csala, #Ivan Stavenchuk
Thanks for your idea and help. I solved my problem as shown below
I added a main Textbox (textBox21) and used keydown event of main textbox
private void textBox21_KeyDown(object sender, KeyEventArgs e)
{
TextBox tb = new TextBox();
tb.Name = "textBox" + i.ToString();
if (e.KeyCode==Keys.Enter)
{
TextBox tbx = this.Controls.Find(tb.Name, true).FirstOrDefault() as TextBox;
tbx.Text = textBox21.Text ;
i++;
if (i>20) i=1;
textBox21.SelectAll();
}
}
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 have 81 RichTextBoxes in my form (Sudoku Solver), and I would like them to turn gray when user inputs data into them and when there is no data (for example ereased or never was there) to stay white. How do I manage that?
Use an EventHandler!
From MSDN
private void TextChangedEventHandler(object sender, EventArgs e)
{
TextBox tb = sender as TextBox;
if(tb != null){
if(tb.Text.Length > 0){
//set color
}
else{
//set color
}
}
}
...
//Loop through your controls (textboxes) and set handler
foreach(Control c in this.Controls){
if(c is TextBox){
c.TextChanged += TextChangedEventHandler;
}
}
$(".test").on("change keyup paste click", function() {
if(this.val()=="")
{
this.css('background-color', '#ffff00');
}
else
{
this.css('background-color', '#ffff55');
}
})
I have a win app form with 3 text boxes and buttons as dial pad (it's a touchscreen app)...
When a dial pad button is pressed I want to check which one of these 3 text boxes has focus, and append text to it.
Something like:
if (tbx1.Focused == true)
{
tbx1.Text += "0";
}
else if (tbx2.Focused == true)
{
tbx2.Text += "0";
}
else
{
tbx3.Text += "0";
}
But this doesn't work... It appends text to tbx3 all the time.
Any suggestions?
Thanks :)
The problem arises when you click the button, the button will gain focus and not any of your textboxes.
What you can do is subscribe to the LostFocus event and remember what textbox had the focus last.
Something like:
private TextBox lastFocused;
private void load(object sender, EventArgs e){
foreach (TextBox box in new TextBox[] { txtBox1, txtBox2, txtBox3 }){
box.LostFocus += textBoxFocusLost;
}
}
private void textBoxFocusLost(object sender, EventArgs e){
lastFocused = (TextBox)sender;
}
I've got a Windows Forms application in which I have a number of RadioButtons. These RadioButtons are placed within a FlowLayoutPanel which automatically arranges them for me. All RadioButtons that are directly added to the FlowLayoutPanel are grouped, meaning I can select only one of them. However, some of these RadioButtons are paired up with a TextBox so I can supply some argument there. But to have all this arranged properly, I add a Panel control to the FlowLayoutPanel so I can control the alignment of the RadioButton and TextBox relatively to each other myself.
These RadioButtons now have their own respective Panels as parent controls and thus are no longer included in the radio group with the other RadioButtons. I read that the the RadioButtons that are in the System.Web.UI namespace have a GroupName property, but unfortunately their System.Windows.Forms counterparts lack this property. Is there some other way I can group these radio buttons are am I going to have to handle onClick events myself?
Thanks,
Jerry
I'm afraid you'll have to handle this manually... It's not so bad actually, you can probably just store all the RadioButton in a list, and use a single event handler for all of them:
private List<RadioButton> _radioButtonGroup = new List<RadioButton>();
private void radioButton_CheckedChanged(object sender, EventArgs e)
{
RadioButton rb = (RadioButton)sender;
if (rb.Checked)
{
foreach(RadioButton other in _radioButtonGroup)
{
if (other == rb)
{
continue;
}
other.Checked = false;
}
}
}
I agree with #JonH - using tags is the cleanest way to do that (imho)
private void FormLoad(object sender, EventArgs e)
{
radioCsv.Tag = DataTargetTypes.CsvFile;
radioTabbed.Tag = DataTargetTypes.TxtFile;
radioSas.Tag = DataTargetTypes.SasFile;
}
private void RadioButtonCheckedChanged(object sender, EventArgs e)
{
var radio = (RadioButton) sender;
this.DataDestinationType = (DataTargetTypes)radio.Tag;
}
Here is a little improvement over the first answer: create a RadioGroup class that encapsulates the grouping functionality and adds support for standard keyboard navigation (up/down keys) and makes tabbing work.
To use it, simply declare a RadioGroup member in your form and new it (after InitializeComponent()), passing all the radio buttons you want in the group in proper order.
public class RadioGroup
{
List<RadioButton> _radioButtons;
public RadioGroup(params RadioButton[] radioButtons)
{
_radioButtons = new List<RadioButton>(radioButtons);
foreach (RadioButton radioButton in _radioButtons)
{
radioButton.TabStop = false;
radioButton.KeyUp += new KeyEventHandler(radioButton_KeyUp);
radioButton.CheckedChanged += new EventHandler(radioButton_CheckedChanged);
}
_radioButtons[0].TabStop = true;
}
void radioButton_KeyUp(object sender, KeyEventArgs e)
{
e.Handled = true;
RadioButton radioButton = (RadioButton)sender;
int index = _radioButtons.IndexOf(radioButton);
if (e.KeyCode == Keys.Down)
{
index++;
if (index >= _radioButtons.Count)
{
index = 0;
}
e.Handled = true;
}
else if (e.KeyCode == Keys.Up)
{
index--;
if (index < 0)
{
index = _radioButtons.Count - 1;
}
e.Handled = true;
}
radioButton = _radioButtons[index];
radioButton.Focus();
radioButton.Select();
}
void radioButton_CheckedChanged(object sender, EventArgs e)
{
RadioButton currentRadioButton = (RadioButton)sender;
if (currentRadioButton.Checked)
{
foreach (RadioButton radioButton in _radioButtons)
{
if (!radioButton.Equals(currentRadioButton))
{
radioButton.Checked = false;
}
}
}
}
}
One caveat: the up/down keys won't work well with the existing RadioButton class because it already handles the up/down keys. One easy way to fix it to subclass RadioButton and turn off handling of up/down keys:
public class RadioButtonEx : RadioButton
{
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (keyData == Keys.Up || keyData == Keys.Down)
{
return true;
}
return base.ProcessCmdKey(ref msg, keyData);
}
}
#Jerry, I'm not too familiar with Windows Forms, but I will take a shot. If there a property called Tag, you could tag each radio button with a unique tag.