private void txtOctet1_TextChanged(object sender, EventArgs e)
{
double numCheck1;
if (txtOctet1.Text == "")
{
}
else
{
numCheck1 = Convert.ToDouble(txtOctet1.Text);
if (numCheck1 < 0 | numCheck1 > 255)
{
btnSubnetting.Enabled = false;
lblOctet1Error.Text = "Error";
lblOctet1Error.BackColor = Color.Red;
lblOctet1Error.ForeColor = Color.White;
}
else
{
btnSubnetting.Enabled = true;
lblOctet1Error.Text = "No Error";
lblOctet1Error.BackColor = Color.White;
lblOctet1Error.ForeColor = Color.Black;
}
}
}
I have made a decimal to binary converter in C#. This users a class made by me. The user enters their "IP address" in four textboxes (one for each Octet). The above code does work but I don't want to have to repeat the above code for the other third Octet input textboxes. How would I manage this (if it is possible)
Instead of showing you the solution, let's play with VS a bit :
1. Introduce two variables that hold the textbox and label references and replace all use below :
private void txtOctet1_TextChanged(object sender, EventArgs e)
{
double numCheck1;
TextBox txtToValidate = txtOctet1; // Variable 1
Label lblError = lblOctet1Error; // Variable 2
/* Select from here in the next step */
if (txtToValidate.Text == "") // Here, txtOctet1 replaced
{
}
else
{
numCheck1 = Convert.ToDouble(txtToValidate.Text); // Here, txtOctet1 replaced
if (numCheck1 < 0 | numCheck1 > 255)
{
btnSubnetting.Enabled = false;
lblError.Text = "Error"; // Here, lblOctet1Error replaced
lblError.BackColor = Color.Red; // Here, lblOctet1Error replaced
lblError.ForeColor = Color.White; // Here, lblOctet1Error replaced
}
else
{
btnSubnetting.Enabled = true;
lblError.Text = "No Error"; // Here, lblOctet1Error replaced
lblError.BackColor = Color.White; // Here, lblOctet1Error replaced
lblError.ForeColor = Color.Black; // Here, lblOctet1Error replaced
}
}
/* Select to here in the next step */
}
No progress for the moment
2. Select the code you want to reuse
with the mouse or the keyboard, select all code between the two comments place holder I've put. Basically, you should have wrapped up the outermost if/else statement.
3.a Extract to a method
Right click the select code, choose Refactor,Extract to a method.
Choose a name for your method, ValidateOctet for example.
Validate. You should have extracted the logic in a custom method :
private void txtOctet1_TextChanged(object sender, EventArgs e)
{
double numCheck1;
TextBox txtToValidate = txtOctet1; // Variable 1
Label lblError = lblOctet1Error; // Variable 2
ValidateOctet(txtToValidate, lblError);
}
private void ValidateOctet(TextBox txtToValidate, Label lblError)
{
if (txtToValidate.Text == "") // Here, txtOctet1 replaced
{
}
else
{
numCheck1 = Convert.ToDouble(txtToValidate.Text); // Here, txtOctet1 replaced
if (numCheck1 < 0 | numCheck1 > 255)
{
btnSubnetting.Enabled = false;
lblError.Text = "Error"; // Here, lblOctet1Error replaced
lblError.BackColor = Color.Red; // Here, lblOctet1Error replaced
lblError.ForeColor = Color.White; // Here, lblOctet1Error replaced
}
else
{
btnSubnetting.Enabled = true;
lblError.Text = "No Error"; // Here, lblOctet1Error replaced
lblError.BackColor = Color.White; // Here, lblOctet1Error replaced
lblError.ForeColor = Color.Black; // Here, lblOctet1Error replaced
}
}
}
Still no visible progress
3.b (Optionnal) remove useless variable
I choose to simplify the code by removing the variable we created before. I can call the method directly with the textbox and label reference. Choosing to keep the variable or not is a matter of code styling.
private void txtOctet1_TextChanged(object sender, EventArgs e)
{
double numCheck1;
ValidateOctet(txtOctet1, lblOctet1Error);
}
4. Reuse the method for all textboxes
Simply call ValidateOctet for all couple of Textbox/Label :
private void txtOctet1_TextChanged(object sender, EventArgs e)
{
double numCheck1;
ValidateOctet(txtOctet1, lblOctet1Error);
ValidateOctet(txtOctet2, lblOctet2Error);
ValidateOctet(txtOctet3, lblOctet3Error);
ValidateOctet(txtOctet4, lblOctet4Error);
}
Progress: you have now the logic defined in one place
5. Possible optimization
Take a look at other's answer. Some will probably help you.
There is a System.Net.IPAdress class. That provides a set of methods to play with IP Addresses (notably the TryParse method).
Don't know you business requirement, but your code won't support IP V6. We are at the door of (at least) deployment of IP V6. Maybe you should use only one textbox + the IPAddress class to avoid future limitations.
If you intend to have several IP Address fields, you should think about wrapping all the UI and the logic in a reusable UserControl.
Disclaimer
Please not that my answer was not targeted to find the better solution, but help you with using Visual Studio and it's refactoring features. It's quite common to start with simple things, to prototype, or playing a bit before the actual implementation. Refactoring tools allows to simply redesign some parts of your code.
Extract the code into a helper method that is passed the control.
Call this method for each control in turn.
Write a method / function and call it in every TextChange method; you have to pass the TextField as parameter to set color / error.
Create a method that takes in a TextBox and a Label, and call that method once for each set of Textbox/Labels.
(Example to follow)
You can attach the same TextChanged event to all the textboxes. The box which generated the event will be in the sender parameter, so you can get it like this TextBox txtOctet = (TextBox)sender; in the event.
Alternatively you could use just a single textbox which is what we do. This has two advantages. You can also type IPv6 addresses there and validation can be done simply by parsing the address using standard functions. We validate the address like this:
IPAddress address = null;
IPAddress.TryParse(txtIP.Text, out address);
if(address == null)
{
// Set error...
}
Related
so i have an adrduino that sends me data constantly, I made it Json data. so arduino sends me [0,0,0,0] constantly and the 0 changes depending on the condition in the arduino. My Issue is, in my c# im reading this arduino data and i'm using it, however my methods keeps on firing because the conditions are met. i want it to just fire once if the value is changed and that's all. for example if i get from arduino [0,2,0,0] i want it to update and if stays 2 i don't want my method to fire unless it's back to 0 again.
This is my c# code where i read the data
void serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e) {
var str = serial.ReadLine();
outputStr = str;
//intvalue = int.Parse(str);
try{
var json = JSON.Parse(str);
FirstSet = int.Parse(json[0].Value); // can be either 0 or 1
SecondSet = int.Parse(json[1].Value);// can be either 0 or 2
ThirdSet = int.Parse(json[2].Value);// can be either 0 or 3
ForthSet = int.Parse(json[3].Value);// can be either 0 or 4
}catch(Exception ex){
VLog.Info("EXCEPTION!: " + ex.Message);
}
// Set 1
if (FirstSet == 1)
On1();
else if (FirstSet == 0)
Off1();
// Set 2
if (SecondSet == 2)
On2();
else if (SecondSet == 0)
Off2();
// Set 3
if (ThirdSet == 3)
On3();
else if (ThirdSet == 0)
Off3();
// Set 4
if (ForthSet == 4)
On4();
else if (ForthSet == 0)
Off4();
changed = true;
}
some basic validation?
above the class:
private string lastParsed;
inside the class start with:
if (lastParsed != null && lastParsed == str)
{
return;
}
else
{
lastParsed = str;
}
EDIT: looks like you deleted your original code, but if you want to check only one of the int values for each sensor perhaps you could try another approach
above method:
private bool[] sensorState = new bool[4];
I don't remember exactly how you called the On & Off methods but in each IF and ELSE IF you could add
if (first == 0 && sensorState[0]) // it means you should switch OFF and it's currently ON
else if (first == 1 && !sensorState[0]) // it means you should switch ON and it's currently OFF
EDIT:
after each if/else block you update the sensorState
if (first != 0)
sensorState[0] = true;
else
sensorState[0] = false;
and so on..
You probably want to look into Event Handlers. Specifically when properties change. You're already using event handlers for when data is received as a SerialDataReceivedEvent, now you're adding another layer on top of it to handle if the value changes.
The basic concept is you build a class that is responsible for reading your Arduino inputs. Use Task.Run() to monitor on another thread so it doesn't lock your main process. That class will have an event handler in it that you will call from within your monitor class.
When your app instantiates this monitoring object, it will then register an action to that event handler.
This answer lays out a modern version of a class with a PropertyChangedEventHandler. That class should be the monitor that is checking the sensor. Then if the property changes, it will fire the event handler that your main program has registered with.
If I use the example from that answer, here's what your program might look like:
class Program
{
public ISensorMonitor Sensor1 { get; }
public ISensorMonitor Sensor2 { get; }
public ISensorMonitor Sensor3 { get; }
public ISensorMonitor Sensor4 { get; }
static void Main(string[] args)
{
// In this example Sensor1Monitor would implement ISensorMonitor
Sensor1 = new Sensor1Monitor();
Sensor1.PropertyChanged += DoSomethingWithSensor1;
Sensor1.StartMonitoring();
// ... implement the other 3 sensors.
}
void DoSomethingWithSensor1(object sender, PropertyChangedEventArgs e)
{
// This ensures that only the SensorValue property will handled.
if (e.PropertyName != nameof(ISensorMonitor.SensorValue))
return;
// ... Do something with Sensor1.SensorValue
}
// ... implement the other 3 sensors.
}
This will ensure DoSomething() only is called when the value of the monitor's sensor property reading changes.
Consider changing your model first... there is no need to store numbers for an On/Off state, just make your properties bool. Then, if you want to signal changes to the state, just pack it into the property setter instead of trying to be smart in some other area:
class MyContainerIsNotPartOfTheQuestion
{
private bool m_FirstSet;
public bool FirstSet
{
get { return m_FirstSet; }
set
{
if (value != m_FirstSet)
{
m_FirstSet = value;
// handle On/Off where it belongs
if (value) On1();
else Off1();
}
}
}
// same for SecondSet etc.
void serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
// ... your starting code
FirstSet = int.Parse(json[0].Value) != 0;
// set others
// Done, no handling of On/Off here
}
}
I have this function of which works fine however is there and easier way to complete the validation check using the mail address class, and would it be more fitting. Thanks in advance.
TextBox tb = new TextBox();
tb.KeyDown += new KeyEventHandler(txtEmail_KeyDown);
string strRegex = #"^(?("")("".+?(?<!\\)""#)|(([0-9a-z]((\.(?!\.))|[-!#\$%&'\*\+/=\?\^`\{\}\|~\w])*)(?<=[0-9a-z])#))" + #"(?(\[)(\[(\d{1,3}\.){3}\d{1,3}\])|(([0-9a-z][-\w]*[0-9a-z]*\.)+[a-z0-9][\-a-z0-9]{0,22}[a-z0-9]))";
Regex re = new Regex(strRegex); // New regex Object created
// Run Checks after the enter is pressed.
if (e.KeyCode == (Keys.Enter))
{
// checks for is match, if empty and length
if (!re.IsMatch(txtEmail.Text) || (txtEmail.Text.Equals("")) || txtEmail.Text.Length > 100)
{
// display messagebox with error
MessageBox.Show("Email not correct format!!!! ");
}
else
{
MessageBox.Show("Email Format is correct");
}
}
}
you can validate with the EmailAddressAttribute class pretty easily like this in c#
public bool ValidateEmail(string EmailToVerify)
{
if (new EmailAddressAttribute().IsValid(EmailToVerify))
return true;
else
return false;
}
but to use this you need to add this using at the top of your c# code page
using System.ComponentModel.DataAnnotations;
the only downside to this is that EmailAdressAttribute is not so permisive so it depends on what you want to restrict and permit
And if you need it here is the link the the msdn doc about this class :
https://msdn.microsoft.com/fr-fr/library/system.componentmodel.dataannotations.emailaddressattribute(v=vs.110).aspx
No, it is not stable. Since any regular expression of itself represents a finite state machine, it can, in special cases, get into an infinite loop that grafts to the server's DDOS attack.
Just use MailAddress class for validation.
UPDATE 1
After testing MailAddress class and new EmailAddressAttribute().IsValid("MAIL_TEXT_HERE")
I came to conclusion that EmailAddressAttribute's Validation is working better.
You can implement it in this way, let's say that you have TextBox and Button for submit. Just add this Click event handler to buttons Click Event:
private void button1_Click(object sender, EventArgs e)
{
if(!new EmailAddressAttribute().IsValid(textBox1.Text))
{
MessageBox.Show("Email is not valid");
}
else
{
MessageBox.Show("Email is valid");
}
}
I am developing an app in C# which has forms that takes simillar inputs from users at different states.
I need to be able to validate them and for that reason I am using errorproviders
The code is working fine but I notice that with my current knowledge if I wanted to validate multiple forms then I will have to keep copy pasting the validation code for similar forms all over in each of them, I am wondering if there is a simpler way of reusing the validation code by having it in a central location that can be accessed by all of the forms instead of having to code it for each of them.
Below is a snippet of the validation code, in C#
//Methods to verify and user inputs
private bool ValidateName()
{
bool bStatus = true;
if (name.Text == string.Empty)
{
errorProvider2.SetError(name, "");
errorProvider1.SetError(name, "Please Enter Name");
bStatus = false;
}
else
{
errorProvider1.SetError(name, "");
errorProvider2.SetError(name, "Good");
bstatus = true;
}
return bStatus;
}
private void name_Validating(object sender, CancelEventArgs e)
{
ValidateName();
}
What I want to be able to do is have the method ValidateName() defined in such a way that I could just call it in the name_Validating() function of forms which has a textbox called name to validate it.
You'll want something along these lines. Not in front of a project so don't have the precise syntax though. It should point you in the right direction though
//Methods to verify and user inputs
private bool ValidateName(string aName)
{
bool bStatus = true;
// You'll need to fill this bit
// cast or instatiate a textbox here, let's call it txt_box_name
//
// cast : if you pass an object that you know is a textbox
//
// instantiate : you can create an instance of a textbox with Activator.CreateInstance
// more on that here: http://msdn.microsoft.com/en-us/library/system.activator.createinstance%28v=vs.110%29.aspx
//
// and then continue as normal with your generic text box field
if (txt_box_name.Text == string.Empty)
{
// do something
}
else
{
// do something else
}
return bStatus;
}
private void name_Validating(object sender, CancelEventArgs e)
{
ValidateName("name");
// or :
//ValidateName("username");
}
I need a textbox which can contain a maximum of 8 chars which can be achieved by setting
this.textBox1.MaxLength = 8;
However, sometimes my program will pre-enter a few characters (i.e. 6). When presented to the user, I want him to be able to append the missing 2, but not be able to delete the pre-entered 6 characters.
I do not want to have something like
if(!textBox1.Text.Equals(strPreEntered)) throw new Exception(); // Or show a messagebox, or ..
Ideally I would like the Textbox to not accept any backspaces in case textBox1.Length == strPreEntered.Length
What you really want is a flag indicating whether the TextBox has had pre-entered characters sent to it or not. Set it to true whenever you send the pre-entered characters to the TextBox.
Then in the TextBox's OnKeyPress event, ignore the keypress if the KeyCode is a backspace if the flag is set.
public class FormTest : Form
{
public FormTest() : base()
{
LimitedTextBox tb = new LimitedTextBox();
this.Controls.Add(tb);
tb.Text = "123456";
tb.MaxLength = 8;
tb.HasPreenteredText = true;
}
}
public class LimitedTextBox : TextBox
{
private int preenteredTextLength = -1;
private bool hasPreenteredText = false;
public bool HasPreenteredText
{
get { return hasPreenteredText; }
set
{
if (value == true)
{ preenteredTextLength = this.TextLength; }
else
{ preenteredTextLength = -1; }
hasPreenteredText = value;
}
}
protected override void OnKeyPress(KeyPressEventArgs e)
{
if (this.TextLength <= preenteredTextLength && e.KeyChar == '\b')
{ e.Handled = true; } // Causes the KeyPress to be skipped as it was already 'handled'
if (this.SelectionStart < preenteredTextLength) // Prevent user from overwriting/deleting selected text beyond the minimum text length
{ e.Handled = true; }
base.OnKeyPress(e);
}
}
The above code's a little sloppy but you would of course want to clean it up. Maybe have a SetPreenteredText() method that handles setting the boolean value within the LimitedTextBox control and make the boolean private, you don't want to trouble the caller with that sort of thing. The code works as expected though and accomplishes what you seem to want.
I am talking in the context of event handler in a C# windows forms, but I'm assuming the answer could be used anywhere in C#.
To give an example, I have a form that has many check boxes that each activate a button. The CheckedChanged event is handled by a function that is very similar for each CheckBox and it looks something like this right now:
private void acheckbox_CheckedChanged(object sender, EventArgs e)
{
int uniquetocheckbox = 12345;
if(acheckbox.CheckedChanged)
{
ThisFunction(uniquetocheckbox, true);
AssociatedButton.Enabled = true;
}
else
{
ThisFunction(uniquetocheckbox, false);
AssociatedButton.Enabled = false;
}
}
There are a lot of these check boxes and I'm trying to cut and past the code for each and make as few changes as possible so I want to do something like this :
private void acheckbox_CheckedChanged(object sender, EventArgs e)
{
int uniquetocheckbox = 12345;
if((CheckBox)sender.Checked) //CHANGE HERE
{
ThisFunction(uniquetocheckbox, true);
AssociatedButton.Enabled = true;
}
else
{
ThisFunction(uniquetocheckbox, false);
AssociatedButton.Enabled = false;
}
}
This does not work. The easy work around is this :
private void acheckbox_CheckedChanged(object sender, EventArgs e)
{
int uniquetocheckbox = 12345;
CheckBox cb = (CheckBox)sender;
if(cb.Checked) //CHANGE HERE
{
ThisFunction(uniquetocheckbox, true);
AssociatedButton.Enabled = true;
}
else
{
ThisFunction(uniquetocheckbox, false);
AssociatedButton.Enabled = false;
}
}
But out of pure curiosity I am wondering if there is a way to do it in one line like the second example I gave. I would like to know because I think it looks better and is obviously 1 line shorter.
I think you're just missing a set of parenthesis. You want to cast to Checkbox, then get the properties of that:
if (((CheckBox)sender).Checked)
This will force the order of operations to cast first, then get the property from the cast result.
Sure, it's possible. You just missed another set of brackets:
if(((CheckBox)sender).Checked)
However, I wouldn't do this. Why? You don't want to cast again if you want to access the sender as a textbox again if you did it your way.
You can. For example:
object o;
o = new SomeType();
var prop = ((SomeType)o).SomeProperty;
It needs to be this:
if(((CheckBox)sender).Checked) //CHANGE HERE
But personally I like the way you've shown better. That way if it needs to be casted again, it's already been done.
Don't know any C# but ((CheckBox)sender).Checked) should work. In java the "." (member access) has higher priority than casting so putting the parenthesis like this should force the casting to happen first.
You just need a couple of more parenthesis in your if statement:
if (((CheckBox)sender).Checked)
{
...
}