Tic Tac Toe - C# - Having trouble completing checks - c#

So here's the deal, I'm trying to compare images in a local resource for X and O, and if they're the same in the winCondition array, to message the user they won.
The problem I'm finding is that b1.Image isn't giving me the proper comparison. It's comparing this:
+ b1.Image {System.Drawing.Bitmap} System.Drawing.Image {System.Drawing.Bitmap}
when I want it to compare the image names instead.
One of these problems is that when turnNumber = 5, it says I won, when I haven't. I believe this is due to the b1.Image problem. Once I click another square, it checks for the win again.
I want to disable the buttons once a game is completed, however I don't know how to do this.
Would it be as simple as:
foreach (Button btnEnabled in buttonArray)
{
btnEnabled.Enabled = false;
}
Here is the code, and again, thank you for any help. I have been struggling with this for a few days.
namespace BGreinAssignment2
{
public partial class frmTicTacToe : Form
{
//Global variables
private bool player1Turn = false;
private bool player2Turn = true;
private int[,] winCondition =
{
{0,1,2}, //Horizontal top
{3,4,5}, //Horizontal Middle
{6,7,8}, //Horizontal Bottom
{0,3,6}, //Vertical Left
{1,4,7}, //Vertical Middle
{2,5,8}, //Vertical Right
{0,4,8}, //Diagonal Top Left to Bottom Right or Vice-Versa
{2,4,6} //Diagonal Top Right to Bottom Left or Vice-Versa
};
private Button[] buttonArray;
private int turnNumber = 0;
public frmTicTacToe()
{
InitializeComponent();
}
//Creates the button array for checks and sets X to go first.
private void frmTicTacToe_Load(object sender, EventArgs e)
{
//Creates button array for checking if image is there/check for beginning of game
buttonArray = new Button[9] {btnTopLeft, btnTopMid, btnTopRight, btnMidLeft, btnMid, btnMidRight, btnBotLeft, btnBotMid, btnBotRight};
//Sets player 1 to go first to satisfy the "X always goes first"
player1Turn = true;
player2Turn = false;
}
/// <summary>
/// Checks the buttons if the images don't create a win condition through the winCheck method,
/// displays message box to user with "Draw!" break is included so it doesn't say "Draw!" for each button it checks.
/// </summary>
private void drawCheck()
{
foreach (Button checkDraw in buttonArray)
{
if (checkDraw.Image != null)
{
MessageBox.Show("Draw!");
break;
}
}
}
/// <summary>
/// Checks the win condition to see if the images are the same. If they are, it will show a message box with the winner.
/// </summary>
/// <param name="btnChecks">Creates an array to check the button images</param>
/// <returns>If there is a winner, returns true and shows message box</returns>
private bool winCheck(Button[] btnChecks)
{
bool win = false;
for (int i = 0; i < 8; i++)
{
int a = winCondition[i, 0], b = winCondition[i, 1], c = winCondition[i, 2];
Button b1 = btnChecks[a], b2 = btnChecks[b], b3 = btnChecks[c];
if (b1.Image == null || b2.Image == null || b3.Image == null)
{
continue;
}
if (b1.Image == b2.Image && b2.Image == b3.Image)
{
win = true;
MessageBox.Show("Game over. " + b1.Image + " Wins!");
}
}
return win;
}
//If player chooses top left square
private void btnTopLeft_Click(object sender, EventArgs e)
{
if (btnTopLeft.Image == null)
{
if (player1Turn == true)
{
if (turnNumber == 0)
{
btnTopLeft.Image = BGreinAssignment2.Properties.Resources.tic_tac_toe_X;
player1Turn = false;
player2Turn = true;
turnNumber++;
}
else
{
btnTopLeft.Image = BGreinAssignment2.Properties.Resources.tic_tac_toe_X;
player1Turn = false;
player2Turn = true;
turnNumber++;
if (turnNumber >= 5)
{
winCheck(buttonArray);
}
if (turnNumber == 9)
{
drawCheck();
}
}
}
else
{
btnTopLeft.Image = BGreinAssignment2.Properties.Resources.tic_tac_toe_O;
player1Turn = true;
player2Turn = false;
turnNumber++;
if (turnNumber <= 5)
{
winCheck(buttonArray);
}
if (turnNumber == 9)
{
drawCheck();
}
}
}
else
{
MessageBox.Show("This space has already been selected");
}
}
//Excluded rest of code (just button clicks, repeats of same for 9 squares)
/// <summary>
/// Resets the game for the player.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnPlayAgain_Click(object sender, EventArgs e)
{
//For each button, set image to null then reset turn counter and set turn to player 1.
foreach (Button btnSpaces in buttonArray)
{
btnSpaces.Image = null;
}
turnNumber = 0;
player1Turn = true;
player2Turn = false;
}
}
}

