I have few text boxes that should allow a certain format, but when a user enters it in a wrong format in a textbox, I would like to catch the control name and clear the text of the textbox.
Clearing the user input because it's not in a given format is very user-unfriendly. What if only one of ten characters was wrong? They'd have to type it all over again. Just use a MaskedTextBox with a Mask for the pattern you expect.
When using a MaskedTextBox, you can subscribe to the MaskInputRejected event as described here:
public void Form1_Load(Object sender, EventArgs e)
{
... // Other initialization code
maskedTextBox1.Mask = "00/00/0000";
maskedTextBox1.MaskInputRejected += new MaskInputRejectedEventHandler(maskedTextBox1_MaskInputRejected)
}
void maskedTextBox1_MaskInputRejected(object sender, MaskInputRejectedEventArgs e)
{
toolTip1.ToolTipTitle = "Invalid Input";
toolTip1.Show("We're sorry, but only digits (0-9) are allowed in dates.", maskedTextBox1, maskedTextBox1.Location, 5000);
}
Throwing exceptions for expected behaviour is never right as they are very expensive. If you need to see where the exception originated just check the top line of the stack trace.
debug only
you can get control name in debug mode from the yourForm.cs . i dont think this code will run on relese cuz. the source file wont be in ther release right?
using System.Diagnostics;
public void ParseControlText()
{
try
{
var doubleval = Double.Parse(tb_double.Text);
var intval = Int32.Parse(tb_int.Text);
//... bunch of controls need to be parssed to calculate something
}
catch (FormatException ex)
{
var stlast = new StackTrace(ex,true).GetFrames().Last();
//this requires form.cs to exist . how am i gonna do this in release? idk
var stLine = File.ReadLines(stlast.GetFileName())
.ToList()[stlast.GetFileLineNumber()-1];
var m = Regex.Match(stLine ,#"\((.*?)\..*?\)");
var ctrlname = m.Groups[1].Value;
MessageBox.Show( ctrlname + " control's text coundnt be Parsed! " );
}
}
Related
I can't figure out how to get the try catch to work. Need to have an error message box pop up when a non number is entered in the text boxes.
private void btnAdd_Click(object sender, EventArgs e)
{
int x = int.Parse(txtIn1.Text);
int y = int.Parse(txtIn2.Text);
txtIn1.Text = x.ToString();
txtIn2.Text = y.ToString();
lstOut.Items.Add((x + y).ToString("N0"));
try
{
int.Parse(txtIn1.Text);
int.Parse(txtIn2.Text);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
return;
}
With minimal modifications: move all the code into the try so it catches when any Exception is hit. You're encountering your exception outside of the try block. You are only going to ever see your catch triggered if something within the corresponding try block is throw an exception.
private void btnAdd_Click(object sender, EventArgs e) {
try {
int x = int.Parse(txtIn1.Text);
int y = int.Parse(txtIn2.Text);
txtIn1.Text = x.ToString();
txtIn2.Text = y.ToString();
lstOut.Items.Add((x + y).ToString("N0"));
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
return;
}
}
Edit: As suggested by commenters, I think this answer is incomplete without stating that a Try/Catch block is overkill in this instance.
A better approach would be to use the built-in TryParse method (which can return a boolean regarding the success of the parse attempt, and an output value). Here is one way you could accomplish this:
private void btnAdd_Click(object sender, EventArgs e) {
var xSuccess = int.TryParse(txtIn1.Text, out int x);
var ySuccess = int.TryParse(txtIn2.Text, out int y);
if(!xSuccess)
MessageBox.Show($"{x} could not be parsed to int!");
if(!ySuccess)
MessageBox.Show($"{y} could not be parsed to int!");
if(xSuccess && ySuccess)
lstOut.Items.Add((x + y).ToString("N0"));
}
You shouldn't use try-catch as a control block as explained in this SO post. Use if for that. Try catch is really meant to be used when you can't do otherwise or when something that you didn't expect happened.
You can use this SO post as an example and your code could look like this
private void btnAdd_Click(object sender, EventArgs e)
{
int x;
int y;
if(!int.TryParse(txtIn1.Text, out x) || !int.TryParse(txtIn2.Text, out y))
MessageBox.Show("Parse failed !");
}
You can use
Console.WriteLine(x);
Console.WriteLine(y);
to verify that the vars were properly given a value
For more information about the int.TryParse() method vs int.Parse() see this post
As other have mentioned, it's the first int.Parse() functions that are tripping things up - the ones outside the Try/Catch block.
I wanted to expand on the TryParse() function - and why should probably be using that.
Exceptions are expensive - they're a rather large overhead in terms of Time/CPU/etc. They're also not user-friendly. You want to say "Please enter a valid number" to the user, not "An exception occurred: ..."
Instead, you can use TryParse, which returns whether the parsing worked; the output of the parse is an "out" parameter in the inputs list:
int myValue;
bool parseWorked = int.TryParse("3", out myValue);
This doesn't have the Exception overhead - it runs quickly, regardless of whether the input's valid.
Why not use a different approach?
Use the TextBox.KeyPress event:
private void txtIn1_KeyPress(object sender, KeyPressEventArgs e)
{
if (!char.IsDigit(e.KeyChar) /* || add more conditions*/)
e.Handled = true; // Prevent key to be added to the TextBox' text.
}
Now you don't have to check if there are non-numbers in your string.
Your statement int.Parse(txtIn1.Text); will surely work.
Good day fellow helpers, i have following problem:
(running MS Visual Community Edition 2015)
private void button4_Click(object sender, EventArgs e) // Senden
{
serialPort2.WriteLine("SR,00,002\r\n");
textBox1.Text = "gesendet";
textBox3.Text = "";
try
{
System.IO.StreamReader file = new System.IO.StreamReader("C:\\blub.txt");
String line = file.ReadToEnd();
string Hallo = line; \\in the beginning there is "0" in the file
file.Close();
decimal counter = Convert.ToDecimal(Hallo); \\just for testing
counter++;
string b = serialPort2.ReadLine();
string[] b1 = Regex.Split(b, "SR,00,002,"); \\cuts off unwanted input from device
decimal b2 = decimal.Parse(b1[1]); \\number like -3000
System.IO.StreamWriter test = new System.IO.StreamWriter("C:\\blub.txt");
test.WriteLine(counter);
test.Close();
textBox7.Text = "Das ist counter:" + counter;
}
catch (TimeoutException)
{
textBox3.Text = "Timeout";
throw;
}
}
Now, the Serialport is a device that returns a lengthmeasurment. As it is a bit weird, or just the way its build it start with a negitve number (between -5000 and -3370). Now as i want to get measurement on the screen that is realistic i want to set the value to 0 and calculate the difference.
Means: I start the programm - press send - get a value (say -3000) - press send again (after pushing the seonsor in) and get the value that its been pushed in > 0 by adding the difference to 0.
I only learned to store values externally when i had a C course a year back like i did within my programm. Is there a way to store the value from the first measurement in the programm so i can use it on the next send/try?
The counter was just for testing and I would exchange it for the "decimal b2"
I hope there is an easy fix for that, not really a pro with C# yet but i'm eager to learn. I thank the willing helpers in advance, MfG, Chris
OK, I will simplify this in order to show concept so it will not have all the code you are actually using.
So, what you want is to click on button, get some values and store them for next click.
Value is stored in variable. If you have variable in function that is handler for click event, as soon as function completes execution, value will be destroyed.
So, what you need is to create variable in outer scope (class level). Your function is already in class of the form so let's get to code:
class Form1
{
string BetweenClickStorage;
private void button4_Click(object sender, EventArgs e)
{
//Load data here
BetweenClickStorage = LoadedData;
}
}
After this, when you click again on the button, value will still be in BetweenClickStorage. It will be also available to all other buttons click handlers and other code in that form.
If I'm understanding your question correctly, the answer is simply to declare a variable outside the try/catch:
//declare variable //
var measurement;
// TRY #1 //
try
{
//assign value to the variable here
}
catch
{
}
// TRY #2 //
try
{
// reference variable here
}
catch
{
}
i am an engineering student and i am currently working on my final year project. i am trying to build a rfid-based parking lot management system in C#. based on some research i have written the following code to read data from rfid reader but i am facing this problem. the event handler
which i use to read the received data fires twice, which i don't understand how...i did some research on the internet and found many people are facing similar problem of an event handler firing twice but most of them are button-click events. i could only find a few threads on custom event handler but those solutions don't seem to work in my project. any possible solutions to this problem?
private void Parking_layout_Load(object sender, EventArgs e)
{
foreach (string port in System.IO.Ports.SerialPort.GetPortNames())
{
comboBox1.Items.Add(port);
if (comboBox1.Items.Count > 0)
comboBox1.SelectedIndex = comboBox1.Items.Count - 1;
}
RFID = new SerialPort();
RFID.PortName = comboBox1.Text;
RFID.BaudRate = 9600;
RFID.DataBits = 8;
RFID.Parity = Parity.None;
RFID.StopBits = StopBits.One;
RFID.Open();
RFID.DataReceived += new SerialDataReceivedEventHandler(RFID_DataReceived);
}
private void RFID_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
try
{
tag_id = RFID.ReadExisting().ToString();
SetLabel(tag_id);
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
the RFID_DataReceived executes twice. if i put a messageBox.show() statement to test it, it shows the message twice. how do i fix this problem?
Set a break point on the RFID_DataReceived method in order to see why it is firing twice. You can then take a look at the stack window to see the stack trace of the code.
You can also do the same for the original method Parking_layout_Load to see if perhaps it is being called more then once from another piece of code. You can also place code inside the function in order for the stacktrace to be written to the output window.
private void RFID_DataReceived(object sender, SerialDataReceivedEventArgs e)
{ Debug.WriteLine("StackTrace: '{0}'", Environment.StackTrace);
try
{
tag_id = RFID.ReadExisting().ToString();
SetLabel(tag_id);
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
For even more detail then use the stacktrace class as in this example : StackTrace Class
Environment.StackTrace Property
How to: Use the Call Stack Window
What is the incoming data? Looking at your code, I notice you have the line
RFID.DataBits = 8;
In .NET, a char is 2 bytes. If you are reading a character from your device, then it would in fact need to call your event handler twice to process all 16 bits. Can you change the value to 16?
I have a simple application that reverses any text typed to it in another textbox. The catch is, you can modify either textbox and the changes will be (literally) reflected in the other.
I wrote this code, believing for it to cause problems.
private void realText_TextChanged(object sender, EventArgs e)
{
mirrorText.Text = mirror(realText.Text);
}
private void mirrorText_TextChanged(object sender, EventArgs e)
{
realText.Text = mirror(mirrorText.Text);
}
private string mirror(string text)
{
return new string(text.Reverse().ToArray()).Replace("\n\r", "\r\n");
}
I then tried it out, believing that it would cause an infinite loop (realText changes mirrorText, another event happens, mirrorText changes realText, etc). However, nothing except the intended behavior happened.
I'm of course happy about this, I could just leave it here. Or could I?
I'm quite sure the TextChanged event is supposed to be fired whenever Text is changed. Is this intended behavior of some error protection in the events, or was I just lucky? Can this code misbehave on another computer, with other build settings, etc? It can be easily fixed:
private void realText_TextChanged(object sender, EventArgs e)
{
if (realText.Focused)
{
mirrorText.Text = Mirror(realText.Text);
}
}
I'll probably do it anyway to be safe, but is it required to check this? (I'm not even going to ask if it's recommended.)
Per the comments, and as already answered, the TextChanged event is not getting raised when you set the Text property to the value it already has.
It's not clear whether this is something you can safely rely upon. It is a sensible optimisation, and I would be very surprised if future versions of .NET Framework drop it, but I cannot speak for older versions, nor for third-party implementations (Mono).
To be absolutely safe, I would not use the Focused check you put in your question. I would do exactly what the Text setter does now.
private void realText_TextChanged(object sender, EventArgs e)
{
var newMirrorText = Mirror(realText.Text);
if (mirrorText.Text != newMirrorText)
mirrorText.Text = newMirrorText;
}
This has the same advantage of preventing infinite recursion, but plays more nicely with other code you may put in your form that changes the text as a result of some other event.
The reason it doesn't cause a loop is that it checks whether the Text property actually changed, i.e. if the new value does not equal the old value. In your case the mirror function happens to reverse itself, which leads to the same text after two passes.
It's pretty easy to check.
First, replace both textbox controls with
class T : TextBox
{
public override string Text
{
get
{
return base.Text;
}
set
{
base.Text = value;
}
}
}
Second, set the breakpoint on setter. Add these expressions to the Watch window:
Name
Text
value
Third, launch the app, copy '123' from somewhere and paste it to the first textbox. Here it goes:
1st break:
Name: "mirrorText"
Text: ""
value: "321"
2nd break:
Name: "realText"
Text: "123"
value: "123"
3rd... whoops, it does not breaks anymore. To detect why we had to go deeper. Look at referencesource: text box setter does nothing unusual, but TextBoxBase's one looks interesting:
set {
if (value != base.Text) { // Gotcha!
base.Text = value;
if (IsHandleCreated) {
// clear the modified flag
SendMessage(NativeMethods.EM_SETMODIFY, 0, 0);
}
}
}
So, as hvd already answered, the reason is the textbox does not raise TextChanged if old and new values are the same. I don't think the behavior will change, at least for winforms. But if you want more robust solution, here it is:
private void RunOnce(ref bool flag, Action callback)
{
if (!flag)
{
try
{
flag = true;
callback();
}
finally
{
flag = false;
}
}
}
private bool inMirror;
private void realText_TextChanged(object sender, EventArgs e)
{
RunOnce(ref inMirror, () =>
{
mirrorText.Text = mirror(realText.Text);
});
}
private void mirrorText_TextChanged(object sender, EventArgs e)
{
RunOnce(ref inMirror, () =>
{
realText.Text = mirror(mirrorText.Text);
});
}
private string mirror(string text)
{
return new string(text.Reverse().ToArray()).Replace("\n\r", "\r\n");
}
P.S. mirror() will fail on surrogate pairs. Here're some solutions.
If textbox has a Text, and we try to change it with the same Text, the TextChange event is not raising because new text is same as the previous.
In your code, the realText_TextChanged event reverses the text and changes the mirrorText with it.
The mirrorText_TextChanged event reverses the text and try to change the realText.
The realText has already this text and does not raises the realText_TextChanged event.
I have written a little program. It works almost as I want, I just have one problem. I am trying to copy all functions I have found in the other program.
I have a TextBox, when the user can write a phone number. Firstly, he is only allowed to use digits and "+"and "-", so I use:
private void textBoxPhoneNumber_KeyPress(object sender, KeyPressEventArgs e)
{
if ((char.IsDigit(e.KeyChar) == false) && (e.KeyChar != '+') && (e.KeyChar != '-') && (e.KeyChar != '\b')) e.Handled = true;
}
Then I want the phone number to be in certain format (+12-34-1234567), so I use:
private bool IsPhoneNumberCorrect(string name)
{
return Regex.IsMatch(name, #"^+\+[0-9]{2}-[0-9]{2}-[0-9]{7}$", RegexOptions.None);
}
and finally this (with TextChange):
private void phoneNumberValidity(object sender, EventArgs e)
{
counter4 = Convert.ToInt32(IsPhoneNumberCorrect(textBoxPhoneNumber.Text));
pictureBoxPhoneNumber.Image = imageList1.Images[counter4];
checkIfOk();
textBoxPhoneNumber.Focus();
}
I use counter4 as a part of method (checkIfOk) that enables button. There is also an "X" icon that changes into "tick" when the number is given in proper format.
It works perfectly for me (just like in the program I am copying) - when the user writes something in the TextBox, he can only use digits and "+" and "-" and when the format is ok the icon changes and when other textboxes are also ok, the Ok buton enables.
Now, finally, the problem:
I am able to paste something from the Clipboard. In the original program, when I paste something with letters, digits and other signs, only digits and "+" and "-" remains. My program accepts everything in such situation.
I've been looking for something that might be helpful, but all I have found was very complicated. Is there a way to do it?
I tried to do something like this. It causes that when pasting only digits and "+" and "-" remains as it should, but the user can't write anything.
I am still a beginner. Maybe I am making a simple mistake?
private void phoneNumberValidity(object sender, EventArgs e)
{
Regex regex = new Regex("[^0-9-+]");
if (regex.IsMatch(Clipboard.GetText()))
{
counter4 = Convert.ToInt32(IsPhoneNumberCorrect(textBoxPhoneNumber.Text));
pictureBoxPhoneNumber.Image = imageList1.Images[counter4];
string output = regex.Replace(Clipboard.GetText(), "");
textBoxPhoneNumber.Text = output;
checkIfOk();
textBoxPhoneNumber.Focus();
}
}
I am trying to do something like this:
private void phoneNumberValidity(object sender, EventArgs e)
{
counter4 = Convert.ToInt32(IsPhoneNumberCorrect(textBoxPhoneNumber.Text));
pictureBoxPhoneNumber.Image = imageList1.Images[counter4];
checkIfOk();
textBoxPhoneNumber.Focus();
Regex regex = new Regex("[^0-9-+]");
if (textBoxPhoneNumber.Text.Contains("a"))
{
if (regex.IsMatch(Clipboard.GetText()))
{
string output = regex.Replace(Clipboard.GetText(), "");
textBoxPhoneNumber.Text = output;
}
}
}
I know that it's not exactly what I want, but maybe someone can give some clues...
Generally i thought, that I'd like to check if the text in tb contains some unwanted elements, but I don't know how to check it. As you can see, it checks only one unwanted element.
First of all, please use TRY-Catch for the Convert.ToInt32 !
Second: Use TextChanged event, and validate the input with the actual content of the TextBox
To validate, you can do something similar:
string output = ""
string clipboardText = GetClipboardText()
for each chara in clipboardText's characters
if chara.isNumeric or chara=='+' or chara == '-'
output += chara
end foreach
Of course its just a simple soultion, but you can confgure it as you want.
Or if you want more complex way, you can play with the regex... Start with number or + - BUT not contains alphabetical char. Based on your request.
This is what I made, and it works :) I will only add try-catch block as Krekkon has suggested.
private void phoneNumberValidity(object sender, EventArgs e)
{
counter4 = Convert.ToInt32(IsPhoneNumberCorrect(textBoxPhoneNumber.Text));
pictureBoxPhoneNumber.Image = imageList1.Images[counter4];
if (Regex.IsMatch(textBoxPhoneNumber.Text, "[^0-9-+]"))
{
Regex regex = new Regex("[^0-9-+]");
string output = regex.Replace(Clipboard.GetText(), "");
textBoxPhoneNumber.Text = output;
}
checkIfOk();
textBoxPhoneNumber.Focus();
}
Maybe it will help someone in the future.
Maybe you should try like this: leave the first version of phoneNumberValidity method as it is and then check if the tb Text has some unwanted elements, get rid of them.