OverView
I have researched out there an I know there is a vast amount of info subscribing multiple event handlers to a single event however, I have not been able to apply it to my scenario. Pretty much I have a bout 30 of these validation event handlers from a textBox, all doing he same process. Below is one of those handlers:
private void txt_HouseName_Validating(object sender, CancelEventArgs e)
{ // Convert User input to TitleCase After focus is lost.
if (Utillity.IsAllLetters(txt_HouseName.Text) | !string.IsNullOrEmpty(txt_HouseName.Text))
{
errorProvider.Clear();
txt_HouseName.Text = Utillity.ToTitle(txt_HouseName.Text);
isValid = true;
}
else
{
errorProvider.SetError(txt_HouseName, "InValid Input, please reType!!");
isValid = false;
//MessageBox.Show("Not Valid");
}
}
How would I minimizes my code to just one of these lines of code and only have one of these event handler?
I know I should attach them within the designer code something similar to this
this.txt_Fax.Validating += new System.ComponentModel.CancelEventHandler(this.txt_Fax_Validating);
But as they are textboxes How would I go about attaching 1 validating events handlers to all of my TextBoxes
You should be using the object sender parameter. as the sender is nothing but the object that called the Event Handler. So, have a global event handler and attach the same handler to all the text boxes. Your Event handler will look something like this.
private void txt_Validating(object sender, CancelEventArgs e)
{ // Convert User input to TitleCase After focus is lost.
//Cast the sender to a textbox so we do not need to use the textbox name directly
TextBox txtBx = (TextBox)sender;
if (Utillity.IsAllLetters(txtBx.Text) | !string.IsNullOrEmpty(txtBx.Text))
{
errorProvider.Clear();
txtBx.Text = Utillity.ToTitle(txtBx.Text);//using the cast TextBox
isValid = true;
}
else
{
errorProvider.SetError(txtBx, "InValid Input, please reType!!");
isValid = false;
//MessageBox.Show("Not Valid");
}
}
Since the object sender parameter is passed with almost every event, it makes it easy to have a common callback for similar events and just check the sender and perform specific operations.
Related
I have a DataGridView with several columns of TextBoxes. I need to capture the event where they are done entering data, and are exiting the box (via Tab, Enter, Mouse click elsewhere, etc)
I have searched SO and Google, and it seems like you have to build an event from scratch. I've tried multiple variations on what I have found since I can't seems to find one that fits with my particular needs.
I've been at this for longer than I care to admit and I need help.
Here is what I have...
// Select DataGridView EditingControlShowing Event
Private void gridData_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e) {
e.Control.TextChanged += new EventHandler(textBox_TextChanged);
Control cntObject = e.Control;
cntObject.TextChanged += textBox_TextChanged;
}
// TextBox TextChanged Event
Private void textBox_TextChanged(object sender, EventArgs e) {
// Checks to see if the AddlQty field was altered
if (gridData.Columns[e.ColumnIndex].Name == "AddlQty") {
// Validate Entry
if (e.Text is Not numeric) {
MessageBox.Show("Entry Not Valid, Only Numeric Values Accepted");
} else {
CalcFinalQty(e.RowIndex);
}
}
}
For the record, the code does NOT work, the validation is quasi code and I'm getting an error in the function heading. The important part for me is the
if (gridData.Columns[e.ColumnIndex].Name == "AddlQty"){ }
I just need help getting to that point.
I have some CheckBoxes created dynamically on code. I do read a barcode using a barcode reader. I'm trying to stop the Unchecked and Checked events from firing when I'm using the barcode. For that effect I:
only assign both events when I get the focus on the Checkboxes, and when I lose the focus I take the events out.
after each Checked and Unchecked event I assign the focus to another control in the window (so the LostFocus event gets triggered)
But went I use the barcode reader, all of the CheckBoxes objects receive the Unchecked event if they were checked (but not the Checked event if they were unchecked).
Is there a way to prevent this from happening?
The only places where the Unchecked method is being used are the ones in the code show, nowhere else in the code of the application.
A pointer to a better way to handle this dynamic creation of Checkboxes will not go unappreciated.
private void SomeMethod ()
{
foreach (KeyValuePair<String, String> kvp in someDictionary)
{
CheckBox checkBox = new CheckBox();
checkBox.Content = kvp.Key;
checkBox.GotFocus +=new RoutedEventHandler(checkBox_GotFocus);
checkBox.LostFocus += new RoutedEventHandler(checkBox_LostFocus);
checkBox.ClickMode = ClickMode.Release;
Grid.SetRow(checkBox, fileSelectionGrid.RowDefinitions.Count);
fileSelectionGrid.Children.Add(checkBox);
RowDefinition row = new RowDefinition();
fileSelectionGrid.RowDefinitions.Add(row);
}
}
void checkBox_LostFocus(object sender, RoutedEventArgs e)
{
CheckBox checkBox = sender as CheckBox;
checkBox.Checked -= new RoutedEventHandler(checkBox_Checked);
checkBox.Unchecked -= new RoutedEventHandler(checkBox_Unchecked);
}
void checkBox_GotFocus(object sender, RoutedEventArgs e)
{
CheckBox checkBox = sender as CheckBox;
checkBox.Checked += new RoutedEventHandler(checkBox_Checked);
checkBox.Unchecked += new RoutedEventHandler(checkBox_Unchecked);
}
EDIT :
Just checked that the click event is not raised when the CheckBox doesn't have the focus.
Usually for such kind of problems i declare a bool flag which is assigned value before and after code line where an event will fire and when that event is fired the first thing it does is to check for that flag value.
For e.g.
bool flag = false;
private void SomeMethod()
{
flag = true;
YourCheckBox.checked = false;
flag = false;
}
void YourCheckBox_Checked(object sender, RoutedEventArgs e)
{
if (flag)
return;
// Do something....
}
void YourCheckBox_UnChecked(object sender, RoutedEventArgs e)
{
if (flag)
return;
// Do something....
}
When i assigned flag = true the next line will fire selection changed event. when i does it will return coz flag is set to true;
Instead of basing on loosing focus, try disabling your event handlers directly before barcode reading and enabling them afterward. Something like this:
public void ReadBarcode(ComboBox cmbx)
{
FieldInfo info = cmbx.GetType().GetField("SelectedIndexChanged", BindingFlags.Instance | BindingFlags.NonPublic);
if (info != null)
{
object obj = info.GetValue(cmbx);
if (obj is EventHandler)
{
EventHandler handler = (EventHandler)obj;
cmbx.SelectedIndexChanged -= handler;
//
// Perform your bar code reading here.
//
cmbx.SelectedIndexChanged += handler;
}
}
}
I have used a single combobox for clarity sake, obviously you can use the same technique for an array of comboboxes
I found a solution. I added event handlers for KeyUp and KeyDown (the barcode input is consider keystrokes) to the control that was receiving the focus with:
e.Handled = true;
and that stopped the checkboxes receiving them.
As per the documentation, it is a Bubbling event. And the control and the checkboxes are cousins
control->grid 1->parent grid
checkbox->grid 2->parent grid
I would not have expected it to go up to the parent grid and then down. I need to read more about WPF.
Seems to me a bit of a hack. If someone gets a better answer, I will mark it.
Is there a way to find out if the "TextChanged" event is fired because
the user is typing into a textbox or
the programmer called myTextBox.Text = "something"?
Just to give you some color on this, I don't want to react when the user is typing each letter into the textbox so I am using the "Validated" event to catch when the user is done so I can react. The problem is I don't have a way to catch when the programmer does "myTextbox.Text = "something". The only way I know to catch changes there is to use TextChanged but then I don't want to be reacting when the user is typing each letter into the textbox. Any suggestions?
So in your "Formatted" Textbox class:
public override String Text{
get{return text;}
set
{
//perform validation/formatting
this.text = formattedValue;
}
this should allow you to format the text when it is changed by a programmer, the user input validation will still need to be handled in the validating event.
I will guess that you're creaing a UserControl that other developers will use, thus "end-user" programmers may set the text programmatically. I think the simplest thing would be to follow #jzworkman's suggestion and make a class that overrides the Text property setter. As #vulkanino notes, you should probably raise and catch the Validating event, though.
public class TextBoxPlus : TextBox {
public event CancelEventHandler ProgrammerChangedText;
protected void OnProgrammerChangedText(CancelEventArgs e) {
CancelEventHandler handler = ProgrammerChangedText;
if (handler != null) { handler(this, e); }
}
public override string Text {
get {
return base.Text;
}
set {
string oldtext = base.Text;
base.Text = value;
CancelEventArgs e = new CancelEventArgs();
OnProgrammerChangedText(e);
if (e.Cancel) base.Text = oldtext;
}
}
}
In your source, add the same handler to both the Validating and ProgrammerChangedText events:
// Somewhere...
textBoxPlus1.Validating += textBoxPlus1_Validating;
textBoxPlus1.ProgrammerChangedText += textBoxPlus1_Validating;
void textBoxPlus1_Validating(object sender, CancelEventArgs e) {
decimal d;
if (!Decimal.TryParse(textBoxPlus1.Text, out d)) {
e.Cancel = true;
}
}
If you want to perform validation, use the Validating event, not the Validated (which comes when it is too late to act).
That said, what's the real need here?
The Validating event is supplied an object of type CancelEventArgs. If
you determine that the control's data is not valid, you can cancel the
Validating event by setting this object's Cancel property to true. If
you do not set the Cancel property, Windows Forms will assume that
validation succeeded for that control, and raise the Validated event.
(http://msdn.microsoft.com/en-us/library/ms229603.aspx)
// This is the manual way, which is an alternative to the first way.
// Type 'this.TextChanged += ' into your form's constructor.
// Then press TAB twice, and you will have a new event handler.
this.TextChanged += new EventHandler(textBox1_TextChanged);
void textBox1_TextChanged(object sender, EventArgs e)
{
//put the logic here for your validation/requirements for validation
// ex. if (textbox1.Text=="something") {//don't validate}
//
}
Heyo,
I have a standard WinForms MonthCalendar in my application with a handler hooked up to the DateChanged event. Whenever I change the date by day, clicking on a certain date in the little calendar, the event fires once. However, whenever I change the date by month, clicking on the < and > in the control, the event fires twice. I want the event to fire once in all situations.
Any ideas?
EDIT: I debugged and found out that the SelectedItem or Range is the same on the first and second handler call. So I need a way to differentiate between the first and second call while still allowing for proper handling when the event only fires once.
The handler code was requested, here it is, but it has nothing to do with the event firing multiple times:
List<TimestampInfo> displayTimestamps = databaseManger.QueryForTimestamps(DayPicker.SelectionRange);
if (displayTimestamps == null) return;
TimestampsListBox.Items.Clear();
TimestampsListBox.Items.AddRange(displayTimestamps.ToArray());
Somewhat of a hack, but compare the SelectionRange string value with the last DataChanged event. Just run your code if it's different:
private string _LastRange = string.Empty;
private void monthCalendar1_DateChanged(object sender, DateRangeEventArgs e) {
if (monthCalendar1.SelectionRange.ToString() != _LastRange) {
_LastRange = monthCalendar1.SelectionRange.ToString();
List<TimestampInfo> displayTimestamps = databaseManger.QueryForTimestamps(DayPicker.SelectionRange);
if (displayTimestamps == null) return;
TimestampsListBox.Items.Clear();
TimestampsListBox.Items.AddRange(displayTimestamps.ToArray());
}
}
I couldn't reproduce this until I hooked up the event handler twice.
monthCalendar1.DateChanged += new System.Windows.Forms.DateRangeEventHandler(this.monthCalendar1_DateChanged);
monthCalendar1.DateChanged += new System.Windows.Forms.DateRangeEventHandler(this.monthCalendar1_DateChanged);
Is you code munging around with the event handlers?
Try this:
private void monthCalendar1_DateChanged(object sender, DateRangeEventArgs e) {
Calendar1.SelectedDate = Calendar1.VisibleDate;
// any additional code optional
}
I am using c# winform.
I have 2dimensional array of text boxes I want them to accept only Letters from A-I I've created the method but that works for only one text box.
Here is my code:
textbox[i,j].Validated+=new EventHandler(TextBox_KeyPress);
private void TextBox_KeyPress(object sender, EventArgs e)
{
bool bTest = txtRegExStringIsValid(textbox[1,1].Text.ToString());
ToolTip tip = new ToolTip();
if (bTest == false)
{
tip.Show("Only A-I", textbox[1,1], 2000);
textbox[1,1].Text = " ";
}
}
private bool txtRegExStringIsValid(string textToValidate)
{
Regex TheRegExpression;
string TheTextToValidate;
string TheRegExTest = #"^[A-I ]+$";
TheTextToValidate = textToValidate;
TheRegExpression = new Regex(TheRegExTest);
if (TheRegExpression.IsMatch(TheTextToValidate))
{
return true;
}
else
{
return false;
}
}
Can anyone please guide what should I do make this code work for all text boxes?
if this works for textbox[1,1] you could register your private void TextBox_KeyPress(object sender, EventArgs e) as eventhandler for all your textboxes and instead of textbox[1,1] you could use ((TextBox)sender)
i want text boxes to accept only letters from a-i actually i am trying to make sudoku
There's a much simpler solution than regular expressions, and you don't even need to handle the Validated event to implement it.
In a situation like this, where there are only certain characters that you want to prevent the user from entering, handling the KeyDown event is a much better solution. The user gets immediate feedback that the letter they tried to enter was not accepted. The alternative (the Validating and Validated events) actually wait until the user tries to leave the textbox to rudely alert them that their input was invalid. Especially for a game, this tends to break concentration and isn't particularly user-friendly.
Doing it this way also makes it irrelevant which individual textbox raised the event. Instead, you will handle it the same way for all of the textboxes—by completely ignoring all invalid input.
Here's what I'd do:
First, attach a handler method to your textbox's KeyDown event. You can do this from the Properties window in the designer, or you can do it through code, as you have in the question:
textbox[i,j].KeyDown += TextBox_KeyDown;
Then, you need to put the logic into your event handler method that determines if the key that the user just pressed is in the allowed range (A through I), or outside of it:
private void TextBox_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
{
// Determine if the keystroke was a letter between A and I
if (e.KeyCode < Keys.A || e.KeyCode > Keys.I)
{
// But allow through the backspace key,
// so they can correct their mistakes!
if (e.KeyCode != Keys.Back)
{
// Now we've caught them! An invalid key was pressed.
// Handle it by beeping at the user, and ignoring the key event.
System.Media.SystemSounds.Beep.Play();
e.SuppressKeyPress = true;
}
}
}
If you want to restrict the user to typing in only one letter, you can add code to handle that in the above method, or you can take an even simpler route and let the textbox control handle it for you automatically. To do that, set the MaxLength property of the textbox to true, either in the designer or through code:
textbox[i,j].MaxLength = true;
Check the text of the sender instead of whatever textbox[1,1] is.
Use the sender parameter of the event handler to identify the textbox responsible for the event.
The first thing that will help you is casting the sender of your event to a TextBox like this:
(Also, as Cody Gray said, this is a TextBox_Validated event, not a KeyPress event so I've renamed it appropriately)
private void TextBox_Validated(object sender, EventArgs e)
{
TextBox tb = sender as TextBox()
if (sender == null)
return;
bool bTest = txtRegExStringIsValid(tb.Text.ToString());
ToolTip tip = new ToolTip();
if (bTest == false) {
tip.Show("Only A-I", tb, 2000);
tb .ext = " ";
}
Next you need to actually get into that code for every textbox. There are two obvious approaches to that, you can either assign the eventhandler to each textbox in the array or you can use a custom textbox which always does this validation and then add that to your array.
Assign eventhandler to textboxes
foreach(var tb in textbox)
{
tb.Validated += new EventHandler(TextBox_KeyPress);
}
Create custom textbox control
Create the custom text box control (Add a user control to the project) and then just use it exactly as you would a normal textbox.
public partial class ValidatingTextBox: TextBox
{
public ValidatingTextBox()
{
InitializeComponent();
}
protected override void OnValidating(CancelEventArgs e)
{
bool bTest = txtRegExStringIsValid(this.Text.ToString());
ToolTip tip = new ToolTip();
if (bTest == false)
{
tip.Show("Only A-I", this, 2000);
this.Text = " ";
}
}
private bool txtRegExStringIsValid(string textToValidate)
{
// Exactly the same validation logic as in the same method on the form
}
}