As you discovered, comparing Images directly is not the answer. I haven't tested this, but I suspect it's because each Image could have very different properties, despite being loaded from the same resource. For example, if one button was only 20-pixels square, and another was 50, the Height and Width properties would be different. See the documentation for some other properties.
A better way to handle this, as #John3136 said, is to split the model away from the drawing. This could be as simple as using the Tag property on each button to store either an "O" or an "X". You'd check everything the same as you do now, except you'd be comparing b1.Tag == b2.Tag && b2.Tag == b3.Tag. A better, but more complicated way, would be to have an array of something to represent your game board. As with any programming problem, there's many possible ways to do it - char[9] would be the simplest, although string[] or bool?[] could work, creating an enum and storing an array of that, or an array of arrays of any of the above. (Also List<> instead of an array, eventually). In either case, you'd have to update your model at the same time as you update the image, but you're then doing a much simpler comparison to test for victory.
You're entirely correct about disabling the buttons - but here's a question for you. What happens if someone clicks on a button that the other player has already clicked? Sure, you can alert the user, but it still looks like a valid choice. Why not disable it as soon as it's clicked?
I'm also going to go a bit further afield and give you a tip for the "//Excluded rest of code (just button clicks, repeats of same for 9 squares)" line. If you're going to repeat the same code more than twice (and some people would say more than once), you're better off making a function which takes whatever will differentiate it as an argument. For example, you could have
//If player chooses top left square
private void btnTopLeft_Click(object sender, EventArgs e)
{
DoClick(btnTopLeft);
}
//If player chooses top center square
private void ptnTopCenter_CLick(object sender, EventArgs e)
{
DoClick(btnTopCenter);
}
private void DoClick(Button button)
{
// Manipulate button appropriately
}
This isn't doing anything you don't already know how to do - you're already calling other functions, and passing buttons around in arguments (see winCheck()). It's just a way of thinking which will reduce the amount of code you need to write, and thus the places you need to fix any given bug.

Related

NumericUpDown ValueChanged preventDefault?

