I tryed to make a while loop, and i know the problem, i just have no idea how to fix it. The int I use just never updates, making the code useless... I use Visual Studio, windows fom app, if that changes something... Sorry for the lenght, but i don't know where's the problem. (Input 1 and 2 are textboxes...) The text file I use looks like this:
Username: new line
(costum text) new line
Password: new line
(costum text) new line
Username: new line
...
Here's the code:
public partial class Form1 : Form
{
//This is part of the problem
int search = 0;
//This is part of the problem (end)
public void OK_Click(object sender, EventArgs e)
{
string path = #"filePath.txt";
var count = File.ReadLines(path).Count();
string user = File.ReadLines(path).Skip(search + 1).Take(1).First();
string pass = File.ReadLines(path).Skip(search + 3).Take(1).First();
//Main problem
if (Input1.Text != "" && Input2.Text != "")
{
while (Input1.Text == user && Input2.Text == pass)
{
if (search < count)
{
search = search + 4;
}
}
if (search < count)
{
MessageBox.Show("worked");
search = 0;
}
}
//Main problem (end)
}
}
This can be greatly simplified. The usernames and passwords are on alternating lines, so they need to be declared inside of the loop. You can also use a for loop to control skipping to the next username/password combination at the end of each iteration of the loop. And you don't need to do File.ReadLines multiple times, that causes it to hit the disk multiple times for something you could just hold in memory once.
You should also rename your textboxes to have names that represent the data they should contain. So UsernameTextbox instead of Input1 for example.
public void OK_Click(object sender, EventArgs e)
{
string path = #"filePath.txt";
var fileLines = File.ReadLines(path);
var authenticatedSuccessfully = false;
for (int line = 0; line < fileLines.Length - 1; line += 2)
{
var user = fileLines[line];
var password = fileLines[line + 1];
if (UsernameTextbox.Text == user && PasswordTextBox.Text == pass)
{
authenticatedSuccessfully = true;
break;
}
}
if (authenticatedSuccessfully)
{
MessageBox.Show("You are logged in!");
}
else
{
MessageBox.Show("Incorrect username or password!");
}
}
Of course...you should keep in mind that this is not secure at all. In the real world, passwords should be one way hashed and salted. Then when a user wants to authenticate you hash the password again and compare it to the stored value. If they match, then they provided the correct password. Storing passwords in plaintext is not a good idea.
Your while condition is wrong. You can use for loop for that(using counters), or you need to rebuild your while loop. You must put if conditions inside While loop dont make them separate. https://www.w3schools.com/cs/cs_while_loop.asp. Using while loop is good chance to go for infinite. So I am using For loops all the times.
Related
I am sort of new to programming and I cannot get this simple looking code to work
What I am trying to do is make a login system that works on an array so its easier to edit and add new people onto the list.
string[] UserCodes = { "admin", "testcode" }; //these are the arrays
string[] UserWords = { "123", "testword" };
public void Button_Clicked(object sender, EventArgs e)
{
for (int i = 0; i < UserCodes.Length; i++)
if (UserCode.Text.Equals(UserCodes[i]) && UserWord.Text.Equals(UserWords[i]))
{
Navigation.PushAsync(new HomePage());
}
for (int i = 0; i < UserCodes.Length; i++)
if (UserCode.Text != (UserCodes[i]) || UserWord.Text !=(UserWords[i]))
{
DisplayAlert("Something Went Wrong", "Incorrect Password or Username", "Try Again");
}
} // And this is the "main" code
I believe the main problem arises from the second part, where it displays an error, because if I don't enter the password correctly it works as it should but if I do enter correctly It sends me to the home page while still displaying the error. I have tried using else if, and i tried to use (!command.Equals(Array[i])). I am extremely confused as to why its acting this way.
Step through this code in the debugger. If you type in a correct UserCode and UserWord you will call Navigation.PushAsync(new HomePage())... and then keep going.
You next check if any UserWord or UserCode is not what you typed, and it will be, then show your error message.
You probably want to call return after Navigation.PushAsync(new HomePage()), or skip over the second for statement.
It feels like a code smell to me when you have one loop checking for a condition followed by an entirely different loop for when that condition fails. As #Corvus noted, you should return once you've made a match, and then you defer the error message after all looping is complete:
public void Button_Clicked(object sender, EventArgs e)
{
for (int i = 0; i < UserCodes.Length; i++)
{
if (UserCode.Text.Equals(UserCodes[i]) && UserWord.Text.Equals(UserWords[i]))
{
Navigation.PushAsync(new HomePage());
return; // thanks to #Corvus
}
}
DisplayAlert("Something Went Wrong", "Incorrect Password or Username", "Try Again");
}
That said, there are improvements you could make but did not ask about. Usually, the user name is acceptable regardless of case, but the password always must match the case. You are okay on the treatment of passwords but the user name match could be changed to ignore case.
Also, you have two arrays that must be in-sync with each other. I would suggest instead a Dictionary<string, string> where the user name is the Key and password is the Value.
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 creating a system that includes a ListBox of integers inserted by the user. I have contained a search button and a search TextBox for the user to input the integer they want to search for within the ListBox. Once the user has inputted the integer, I want a message box to be displayed either informing the user that there is e.g. 1 integer of value '3' in the list box, or an error message box informing the user that the integer does not exist within the list box.
private void buttonSearch_Click(object sender, EventArgs e)
{
listBoxAddedIntegers.SelectedItems.Clear();
for (int i = listBoxAddedIntegers.Items.Count - 1;i>=0; i--) ;
{
if (listBoxAddedIntegers.Items[i].ToString().ToLower().Contains(textBoxSearch.Text.ToLower())) ;
{
listBoxAddedIntegers.SetSelected(i, true);
}
}
// ...
}
I am not really sure on the code that I am meant to include here, and the code that I have already inserted suggests that 'i' does not exist in the current content.
Can anyone help please?
the code that I have already inserted suggests that 'i' does not exist in the current content
As #FrankM already mentioned in the comments. You have a trailing ; after your for-loop.
for (int i = listBoxAddedIntegers.Items.Count - 1;i>=0; i--) ;
This will prevent the for-loop to execute your code within the { ... }. This can be transcribed to
for (int i = listBoxAddedIntegers.Items.Count - 1;i>=0; i--)
{
// Do nothing.
}
{
// now your code
}
This means also that your code within the last curly braces will be in its own scope and so that all your defined variables will be unavailable to the following code.
Answering your actual question:
As you already do for selecting the matching items. You can extent this looping by counting up a counter. And later on show the results with a MessageBox.
With the following snippet of your code
listBoxAddedIntegers.Items[i].ToString().ToLower().Contains(textBoxSearch.Text.ToLower()))
you are currently checking if an item of your list contains the entered TextBox.Text.
So if the user has entered 3, 4, 5, ..., 13, 23 in the ListBox and searches for 3. He will get 3 matches. If you want only 1 match you should use String.Equals(). I used StringComparison.InvariantCultureIgnoreCase to avoid calling ToLower().
private void buttonSearch_Click(object sender, EventArgs e)
{
var counter = 0;
for (int i = 0; i < this.listBoxAddedIntegers.Items.Count; i++)
{
var item = this.listBoxAddedIntegers.Items[i];
if (string.Equals(item.ToString(), this.textBoxSearch.Text, StringComparison.InvariantCultureIgnoreCase))
{
this.listBoxAddedIntegers.SelectedItems.Add(item);
counter++;
}
}
if (counter == 0)
{
MessageBox.Show($"No matches for \"{this.textBoxSearch.Text}\" found!", "Search Results",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
else
{
MessageBox.Show($"{counter} items found for \"{this.textBoxSearch.Text}\"!", "Search Results",
MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
Hint:
Since C#6 you can use string interpolation instead of String.Format() or string concatenation (+).
private void buttonSearch_Click(object sender, EventArgs e)
{
listBoxAddedIntegers.SelectedItems.Clear();
var itemsFound = listBoxAddedIntegers.Items.Where(i=>i.ToString().ToLower().Contains(textBoxSearch.Text.ToLower())).ToList();
if(itemsFound == null)
{
MessageBox.Show("No matches found.");
}
else
{
MessageBox.Show("Found " + itemsFound.Count + " matches.");
}
}
You have to do this:
int count=0;
for(int i=0;i<listBoxAddedIntegers.Items.Count;i++)
{
if(listBoxAddedIntegers.Items[i].Items[i].ToString().ToLower().Contains(textBoxSearch.Text.ToLower())
{
count+=1;
}
}
if(count>0)
{
//display your message here after the loop with the count
}
else
{
//display your message with error
}
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.
I am coding an asian language learning module for my mojoportal-based iphone-optimized website (work in progress, english resources are not fully translated: http://ilearn.dandandin.it/kanatrainer.aspx)
It's a simple "guess how to read this" game, with the right answer stored in a Session object.
I don't understand why, but, expecially using Safari, users will get someone else's Session value
This is an excerpt from the code (i removed some stuff, translated the variables)
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
...
generateRandom();
}
}
protected void generateRandom()
{
int i, j = 0, livello = 5, chance = 0;
System.Random acaso = new Random();
...
while (j <= 0)
{
j = acaso.Next((Convert.ToInt32(TextBoxlunghezza.Text) + 1));
}
...
for (int k = 0; k < j; k++)
{
i = acaso.Next(livello);
Session["randomLetters"] += (globals.asianCharacters[i]);
...
}
...
}
protected void AnswerButton_Click(object sender, EventArgs e)
{
string compare = Server.HtmlEncode(InputTextBox.Text.ToLower());
if (compare == "")
{
Label1.Text = ("You did not write anything");
return;
}
if (Session["randomLetters"].ToString() != compare)
{
Label1.Text = ("Wrong!" + Session["randomLetters"]);
}
else
{
Label1.Text = ("Right!" + Session["randomLetters"]);
}
...
}
What happens in visual studio, with every browser:
randomLetters is "hello". User writes "hello" in the textbox, and "hello" is compared to "hello". Label says "Right! hello".
What happens in iis, only in webkit-based browsers:
randomLetters is "hello". User writes "hello" in the textbox, but "hello" is compared to "goodbye". Label says "Wrong! goodbye".
I don't understand how Session["randomLetters"] has changed
Public vs private code:
How are your storing the session state? Cookie? Database? so on... I have had many problems (usually with IE 8) with the way that the browser was caching the pages and the cookies. Usually, changing the respective setting in the browser fixed the problem. I don't know if that helps here. To make it more robust, I then have to find a way to notify the user when one of these settings is not right.
Using HiddenFields i "solved" the problem (but i don't like that way)