I am trying to validate textboxes for empty values. If the textbox is empty and loses focus, an error has to show and the textbox has to receive focus again.
Reading about this I came across the Validating event, which can be cancelled through e.Cancel. However when I try to do this, I get an error message.
My code:
private void CheckInput(CancelEventArgs e, TextBox tb)
{
ErrorProvider error = new ErrorProvider();
if (!string.IsNullOrEmpty(tb.Text))
{
error.SetError(tb, "*");
e.Cancel = true;
}
else
{
error.SetError(tb, "");
}
}
private void tbTitel_Validated(object sender, CancelEventArgs e)
{
CheckInput(e, tbTitel);
}
And the error I get is the following:
Error 1 No overload for 'tbTitel_Validated' matches delegate 'System.EventHandler'
How can I fix this?
The validating uses this delegate:
private void tbTitel_Validating(object sender, CancelEventArgs e)
{
}
The validated event uses this:
private void tbTitel_Validated(object sender, EventArgs e)
{
}
You want to use the Validating event (you should link you eventhandler to the validating event, not the validated event. This way you can cancel it.
You probably clicked the validating first and copy/paste/selected the eventhandler name into the validated event. (designer)
The error occurs, because tbTitel_Validated doesnt have CancelEventArgs in its signature.
Take a look at this thread for further information:
No overload for 'method' matches delegate 'System.EventHandler'
Conclusion: Use tbTitel_Validating instead.
You should use the Validating event to execute your checks, not the Validated event.
The two events have different signatures. The Validated event receives the simple EventArgs argument, while the Validating event receives the CancelEventArgs argument that could be used to revert the focus switch.
Said that, it seems that your logic is wrong.
// error if string is null or empty
// if (!string.IsNullOrEmpty(tb.Text))
if (string.IsNullOrEmpty(tb.Text))
{
error.SetError(tb, "*");
e.Cancel = true;
}
else
{
error.SetError(tb, "");
}
Alwasy use validation statements at Object.Validated event handler
Likewise:
private void textBox1_Validated(object sender, EventArgs e)
{
if (string.IsNullOrEmpty(textBox1.Text) || textBox1.Text == "")
{
MessageBox.Show("Please use valid data input!!");
}
}
Related
I was wondering about this problem for a while, but couldn't really come up with a solution. I have 2 different event handlers calling each other recursively. As soon as event A is fired, it triggers event B which triggers event A again and so on...
Basically I want to be able to select text in a RichTextBox and show the corresponding font size in a combo box. When I choose a different font size from the ComboBox, I want it's value to be applied to the selected text.
The 2 events are:
1) The selection changed event of text inside a RichTextBox:
private void MyRTB_SelectionChanged(object sender, RoutedEventArgs e)
{
//Get the font size of selected text and select the concurrent size from the ComboBox.
}
2) The selected index changed event of a Combobox:
private void CmbFont_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
//Apply the chosen font size to the currently selected text of the RichTextBox.
}
What would be the best solution to make sure they each only "do their thing" and do not fire the other event in doing so?
Sometimes changing a property of a control in code fires an event unintentionally. Changing the data source of a ListBox or a ComboBox will fire the SelectedIndexChanged event, for example. Use a flag to handle this case
private bool _loading;
...
_loading = true;
// Fill the ComboBox or ListView here
_loading = false;
In the event handler do this
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
if (_loading) return;
...
}
Refactor your code so that A calls DoSomethingA() and B calls DoSomethingB(). This way, if you want A to do the functionality of B you can just call DoSomethingB() and not have any recursive calls.
Just use a bool (maybe called dontFireA) and set it in A just before calling B
notifying properties (used in order to enable binding from WPF to non-WPF properies) use this technique:
public object MyProperty
{
get
{
return myField;
}
set
{
if (value != myField)
{
myField = value;
NotifyProperyChanged("MyProperty"); // raise event
}
}
}
The if (value != myField) condition prevents infinite recursion (stackoverflowexception).
In some cases (e.g. floating point numbers and inaccurate value transfers) if (Math.Abs(value - myField) > someConstant) is used instead to break the recursion.
Could you apply a similar technique to your problem?
If both events are on the same object or the owners have references to each other, you could also store a flag on each e.g.
private void OnEvent()
{
DoSomething();
}
private void DoSomething()
{
this.IsBusy = true;
// do work
// raise event
if (!other.IsBusy)
RaiseEvent();
}
I am going to make the educated guess that you are not raising Event A or Event B yourself; let's say Event A is the TextBox1.TextChanged event and Event B is the TextBox2.TextChanged event, and they have handlers like:
public void Textbox1_TextChanged(object sender, EventArgs e)
{
...
TextBox2.Text = someString;
}
public void Textbox2_TextChanged(object sender, EventArgs e)
{
...
TextBox1.Text = someOtherString;
}
In this case, the handlers are each going to raise the other textbox's TextChanged event by virtue of changing the text, leading to infinite recursion.
The first thing you can do, if you want both to run once and once only, is to mark that they're already running (changing the text of the other textbox results in that textbox's event handler running within the same call stack:
public void Textbox1_TextChanged(object sender, EventArgs e)
{
if(handler1Running) return; //the second time through we exit immediately
handler1Running = true;
...
TextBox2.Text = "Something"; //the other event handler is invoked immediately
handler1Running = false;
}
public void Textbox2_TextChanged(object sender, EventArgs e)
{
if(handler2Running) return; //the second time through we exit immediately
handler2Running = true;
...
TextBox1.Text = "Something Else"; //the other event handler is invoked immediately
handler2Running = false;
}
Now, the deepest it will go is three levels; 1's handler invokes 2's handler which invokes 1's handler again, which sees that 1's handler is already running and quits before doing anything that would deepen the recursion. Same thing if you start by changing TextBox2.
The other thing you can do is make sure you aren't trying to set the textbox to the same value that's already there. Changing from one string reference to another, even if both references are the same string value, will fire the TextChanged event. If the recursion must continue naturally but will reach a steady state, this is actually the first thing to try:
public void Textbox1_TextChanged(object sender, EventArgs e)
{
StringBuilder builder = new StringBuilder();
... //build string
//now, even though the builder's ToString will produce a different reference,
//we're making sure we don't unnecessarily change the text.
if(builder.ToString != TextBox2.Text)
TextBox2.Text = builder.ToString();
}
public void Textbox2_TextChanged(object sender, EventArgs e)
{
StringBuilder builder = new StringBuilder();
... //build string
//now, even though the builder's ToString will produce a different reference,
//we're making sure we don't unnecessarily change the text.
if(builder.ToString != TextBox1.Text)
TextBox1.Text = builder.ToString();
}
I'm not sure if I'm using the wrong terminology so that may be why my searching has not turned up anything.
I have a bunch of text boxes that I want to validate and check that they don’t contain apostrophes. The code that I have is:
public void apostropheCheck(TextBox fieldName)
{
Match m = Regex.Match(fieldName.Text, #"'");
if (m.Success)
{
validationErrorProvider.SetError(fieldName, "Field can not contain apostrophes");
}
else if (!m.Success)
{
validationErrorProvider.SetError(fieldName, "");
}
}
and the validation on the textbox is:
private void FirstNameTextBox_Validating(object sender, System.ComponentModel.CancelEventArgs e)
{
//Checks for apostrophes
apostropheCheck(FirstNameTextBox);
}
However when I run this the value that gets passed to the void is the text that is in the text box (e.g ‘John’ or ‘Mary’) I could get this to work just using the code that’s in the void for each validation event but that would be repeating myself a lot. Is there a better way?
You can have one common handler and use that for all of the textboxes' Validating event.
private void CommonTextBox_Validating(object sender, System.ComponentModel.CancelEventArgs e)
{
//Checks for apostrophes
apostropheCheck((TextBox)sender);
}
The sender object of the event is a TextBox, so you can cast it to a text box and repeat the same event handler for all of the text boxes in your application
private void FirstNameTextBox_Validating(object sender, System.ComponentModel.CancelEventArgs e)
{
apostropheCheck(((TextBox)sender).Text);
}
Terminology: you are referring to your function apostropheCheck as the void which is its return type the standard way is to use the function name apostropheCheck.
All of you text boxes can be validated using the same function if you replace the name of the text box in the code with sender ex.
private void FirstNameTextBox_Validating(object sender,System.ComponentModel.CancelEventArgs e)
{
//Checks for apostrophes
apostropheCheck((TextBox)sender);
}
Getting an error of :
Error 1 'string RadioGroupTester.Form1.chkReceipt_CheckedChanged(object, System.EventArgs)' has the wrong return type
When I compile a very simple program to understand radio and check box controls.
Here's the code for the form is as follows:
private string rdoMastercard_CheckedChanged(object sender, EventArgs e)
{
if (rdoMastercard.Checked)
return "You have selected Mastercard";
else
return "You have selected Visa";
}
private string chkReceipt_CheckedChanged(object sender, EventArgs e)
{
if (chkReceipt.Checked)
return "You will receive a receipt";
else
return "You will not receive a receipt";
}
private string chkRecurring_CheckedChanged(object sender, EventArgs e)
{
if (chkRecurring.Checked)
{
return "You will be charged monthly";
}
else
return "This is a one time payment";
}
And here's what the form looks like:
What am I doing wrong here? I apologize, but I'm still pretty new to C# and VS 2010.
Thanks,
Ray
You can't return things from an event handler. Do you mean to show a message box instead? Or give feedback through a label? It would be something like:
private string void rdoMastercard_CheckedChanged(object sender, EventArgs e)
{
if (rdoMastercard.Checked)
return MessageBox.Show("You have selected Mastercard");
else
return MessageBox.Show("You have selected Visa");
}
and the same for your other examples. This example uses a message box but you can set a Label's text or whatever.
The reason? How do you expect C# to know what you want to do when you're returning something from an event handler? An event handler handles events, nothing more.
Edit: So for what you want to do, it would be something like:
private void btnConfirmChoices_Click(object sender, EventArgs e) {
string str = string.Empty;
if(rdoMastercard.Checked)
str += "You have selected Mastercard\n";
else
str += "You have selected Visa\n";
if (chkReceipt.Checked)
str += "You will receive a receipt\n";
else
str += "You will not receive a receipt\n";
if (chkRecurring.Checked)
str += "You will be charged monthly";
else
str += "This is a one time payment";
MessageBox.Show(str);
}
Not sure how you got in this pickle, you are seemingly guessing that returning a string from the CheckedChanged event handler is useful. No such use has been intended in the design, the declaration for the RadioButton.CheckedChanged event handler is:
public event EventHandler CheckedChanged;
Which makes the declaration of the EventHandler delegate type relevant:
public delegate void EventHandler(object sender, EventArgs e);
Which defines exactly what your event handler should look like. It has to be a method that returns void and takes two argument, one of type object and one of type EventArgs. Which is what you get when you double-click the radio button in the designer:
private void radioButton1_CheckedChanged(object sender, EventArgs e) {
}
Note how the auto-generated method exactly matches the signature of the delegate type. The compiler is happy. What it won't be happy about is you changing the signature of your event handler. The Winforms code was pre-programmed to call your CheckedChanged event handler and it is hoping that you implemented the way it was pre-programmed. What it cannot do is deal with a different return type. It doesn't know what to do with it. What is it supposed to do with it? Do you want to log it? Do you want to change the Text property of the radio button? Do you want to send it across the Internet to another machine?
These things are certainly possible. But you have to write that code, Winforms cannot guess for you what you want to use it for.
The buck stops there, your time to take charge.
I have a textbox and in some cases in Enter event I need to set the focus to a different textbox.
I tried that code:
private void TextBox1_Enter(object sender, EventArgs e)
{
if(_skipTextBox1) TextBox2.Focus();
}
But this code doesn't work. After that I found on MSDN:
Do not attempt to set focus from within the Enter, GotFocus, Leave, LostFocus, Validating, or Validated event handlers.
So how can I do it other way?
Postpone executing the Focus() method until after the event is finished executing. Elegantly done by using the Control.BeginInvoke() method. Like this:
private void textBox2_Enter(object sender, EventArgs e) {
this.BeginInvoke((MethodInvoker)delegate { textBox3.Focus(); });
}
You could handle the KeyPress event instead:
private void TextBox1_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == (char)Keys.Return)
{
e.Handled = true;
TextBox2.Focus();
}
}
textBox.Select();
or
textBox.Focus();
or
set TabIndex = 0 from properties of that textBox.
both methods are use to set focus on textBox in C#, .NET
I'm a beginner with C# and I'm developing a basic application.
I want to check if the value of a textbox is a number with the following code :
private void check_value(object sender)
{
TextBox tb = (TextBox)sender ;
if (!Utility.isNumeric(tb.Text)){
MessageBox.Show(tb.Text.Length.ToString());
tb.Focus();
}
}
private void Amount_1_LostFocus(object sender, RoutedEventArgs e)
{
check_value(sender);
}
When I enter a letter in the textbox there is an infinite loop and it seems that the tb.Focus() actually cause the LostFocus event to be call recursively.
I don't understand why the call to the Focus method of an object triggers the LostFocus event of the same object.
Opening the modal MessageBox is responsible for loosing the focus. Try hook to Validating event.
As i said before in the link provided by Xaqron it's said that it's forbidden to use the Focus method in the LostFocus event.
And as I'm developing a WPF application there is no Validating event and CausesValidation property, so the others ways to validate the content is to use the TextChanged event or use binding validation.
Thank you for your answers.
Of course, in a perfectly valid program, you should not change Focus in the LostFocus event. This also applies to the Enter, GotFocus, Leave, Validating and Validated events, which Ms makes clear in the documentation https://learn.microsoft.com/pl-pl/dotnet/api/system.windows.forms.control.lostfocus.
However, in very unusual cases, you can use the timer to trigger changes to the Focus, bypassing this problem.
private TextBox tb = null;
private System.Windows.Forms.Timer MyTimer;
private void initialize()
{
MyTimer.Tick += new System.EventHandler(MyTimer_Tick);
MyTimer.Enable = false;
MyTimer.Interval = 100;
}
private void check_value(object sender)
{
tb = (TextBox)sender ;
if (!Utility.isNumeric(tb.Text)){
MessageBox.Show(tb.Text.Length.ToString());
MyTimer.Enable = true;
}
}
private void Amount_1_LostFocus(object sender, RoutedEventArgs e)
{
check_value(sender);
}
private void MyTimer_Tick(object sender, EventArgs e)
{
MyTimer.Enabled = false;
if (tb!=null) tb.Focus();
}