I want to create a form that allows the user to set a certain amount of points in five different fields (NumericUpDown). When that amount of points reaches 0, the user can't add any more. (I still want the user to be able to remove points, though.)
Here is my code so far:
private void calculateValue() {
decimal tempValue = CMB_num_Aim.Value + CMB_num_Reflexes.Value +
CMB_num_Positioning.Value + CMB_num_Movement.Value + CMB_num_Teamwork.Value;
controlValue = currentValue - tempValue;
MyBox.CMB_tb_cv.Text = controlValue.ToString();
}
This Method (calculateValue) is calculates how many points the user have left (controlValue).
private void CMB_num_Aim_ValueChanged(object sender, EventArgs e) {
calculateValue();
if (controlValue < 0) {
//Prevent Default here
MessageBox.Show("You are out of points!");
}
}
This method (CMB_num_Aim_ValueChanged) fires when the value of the NumericUpDown control has changed. I have one of these for each field, each doing the same thing.
The method fires as expected, but I can't prevent it from happening - the user can apply more points than they have. How can I prevent the user from applying more points?
(I thought about making a mouseUp method, but I don't know if the user will use the mouse or if he will type in the value using the keyboard.)
Seems like you want to create a point distribution system between some skills - aim, movement, teamwork etc. You can do that easily by setting Maximum value of NumericUpDown control when you enter it. Subscribe all skill updown controls to the same event handler:
private void SkillNumericUpDown_Enter(object sender, EventArgs e)
{
var skill = (NumericUpDown)sender;
var availablePoints = 42;
var maxSkillPoints = 20; // usually you cannot assign all points to one skill
var unassignedPoints = availablePoints - SkillPointsAssigned;
skill.Maximum = Math.Min(maxSkillPoints, unassignedPoints + skill.Value);
if (unassignedPoints == 0)
{
MessageBox.Show("You are out of points!");
return;
}
if (skill.Value == maxSkillPoints)
{
MessageBox.Show("Skill maximized!");
return;
}
}
private decimal SkillPointsAssigned =>
CMB_num_Aim.Value +
CMB_num_Reflexes.Value +
CMB_num_Positioning.Value +
CMB_num_Movement.Value +
CMB_num_Teamwork.Value;
Benefit - you will not be able to input illegal value neither by arrows nor manually.
Replace
if (controlValue < 0) {
By
if (controlValue <= 0) {

Computing Form Location with Button

I'm working on a programming assignment, and I'm trying to make this button take the values from two textboxes, and calculate the new location for the form window. I'm having trouble converting the textbox values to type int, and being made usable by the btnCompute_click method.
private void btnCompute_Click(object sender, EventArgs e)
{
int x = Convert.ToInt32(txtXvalue);
int y = Convert.ToInt32(txtYvalue);
Location = new Point(x,y);
}
private void xValue_TextChanged(object sender, EventArgs e)
{
int xValue =
Convert.ToInt32(txtXvalue);
}
private void yValue_TextChanged(object sender, EventArgs e)
{
int y =
Convert.ToInt32(txtYvalue);
}
I forgot to add some additional info, the acceptable values for x and y must be positive. Would I use an if...else statement to control the acceptable values?
user29... i have no idea why death... replied that. it makes no sense to me. but you question makes sense to me. i suppose death... did not understand your question.
First off, everything you ask does not need anything in the TextChanged methods.
Do all your handling in the btnCompute_Click() method because you want to do something *when you click your button, not when the user edits the text of the text boxes, according to your question.
The code that is in your TextChanged() methods will get executed whenever the Text values of those text boxes change. that's not what you asked for it to do. But you could use these events for example, if you wanted a label to become visible or hidden and to set the text of a label which shows text, so you can use it as an error message label, for instance if the integer value of a text box is negative or even if it cannot be parsed.
So in your btnCompute_Click() methods, you first want to get the int values. You need to decide exactly what you want your code to do if the text is not integers. In my opinion, most beginners code things like message boxes or something. I like to give the user feedback with Labels or a status bar message, depending on what I feel is appropriate. Since my first choice would be to use a Label to show the 'error' message when text boxes cannot be parsed to integers, then i would simply return from the button click method without doing anything when the values are not what i want. That way the user gets their messages without annoying popup message boxes or anything. But it's up to you whether you want to pop up a message box or not. Others have given you good code to do that. I want to give you good code that avoids what i consider annoying popup boxes.
When converting strings to an int, Convert.ToInt32 will throw an error if the string cannot be parsed. int.TryParse is the silver bullet for truly parsing strings to integers without any error. Here is the entire code i would use. I made a new project just to make sure i'm not giving you buggy code. I give you my code on how I handle this.
In your updated prerequisite, you mention x & y must be positive and not negative. I note to you that these are not the same. For instance, 0 is neither positive nor negative. I assume that you technically mean that x and y cannot be negative, (and that it does not need to be positive, since 0 should be allowed).
private void Form1_Load(object sender, EventArgs e)
{
lblErrorX.Text = null;
lblErrorY.Text = null;
}
private void btnMoveForm_Click(object sender, EventArgs e)
{
int x = 0; if (int.TryParse(txtX.Text, out x) == false) { return; }
int y = 0; if (int.TryParse(txtY.Text, out y) == false) { return; }
if (x < 0 || y < 0) { return; }
this.Location = new Point(x, y);
}
private void txtX_TextChanged(object sender, EventArgs e)
{
int x = 0;
if (int.TryParse(txtX.Text, out x) == false)
{ lblErrorX.Text = "X is not an valid integer."; return; }
if (x < 0) { lblErrorX.Text = "X cannot be negative."; return; }
lblErrorX.Text = null;
}
private void txtY_TextChanged(object sender, EventArgs e)
{
int y = 0;
if (int.TryParse(txtY.Text, out y) == false)
{ lblErrorY.Text = "Y is not an valid integer."; return; }
if (y < 0) { lblErrorY.Text = "Y cannot be negative."; return; }
lblErrorY.Text = null;
}
In my project, on the form, in the following left to right order: lblX, txtX, lblErrorX. I have the same corresponding for Y: lblY, txtY, lblErrorY. Then i have one Button: btnMoveForm. So my txtX corresponds to your txtXvalue. my btnMoveForm corresponds to your btnCompute, but to me, 'compute' means to calculate, which is not really what this button is doing. this button is moving the form, so that's why i name it as such.
I have played with setting both the Location and the DesktopLocation and it seems to do the same thing. I've always used Location and i just learned that DesktopLocation works too, but since Location is shorter, i use it.
Someone asked why i don't use if(!int.TryParse(...)) { return; } rather than my if(int.TryParse(...) == false) { return; }. My reason is unfortunately that i think ! is an easy one character to miss when reading code, so i avoid it, especially when that little mistake means the opposite of what the code really would do. So my use of '== false' is always for human clarity. But i do like the C# ease of only needing one character. I just think it's a shame that in my opinion, it's a lot safer to write code that is better for humans so we don't mistake it. That's the only reason i use '== false' instead of !. Use ! if you like. It's quite convenient. I regret not using it. hehe.
Oh, and the reason i set the lblErrorX.Text = null; and lblErrorY.Text = null; is on my form in design view, i give them a text value so i can see them. :) so when the program runs, i set the Text to be blank. But you can use the Visible property if you prefer. I just leave them always visible and only set their Text properties.
Based on your expanded criteria you can check for negative numbers conditionally or use Math.Abs to get the absolute value. Something like this.
int x, y;
if (int.TryParse(txtXvalue.Text, out x) && int.TryParse(txtYvalue.Text, out y))
{
if (x < 0 || y < 0)
{
MessageBox.Show("Negative numbers not allowed");
}
else
Location = new Point(x, y);
}
else
{
MessageBox.Show("Must be an Integer");
}
or
int x, y;
if (int.TryParse(txtXvalue.Text, out x) && int.TryParse(txtYvalue.Text, out y))
{
Location = new Point(Math.Abs(x), Math.Abs(y));
}
else
{
MessageBox.Show("Must be an Integer");
}
I think you are looking for this.
private void btnCompute_Click(object sender, EventArgs e)
{
int x = Convert.ToInt32(txtXvalue.Text);
int y = Convert.ToInt32(txtYvalue.Text);
DesktopLocation = new Point(Math.Abs(x), Math.Abs(y));
}
This gets the location for the desktop. Also you need the .Text to get the text inside the textbox. You should also check to make sure the text is not null or empty before using or it will cause an error.
If this isn't what you are looking for please explain a little more.

C# WinForm + Barcode Scanner input, TextChanged 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.

c# panel image only updates half the time

For my programming class we are required to make a memory match game. When the player clicks on a panel an image is displayed. The player clicks on two panels, if the images match they are removed, if they are different they are turned face down.
The problem I am having with this is that only the image from the first panel gets displayed, even though I am using the same line of code to display the images from both panels, and use Thread.Sleep to pause the program after the second tile has been picked. I don't understand why this is happening, any help would be appreciated.
private void tile_Click(object sender, EventArgs e)
{
string tileName = (sender as Panel).Name;
tileNum = Convert.ToInt16(tileName.Substring(5)) - 1;
//figure out if tile is locked
if (panelArray[tileNum].isLocked == false)
{
pickNum++;
//although the following line of code is used to display the picture that is stored in the tile array
//what is happening is that it will only display the picture of the first tile that has been picked.
//when a second tile is picked my program seems to ignore this line completely, any ideas?
panelArray[tileNum].thisPanel.BackgroundImage = tiles[tileNum].tileImage;
if (pickNum == 1)
{
pick1 = tileNum;
panelArray[tileNum].isLocked = true;
}
else
{
pick2 = tileNum;
UpdateGameState();
}
}
}
private void UpdateGameState()
{
Thread.Sleep(1500);
if (tiles[pick1].tag == tiles[pick2].tag)//compares tags to see if they match.
{
RemoveTiles();
}
else
{
ResetTiles();
}
pickNum = 0;
guess += 1;
guessDisplay.Text = Convert.ToString(guess);
if (correct == 8)
{
CalculateScore();
}
}
try this:
(sender as Panel).BackgroundImage = tiles[tileNum].tileImage;
you have to be sure that your tile_Click method is associated to both panel...

Detect whether CapsLock is on or off in Silverlight

You may find if the CapsLock key has been pressed subscribing to the KeyDown/KeyUp event. And then toggle the state of the CapsLock based on that input. The problem with this approach is that you need the initial state of the CapsLock key to start toggling that.
One application of this could be giving the user a notification on a Login Page (this is what i need).
By the way i'm using Silverlight 5.
EDIT
The solution posted here says:
You can however find out if Capslock is on by making use of
KeyEventArgs.PlatformKeyCode that's actually send at onKeyDown.You can
look up the Virtual Key-code for capslock in here:
http://msdn.microsoft.com/en-us/library/ms927178.aspx
With this solution you can't determine the CapsLock state, because KeyEventArgs.PlatformKeyCode returns "an integer value that represents the key that is pressed or released (depending on which event is raised)". So if CapsLock is On and Key A is pressed then KeyEventArgs.PlatformKeyCode = 65, and on the other hand if CapsLock is off and Key A is pressed then KeyEventArgs.PlatformKeyCode = 65.
In other words you can't determine if the CapsLock is enabled or not based on the KeyEventArgs.PlatformKeyCode property.
The answer to this question also seems to have a solution, it checks two things:
the letter typed is Upper Case and Shift isn't pressed
the letter typed is Lower Case and Sift is pressed
Both of this cases implies that the CapsLock is On, but there is also a problem with this solution, given a KeyEventArgs you can know the pressed key in the keyboard but can't know the Char outputted by that key.
I'd suggest using a Behavior for this detection since you can hook into the PasswordChanged and KeyDown events to determine if the Caps Lock is on. Here is a quick behavior I wrote to detect if the Caps Lock is on. You can bind to the CapsLockOn behavior and use something like a data state behavior to hide/show your warning message.
public class DetectCapsLockBehavior : Behavior<PasswordBox>
{
private int _lastKey;
private ModifierKeys _modifiers;
[Category("Settings")]
public bool CapsLockOn
{
get { return (bool)GetValue(CapsLockOnProperty); }
set { SetValue(CapsLockOnProperty, value); }
}
public static readonly DependencyProperty CapsLockOnProperty = DependencyProperty.Register("CapsLockOn", typeof(bool), typeof(DetectCapsLockBehavior), new PropertyMetadata(null));
protected override void OnAttached()
{
AssociatedObject.PasswordChanged += new RoutedEventHandler(AssociatedObject_PasswordChanged);
AssociatedObject.KeyDown += new KeyEventHandler(AssociatedObject_KeyDown);
}
void AssociatedObject_KeyDown(object sender, KeyEventArgs e)
{
_lastKey = e.PlatformKeyCode;
_modifiers = Keyboard.Modifiers;
}
void AssociatedObject_PasswordChanged(object sender, RoutedEventArgs e)
{
if (_lastKey >= 0x41 && _lastKey <= 0x5a)
{
var lastChar = AssociatedObject.Password.Last();
if (_modifiers != ModifierKeys.Shift)
{
CapsLockOn = char.ToLower(lastChar) != lastChar;
}
else
{
CapsLockOn = char.ToUpper(lastChar) != lastChar;
}
}
}
}
NOTE: This is sample code, so there could be bugs. Just trying to demonstrate how it could be done.
region KeysDetection
bool bCaps = false;
bool bIns = false;
bool bNum = false;
public void FloatableWindow_KeyDown(object sender, KeyEventArgs e)
{
switch (e.Key)
{
case Key.CapsLock:
bCaps = !bCaps;
lbl_caps.Opacity = (bCaps) ? 1 : 0.5;
break;
case Key.Insert:
bIns = !bIns;
lbl_ins.Opacity = (bIns) ? 1 : 0.5;
break;
case Key.Unknown:
{
if (e.PlatformKeyCode == 144)
{
{
bNum = !bNum;
lbl_num.Opacity = (bNum) ? 1 : 0.5;
}
}
break;
}
}
}
#endregion

Categories

Resources