private void serialPort_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
if (Clos_flag) return;
try
{
Listening = true;
if (serialPort.IsOpen)
{
this.txt_weight.Invoke(new MethodInvoker(delegate
{
//txt_weight.Text = serialPort.ReadLine();
serialPort.NewLine = "\r";
string weight = serialPort.ReadLine();
if (weight.IndexOf(")") > 0)
{
weight = weight.Substring(3, 8);
// txt_weight.Text = weight.Substring(0, weight.LastIndexOf("0") + 1);
}
}));
}
}
catch (Exception eg)
{
MessageBox.Show(eg.ToString());
}
finally
{
Listening = false;
}
}
What should i change to remove the first zero in the picture, above is the code i use. I tried to change the substring to (2,8) but still it is not working.
I get the value from a weighing machine, once the user click the "Open Serial Port" button
Change this line:
string weight = serialPort.ReadLine();
to this:
string weight = serialPort.ReadLine().TrimStart('0').Trim();
What that will do is readline, trim the first 0, then trim the outside (start amd end) blank spaces before loading the value into the declared variable
Seems like this could be caused by many factors.
Looking at the code, the leading zero should be stripped out, since you already substring out the first two char.
I see that your function serialPort_DataReceived reads the data from a device in your port, so I presume your screen shot is from the output device.
Try and hard code
weight = "12345";
If the problem still persists, it would be caused not by the code, but by your device, etc..
Hope this helps~
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
Edit add: The problem I was given amounts to making use of a text file that contains 18 differing account numbers. I'm given the option of making the program read it to an array or a List<>. Then the program should allow a user to input a number and determine if it matches an entity in the array/List<>, displaying that it's valid/invalid.
It took me a fair while to get my code to work correctly. Now, I don't mind that a bad input validation returning false is followed by the latter methods being run through, thus producing the second popup. It's rather annoying at times, however. It works fine, like I said, but I'd like to find out if there's a way to make it stop running through the rest if the validation returns false.
private void ReadAccNums(int[] accountNumArray)
{
// Try-catch to prevent file error issues.
try
{
// Increment num var.
int num = 0;
// Open ChargeAccounts.txt file.
StreamReader accNumsFile = File.OpenText("ChargeAccounts.txt");
// Read account numbers into array.
while (num < accountNumArray.Length && !accNumsFile.EndOfStream)
{
// Put each item into accountNumArray.
accountNumArray[num] = int.Parse(accNumsFile.ReadLine());
num++;
}
// Close file.
accNumsFile.Close();
}
catch (Exception ex)
{
// Display error message.
MessageBox.Show(ex.Message);
}
}
// Method to handle TextBox input
// validation.
private bool InputIsValid(ref int accNum)
{
// Flag to make sure input is good.
bool inputValid = false;
// Get and validate accountNumbersAccessTextBox input.
if (int.TryParse(accountNumberAccessTextBox.Text, out accNum))
{
// Did we get this far? Confirm input validation.
inputValid = true;
}
// Display error message for accNum.
else
{
MessageBox.Show("Please input a non-decimal, seven digit number" +
" for the account number.");
// Reset Focus to accountNumbersAccessTextBox.
accountNumberAccessTextBox.Focus();
}
// Return result.
return inputValid;
}
// Method to find out if input
// has a match in ChargeAccounts.txt.
private int AccNumSearch(int accNum,
int[] accountNumArray)
{
// Bool flag for matching accNum.
bool accNumFound = false;
// Index var.
int num = 0;
// Position of Sequential Search.
int position = -1;
// Get input from TextBox.
if (InputIsValid(ref accNum))
{
// Read through array to find
// matching accNum.
while (!accNumFound && num < accountNumArray.Length)
{
if (accountNumArray[num] == accNum)
{
// Found a match? Yay! Access granted!
accNumFound = true;
position = num;
}
num++;
}
}
// Return.
return position;
}
// Method to determine whether input
// matches an account number.
private bool AccNumMatch(int[] accountNumArray,
ref int accNum)
{
// Bool flag to confirm
// matching accNum.
bool accNumMatch = false;
// Got a match? Tell the user.
if (AccNumSearch(accNum, accountNumArray) != -1)
{
accNumMatch = true;
MessageBox.Show("Account number correct. Access granted.");
}
else
{
// No match? Alas.
MessageBox.Show("Account number invalid. Access denied.");
}
// Return.
return accNumMatch;
}
private void accountNumberAccessButton_Click(object sender, EventArgs e)
{
// Declare array to be filled by
// ReadAccNums method.
const int SIZE = 18;
int[] accountNumArray = new int[SIZE];
// Get the account numbers.
ReadAccNums(accountNumArray);
// Var for accNum to ref.
int accNum = 0;
// Is our account number correct?
AccNumMatch(accountNumArray, ref accNum);
}
Your code seems and incredibly verbose approach to:
the user types a number into a textbox
the program checks it's numeric
the program checks it's present in a file
If I was tasked to write such a code I might:
void Login_Click(object sender, EventArgs e){
if(!int.TryParse(accountNumberTextbox.Text, out int seeking)) {
MessageBox.Show("The account number text does not appear to be numeric");
return;
}
accNumMatch = File.ReadLines("c:\\temp\\accountnumbers.txt").Any(line => line == accountNumberTextbox.Text));
if(accNumMatch) {
MessageBox.Show("Account number correct. Access granted.");
}
else {
MessageBox.Show("Account number invalid. Access denied.");
}
}
because there simply isn't any point in converting the file contents to number and then searching the number; simpler to leave them as strings and compare strings, after making sure what the user entered was a number
And if I used a numericupdown so the user couldn't even enter a non number:
void Login_Click(object sender, EventArgs e){
accNumMatch = File.ReadLines("c:\\temp\\accountnumbers.txt").Any(line => line == accountNumberNumericUpDown.Value.ToString()));
if(accNumMatch) {
MessageBox.Show("Account number correct. Access granted.");
}
else {
MessageBox.Show("Account number invalid. Access denied.");
}
}
YOu can just convert what they entered to text and launch straight into reading the file and looking for a line bearing what they entered
I appreciate you might be learning, so using LINQ is a bit of a cheat, but even so:
void Login_Click(object sender, EventArgs e){
if(!int.TryParse(accountNumberTextbox.Text, out int seeking)) {
MessageBox.Show("The account number text does not appear to be numeric");
return;
}
accNumMatch = false;
StreamReader accNumsFile = File.OpenText("ChargeAccounts.txt");
while (!accNumsFile.EndOfStream && !accNumMatch)
{
string line = accNumsFile.ReadLine();
accNumMatch = (line == accountNumberTextbox.Text);
}
}
I'll forego lecturing about using/making sure you close and dispose your file readers etc for now ;)
If you have to read a file into an array, you can use System.IO.File.ReadAllLines() as a quick way to read a file. I won't use it here, but you can look it up if you want to see
If you have to read up to X lines from a file, into an array of ints, and then see if any of the ints are the one you seek:
void Login_Click(object sender, EventArgs e){
bool validInput = int.TryParse(accountNumberTextbox.Text, out int seeking);
if(!validInput) {
MessageBox.Show("The account number text does not appear to be numeric");
return;
}
int[] numbers = new int[100];
StreamReader accNumsFile = File.OpenText("ChargeAccounts.txt");
for(int i = 0; i < numbers.Length && !accNumsFile.EndOfStream; i++)
{
string line = accNumsFile.ReadLine();
numbers[i] = int.Parse(line);
}
accNumMatch = false;
foreach(int number in numbers){
if(number == seeking) { //seeking comes from earlier
accNumMatch = true;
break;
}
}
}
You could break these into separate methods. Make a method that takes an input and gives an output:
void Login_Click(object sender, EventArgs e){
int seek = ConvertToAccountNumber(accountNumberTextbox.Text);
if(seek == -1){
MessageBox.Show("Enter a valid number");
return
}
int[] numbers = GetAccountNumbersInFile("ChargeAccounts.txt");
accNumMatch = ArrayContainsNumber(numbers, seek);
}
//this is basically a variation of int.Parse/int.TryParse
public int ConvertToAccountNumber(string s){
bool validInput = int.TryParse(accountNumberTextbox.Text, out int seeking);
if(!validInput)
return -1; //we will use -1 to signify invalid input, because no account number is ever -1
else
return seeking;
}
//File.ReadAllLines can help with this, as can LINQ Select/int parse
public int[] GetAccountNumbersInFile(string p){
int[] numbers = new int[100];
StreamReader accNumsFile = File.OpenText(p);
for(int i = 0; i < numbers.Length && !accNumsFile.EndOfStream; i++)
{
string line = accNumsFile.ReadLine();
numbers[i] = int.Parse(line);
}
}
//there exist helper methods for doing this too, look at the Array class - https://learn.microsoft.com/en-us/dotnet/api/system.array?view=netcore-3.1
public bool ArrayContainsNumber(int[] array, int seeking){
foreach(int number in numbers){
if(number == seeking) {
return true;
}
}
return false;
}
I know why you used ref but you should avoid it. Actually the framework uses out when it parses text to a number and returns a boolean to indiccate the success and a number, but you can easily take the approach that something like string.IndexOf takes - it returns -1 if the needle is not found in the haystack. You haven't learned about exceptions yet (probably) but this would be an opportunity to use them too - throw an exception instead of returning a value if the input data is bad
All in, it's one of the few places where out might be reasonable in your career, so use it if you must (for academicc reasons, but don't use ref - ref is for methods that take a variable in with the intention of using its value before possibly overwriting it with something else. This is an out scenario, where the input variable shouldn't have a value and will be overwritten by the method) but
I am working on a serial monitor project based on the arduino serial monitor, but with a lot of more functionalities. Serial monitor UI with messages every 2 seconds
There are 2 basic functions - reading serial data and visualising it to the richtextbox, writing serial data and also visualising it to the richtextbox. There is a problem when the communication is very intensive (arduino sends a line as fast as it can) and the user input cuts some of the recieved lines in halves. I made an algorythm to separate the input strings from the output strings in the richtextbox by setting sending/receiving flags. However this made the program act strange. Sometimes the command sent to the arduino just doesn't visualise in the richtextbox, but the data from the arduino is visualised just fine. I tried setting breakpoints on the user input visualising method and they were rarely activated. What is more I also set breakpoints on the visualisation of the read data method and they were also rarely activated. However the form was not lagging or freezing and the commands were flying in the richtextbox, contrary to the observed behaviour of the breakpoints. The printing algorythm is heavy, because I implemented multi-color printing.
What I tried:
-tried the blockingcollection approach. Just putting the printing actions in a queue and executing the actions one by one using 2 additional threads to the main one.(Task.Factory.StartNew). The problem was the queue was filled with over 3000 actions in the matter of a minute and the whole thing was lagging behind with like 15 seconds.
-i tried starting a new Task.Factory for every receive/send methods for every printing of a new command and locking the thread until the command is printed in the richtextbox. This is also too slow.
Finally I came up with the idea of just setting flags and allowing or not the print event. Using this approach the user input is almost never printed in the richtextbox. :(
Printing algorythm:
void printToConsole(string print, Color txtColor, string part, Color partColor, bool isMsg, bool endNL)
{
while (print.Contains('\r'))
print = print.Replace("\r", "");
for (int i = 0; i < print.Length; i++)
{
if (newString)
{
newString = false;
printTimeAndPart(part, partColor);
}
else if (i == 0 && !prevStrHadNL && isMsg != prevWasMsg)
{
printNLTimeAndPart(part, partColor);
}
else if (i == 0 && prevStrHadNL)
{
printNLTimeAndPart(part, partColor);
}
else if (i == print.Length - 1)
{
if (print[i] == '\n')
{
if (endNL && isMsg != prevWasMsg)
AppendText("\n");
prevStrHadNL = true;
break;
}
else
{
if (endNL)
AppendText("\n");
prevStrHadNL = false;
}
}
if (print[i] == '\n')
{
printNLTimeAndPart(part, partColor);
}
else
AppendText(print[i].ToString(), txtColor);
}
prevWasMsg = isMsg;
}
private void printNLTimeAndPart(string part, Color partColor)
{
AppendText("\n");
printTimeAndPart(part, partColor);
}
private void printTimeAndPart(string part, Color partColor)
{
if (timestamp == 1)
AppendText(DateTime.Now.ToString("HH:mm:ss.fff"), timeColor);
AppendText(part, partColor);
}
private void AppendText(string txt, Color clr)
{
if (serialControl.ReadAllowed)
{
if (rtArea.InvokeRequired)
{
MethodInvoker mi = delegate ()
{ rtArea.AppendText(txt, clr); };
Invoke(mi);
}
else
rtArea.AppendText(txt, clr);
}
}
private void AppendText(string txt)
{
if (serialControl.ReadAllowed)
{
if (rtArea.InvokeRequired)
{
MethodInvoker mi = delegate ()
{ rtArea.AppendText(txt); };
Invoke(mi);
}
else
rtArea.AppendText(txt);
}
}
Serial read data print:
wait1 and wait2 - flags. When wait1 is false there is no current user input message being printed.
When wait2 is false user input is free to print. If the access to a print operation was denied it is performed after the operation which blocked it. (At least that is the idea)
private void Port_dataRecieved(string a)
{
if (!consoleUsed)
{
newString = true;
consoleUsed = true;
}
inputVal = a;
if (!wait1)
{
inputAccDenied = false;
wait2 = true;
PrintInput(inputVal);
wait2 = false;
}
else
inputAccDenied = true;
if (msgAccDenied)
{
PrintMsg(msgVal);
msgAccDenied = false;
}
}
private void PrintInput(string input)
{
printToConsole(input, inTxtColor, inPrefix, inPrefColor, false, false);
}
This is the dataReceived method from my serial controller class:
I tried several ways to read serial data and the uncommented one is the most stable one I tried.
private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
/* byte[] buffer = new byte[blockLimit];
Action kickoffRead = null;
kickoffRead = delegate
{
port.BaseStream.BeginRead(buffer, 0, buffer.Length, delegate (IAsyncResult ar)
{
try
{
int actualLength = port.BaseStream.EndRead(ar);
byte[] received = new byte[actualLength];
Buffer.BlockCopy(buffer, 0, received, 0, actualLength);
string rcv = Encoding.Default.GetString(received);
dataRecieved(rcv);
}
catch (IOException exc)
{
//handleAppSerialError(exc);
}
kickoffRead();
}, null);
};
kickoffRead();
*/
if (ReadAllowed)
{
string a = port.ReadExisting();
//port.DiscardInBuffer();
dataRecieved(a); //Raise event and pass the string to Form1 serial_dataReceived
}
}
So, I need some advice on how exactly to print the multi-color messages without cutting into each other, printing every time, fast, with low cpu load (now it is like 35% on full load (arduino intensive transmittion) on i5-4310m). I would be glad if you could provide some examples, too.
So one of the forms I have to create is where you enter a first and last name and then it splits the two names and puts them next to the appropriate labels, form design: https://gyazo.com/9b34dca0c1cd464fd865830390fcb743 but when the word stop is entered in any way e.g. Stop, StOp, sToP etc. it needs to end.
private void btnSeparate_Click(object sender, EventArgs e)
{
string strfullname, strgivenname, strfamilyname, strfirstname;
int int_space_location_one, int_space_location_two;
strfullname = txtFullName.Text;
int_space_location_one = strfullname.IndexOf(" ");
strgivenname = strfullname.Substring(0, int_space_location_one);
lblGivenEntered.Text = strgivenname;
strfirstname = strfullname.Remove(0, int_space_location_one + 1);
int_space_location_two = strfirstname.IndexOf(" ");
strfamilyname = strfirstname.Substring(int_space_location_two + 1);
lblFamilyEntered.Text = strfamilyname;
}
This is my current code, I have tried many different ways to get the word stop to end it but it wont work so that's why there is currently no code trying to stop the program, the main problem I get is because it is searching for a space between the first and last name and it obviously doesn't have one for one word it just crashes.
Any help with this would be amazing, thanks in advance.
Just hook up the TextChanged event and go like this:
private void TextChanged(Object sender, EventArgs e)
{
// If text, converted to lower-characters contains "stop" -> Exit
if(txtFullName.Text.ToLower().Contains("stop"))
{
// What I understand as "stopping it".
Application.Exit();
}
}
IF with "stop it" you mean to cancle the operation:
private void btnSeparate_Click(object sender, EventArgs e)
{
// If text, converted to lower-characters contains "stop" -> Exit
if (txtFullName.Text.ToLower().Contains("stop"))
{
// What I understand as "stopping it".
Application.Exit();
}
else
{
// Your code inside the else block
}
}
Short version of everything: Also covering no spaces problem
private void btnSeparate_Click(object sender, EventArgs e)
{
// Save how many words are inside
int wordsInText = txtFullName.Text.Split(' ').Length;
// Save if "stop" was typed into the textbox
bool stopExisting = !txtFullName.Text.ToLower().Contains("stop");
// If text has exactly 3 words and "stop" is NOT existing
if (wordsInText == 3 && !stopExisting)
{
// Save array of splitted parts
string[] nameParts = txtFullName.Text.Split(' ');
// This is never used??
string strfirstname = nameParts[1];
// Set name-parts to labels
lblGivenEntered.Text = nameParts[0];
lblFamilyEntered.Text = nameParts[2];
}
// If text has NOT exactly 3 words and "stop" is NOT existing
else if(wordsInText != 3 && !stopExisting)
{
// If there are no 3 words, handle it here - MessageBox?
}
// If "stop" IS existing
else if(stopExisting)
{
// If text contains "stop" handle it here
// Application.Exit(); <-- if you really want to exit
}
}
You could just check, if one of the entered words is equal to the word "stop". There you need a StringComparions which ignores the case. Or you could parse the entered word into lower/upper-cases.
So if the check is true, you could just end the program with
Environment.Exit(0);
You could just check, if one of the entered words is equal to the word "stop". There you need a StringComparions which ignores the case. Or you could parse the entered word into lower/upper-cases.
So if the check is true, you could just end the program with
Environment.Exit(0);
Code:
if (strfullname.ToLowerInvariant().Contains("stop"))
{
Environment.Exit(0);
}
Let me explain the scenario: serial port that bring me data (string) as the following example:
02051014 0009 M 0 741 30041105 2632 0 30041105
I have tried all kinds of read (read, read byte, read char, read line, read existing). I tried to change the new line but the data keeps duplicated. Look to the example above, and now look how data is coming:
0220510114 00009 M 0 741 300441105 2632 0 300411055
Anyone have any idea of how can I solve this problem?
The code:
[...]
try
{
this.serialPort = new SerialPort("COM1", 2400, Parity.None, 7, StopBits.One);
this.serialPort.DataReceived += new SerialDataReceivedEventHandler(portaSerial_DataReceived);
this.serialPort.Handshake = Handshake.XOnXOff;
this.serialPort.Encoding = Encoding.ASCII;
this.serialPort.Open();
}
[...]
private void portaSerial_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
try
{
var invalidValuesToBreakLine = new int[] { 13, 10, 0 };
int data;
while (this.serialPort.BytesToRead > 0)
{
data = this.serialPort.ReadChar();
if (invalidValuesToBreakLine.Contains(data))
{
if (!this.breakLineWasPerformed)
{
this.breakLineWasPerformed = true;
this.dataList.Add(this.temporaryString);
this.temporaryString = string.Empty;
}
}
else
{
if (this.breakLineWasPerformed)
{
this.breakLineWasPerformed = false;
}
this.temporaryString += (char)data;
}
}
[...]
The first thing I would try is to reset data to an empty string after each call to the ReadChar() method, and or flush the input buffer.
I suspect that the call to BytesToRead() is returning greater than zero, yet the ReadChar() call is returning the original character on the serial port buffer. This is due to the internal timings of a serial port, and the fact that your code is likely "running too fast" for the hardware device.
I would maybe rethink the whole while loop in the method. You could probably simplify this a lot, and just try the following (with your customized code)
private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
SerialPort sp = (SerialPort)sender;
string indata = sp.ReadExisting();
Console.WriteLine("Data Received:");
Console.Write(indata);
}
To change your newline chars, just examine the indata string and break on your characters, store the result in a global variable, and then reuse the left over data.
Having dug about I've found this StackOverflow question / answer that suggests the DataReceived event can fire off at unexpected times. So, if possible you should set a NewLine and trigger on that.
As a test of this idea you could try adding a button and wait until you KNOW you have some data and then click it to show you the stream. If there are no duplicates then that points to the DataReceived event as being over eager and firing incorrectly. You may then want to check your NewLine, DtrEnable and DsrHolding etc.
private void TestButton_Click(object sender, EventArgs e)
{
string indata = this.serialPort.ReadExisting();
MessageBox.Show(indata);
}
UPDATE: SOLUTION AT END
I have a Winform, label1 will display some info returned from a SQL Search using the input (MemberID) received from barcode scanner via txtBoxCatchScanner.
Scenario is people swiping their MemberID Cards under the scanner as they pass through reception and the Winform automatically doing a Search on that MemberID and returning their info including for example "Expired Membership" etc on the receptionist's PC which has the winForm in a corner of her desktop.
I have the Below Code working fine on first swipe (eg. first person)
The number MemberID, for example 00888 comes up in the text box, ADO.NET pulls the data from SQL and displays it fine.
one thing to note maybe, the cursor is at the end of the memberID: 00888|
All good so far, THEN:
when swipe 2 (eg. next person) happens
their number (say, 00999) gets put onto the end of the first in the txtBox eg: 0088800999 so naturally when TextChanged Fires it searches for 0088800999 instead of 00999 ....
I've tried:
txtBoxCatchScanner.Clear();
and
txtBoxCatchScanner.Text = "";
and
reloading the form
at the end of my code to "refresh" the text box
but i guess they trigger the TextChanged Event
How can i refocus or ... clear the old number and cursor back to start of txtBox after the previous swipe has done its stuff...
I'm a beginner so I'm sure the code below is pretty crap....
But if anyone has time, please let me know how fix it to do what i want.
UPDATE:
Ok after much experimenting I''ve managed to get this 1/2 working now hopefully someone more experience can help me to completion! :P
if (txtBoxCatchScanner.Text.Length == 5)
{
label1.Text = txtBoxCatchScanner.Text; // just a label for testing .. shows the memmber ID
txtBoxCatchScanner.Select(0, 5);
}
SO scan 1, say 00888 , then that gets highlighted, scan 2 , say 00997 ... sweet! overwrites (not appends to) 00888 and does it's thing ... scan 2 0011289 ... DOH!!
Problem: not all barcodes are 5 digits!! they are random lengths!! Memeber ID range from 2 digit (eg. 25) to 10 digits, and would grow in the future...
Edit: Something I've discovered that is that the barcodes are read as indvidual key presses. I think this is why answer 1 below does not work and while the big probmlems:
for example with 00675 the input (?output) from the scanner is:
Down: Do
Up: Do
Down: Do
Up: Do
Down: D6
Up: D6
Down: D7
Up: D7
Down: D5
Up: D5
down: Retunn
Up: Return
other info: barcode scanner is: an Opticon OPL6845 USB
Thanks
private void txtBoxCatchScanner_TextChanged(object sender, EventArgs e)
{
Member member = new Member();
member.FirstName = "";
member.LastName = "";
//Get BarCode
//VALIDATE: Is a Number
double numTest = 0;
if (Double.TryParse(txtBoxCatchScanner.Text, out numTest))
{
//IS A NUMBER
member.MemberID = Convert.ToInt32(txtBoxCatchScanner.Text);
//SEARCH
//Search Member by MemberID (barcode)
List<Member> searchMembers = Search.SearchForMember(member);
if (searchMembers.Count == 0)
{
lblAlert.Text = "No Member Found";
}
else
{
foreach (Member mem in searchMembers)
{
lblMemberStatus.Text = mem.MemberStatus;
lblMemberName.Text = mem.FirstName + " " + mem.LastName;
lblMemberID.Text = mem.MemberID.ToString();
lblMessages.Text = mem.Notes;
if (mem.MemberStatus == "OVERDUE") // OR .. OR .. OR ...
{
lblAlert.Visible = true;
lblAlert.Text = "!! OVERDUE !!";
//PLAY SIREN aLERT SOUND
//C:\\WORKTEMP\\siren.wav
SoundPlayer simpleSound =
new SoundPlayer(#"C:\\WORKTEMP\\siren.wav");
simpleSound.Play();
}
else
{
lblAlert.Visible = true;
lblAlert.Text = mem.MemberStatus;
}
}
}
}
else
{
//IS NOT A NUMBER
lblAlert.Text = "INVALID - NOT A NUMBER";
////
//lblMemberName.Text = "";
//lblMemberID.Text = "";
//lblMemberID.Text = "";
}
SOLUTION:
The System won't let me answer my own question for another 3 hours, as I'm a newbie only 1 post, so will put here:
First thanks everyone for your help and Patience.
I Have finally figured a solition, not fully tested yet as its 2am and bed time.
following along from my updates where I had success but hit the variable length of MemberID problem. I've now overcome that with the Code below:
namespace SCAN_TESTING
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void txtBoxCatchScanner_KeyUp(object sender, KeyEventArgs e)
{
if (e.KeyValue == (char)Keys.Return)
{
e.Handled = true;
int barcodeLength = txtBoxCatchScanner.TextLength;
txtBoxCatchScanner.Select(0, barcodeLength);
//TEST
label3.Text = barcodeLength.ToString();
//TEST
label2.Text = txtBoxCatchScanner.Text;
}
}
I'll add this to my previous "real" code and test in the morning
But at this stage is doing exactly what I want! =]
Update: Tested it .. works exactly what needed:
private void txtBoxCatchScanner_KeyUp(object sender, KeyEventArgs e)
{
if (e.KeyValue == (char)Keys.Return)
{
e.Handled = true;
int barcodeLength = txtBoxCatchScanner.TextLength;
txtBoxCatchScanner.Select(0, barcodeLength);
//
//INSERT ORGINAL CODE HERE. No Changes were needed.
//
}//end of if e.KeyValue ...
}//end txtBoxCatchScanner_KeyUp
Hope that helps anyone in the future!! :)
Thanks again for the 2 very good solutions, I can see how they work, and learnt alot.
Just didn't work in my case - more likely due to myself or my error/not understanding, or scanner type.
I´m not exactly sure what the actual problem is.
txtBoxCatchScanner.Clear();
txtBoxCatchScanner.Text = "";
both trigger the "Changed" Event.
But they also clear the box. So that should be what you want to do.
You could check at the beginning if the box is actually empty, and return in case it is. Like:
if(txtBoxCatchScanner.Text == "" |txtBoxCatchScanner.Text == string.Empty)
return;
So nothing else happens, if the box is empty.
If I misunderstood your problem, please specify and I will try to help.
Regards
EDIT:
Your function should work if it looked something like this:
private void txtBoxCatchScanner_TextChanged(object sender, EventArgs e)
{
Member member = new Member();
member.FirstName = "";
member.LastName = "";
if(txtBoxCatchScanner.Text == "" | txtBoxCatchScanner.Text == string.Empty)
return; // Leave function if the box is empty
//Get BarCode
//VALIDATE: Is a Number
int numTest = 0;
if (int.TryParse(txtBoxCatchScanner.Text, out numTest))
{
//IS A NUMBER
//member.MemberID = Convert.ToInt32(txtBoxCatchScanner.Text);
member.MemberID = numTest; // you already converted to a number...
//SEARCH
//Search Member by MemberID (barcode)
List<Member> searchMembers = Search.SearchForMember(member);
if (searchMembers.Count == 0)
{
lblAlert.Text = "No Member Found";
}
else
{
foreach (Member mem in searchMembers)
{
lblMemberStatus.Text = mem.MemberStatus;
lblMemberName.Text = mem.FirstName + " " + mem.LastName;
lblMemberID.Text = mem.MemberID.ToString();
lblMessages.Text = mem.Notes;
if (mem.MemberStatus == "OVERDUE") // OR .. OR .. OR ...
{
lblAlert.Visible = true;
lblAlert.Text = "!! OVERDUE !!";
//PLAY SIREN aLERT SOUND
//C:\\WORKTEMP\\siren.wav
SoundPlayer simpleSound =
new SoundPlayer(#"C:\\WORKTEMP\\siren.wav");
simpleSound.Play();
}
else
{
lblAlert.Visible = true;
lblAlert.Text = mem.MemberStatus;
}
}
}
}
else
{
//IS NOT A NUMBER
lblAlert.Text = "INVALID - NOT A NUMBER";
////
//lblMemberName.Text = "";
//lblMemberID.Text = "";
//lblMemberID.Text = "";
}
txtBoxCatchScanner.Clear();
}
The barcode scanner you use seems to function as a HID - a keyboard emulation. Every simple barcode scanner I know (and I'm working with them on a daily basis) has the option of specifying a suffix for the scanned barcode. Change the suffix to CRLF and add a default button to your form. Scanning a barcode that ends with CRLF will then automatically "push the button".
Move the code that performs the checks from TextChanged event in to the event handler for the buttons Click event and remove the TextChanged event handler. Then, when the button is clicked, also clear the text box and set the focus back to the text box.
You should be good to go, now.
You can easily check whether the barcode scanner already has the correct suffix configured: Open up Notepad and scan some barcodes. If they all appear on separate lines, then everything's fine. Otherwise you'll need to scan some configuration barcodes from the scanner's manual.
To sum it all up, this should be the code for the button's Click event:
private void btnCheckMember_Click(object sender, EventArgs e)
{
Member member = new Member();
member.FirstName = "";
member.LastName = "";
string memberText = txtBoxCatchScanner.Text.Trim();
txtBoxCatchScanner.Text = String.Empty;
int numTest = 0;
if (String.IsNullOrEmpty(memberText) ||!Int32.TryParse(memberText, out numTest))
{
//IS NOT A NUMBER
lblAlert.Text = "INVALID - NOT A NUMBER";
return;
}
member.MemberID = numTest;
List<Member> searchMembers = Search.SearchForMember(member);
if (searchMembers.Count == 0)
{
lblAlert.Text = "No Member Found";
}
else
{
foreach (Member mem in searchMembers)
{
lblMemberStatus.Text = mem.MemberStatus;
lblMemberName.Text = mem.FirstName + " " + mem.LastName;
lblMemberID.Text = mem.MemberID.ToString();
lblMessages.Text = mem.Notes;
if (mem.MemberStatus == "OVERDUE") // OR .. OR .. OR ...
{
lblAlert.Visible = true;
lblAlert.Text = "!! OVERDUE !!";
SoundPlayer simpleSound = new SoundPlayer(#"C:\\WORKTEMP\\siren.wav");
simpleSound.Play();
}
else
{
lblAlert.Visible = true;
lblAlert.Text = mem.MemberStatus;
}
}
}
This solution avoids the following problems:
The event being triggered upon every character added/removed from the content of the text box (which is also the case when scanning a barcode: They are added one by one as if they were entered on a keyboard)
Resulting from 1. the problem that a member check is performed upon every entered character
Resulting from 2. the problem that member XYZ will never be found if there is a member XY in the database, as the check stops after finding XY
Resulting from 3. the problem that member XY will also not be found, but only member Z, because in 3. the text box is cleared and Z is the only character being entered.
The best way to clear the textBox on the next textChange event.
Insert this line
txtBoxCatchScanner.SelectAll();
at the end of TextChange function.. This will select the text, so that i can be replaced easily on the next event.