I'm trying to make a super simple program where you use 10 different buttons to write in a code (kind of like the code to the door of an appartment complex). All the buttons have this click event:
private void number_click(object sender, EventArgs e)
{
var button = (sender as Button);
if (code.Length == 4)
{
code.Remove(0, 1);
}
switch (button.Name)
{
case "button_1":
code += "1";
break;
case "button_2":
code += "2";
break;
case "button_3":
code += "3";
break;
case "button_4":
code += "4";
break;
case "button_5":
code += "5";
break;
case "button_6":
code += "6";
break;
case "button_7":
code += "7";
break;
case "button_8":
code += "8";
break;
case "button_9":
code += "9";
break;
case "button_0":
code += "0";
break;
}
label1.Text = code;
}
I'm simply trying to make so the number the user presses get added to the code string. When there length of the string reaches 4 it is supposed to remove the first character so that there is never more than 4 characters in the string. For some reason this doesn't seem to work. What am I doing wrong?
The immediate cause of the error is that string is immutable and so
code.Remove(0, 1);
computes result string and throws it away. You should assign the result string back:
...
code = code.Remove(0, 1);
...
You can get rid of long switch case and obtain digit from the button's name:
private void number_click(object sender, EventArgs e) {
var button = (sender as Button);
// Add new digit to the right
code += button.Name[button.Name.Length - 1].ToString();
// Ensure code is at most 5 digits long by removing digits from the left
code = code.Substring(Math.Clamp(code.Length - 5, 0, code.Length));
}
If you want to update the code variable you can use Substring method.
if (code.Length == 4)
{
code = code.Substring(1);
}
Your problem is caused by the fact that System.String instances are immutable. This means you can't modify the string code points to, but you can make it point to another string. The Remove method of System.String doesn't actually remove anything, it just creates a new string without the unwanted characters and returns a reference to it. This means that instead of
code.Remove(0, 1);
You want:
code = code.Remove(0, 1);
Related
this is the first real program I'm making for school, and I'm having some trouble with it. I believe my case structure and everything else is right, but when I attempt to add two numbers in my calculator, the text property for label 7 does not update.
This is my sample of how I have my case structure set up:
private void radioButton5_CheckedChanged(object sender, EventArgs e)
{
if (radioButton5.Checked == true)
rb = 5;
}
and then the actual case structure itself, as well as the rest of the code:
public void button1_Click(object sender, EventArgs e)
{
double num1 = 0;
double num2 = 0;
double result = 0;
string resultInLabel;
switch (rb)
{
case 1:
result = num1 + num2;
break;
case 2:
result = num1 - num2;
break;
case 3:
result = num1 * num2;
break;
case 4:
result = num1 / num2;
break;
case 5:
break;
}
resultInLabel = Convert.ToString(result);
resultInLabel = label7.Text;
}
button1 is my equals button, forgot to rename it. If more code is needed please let me know, first time posting and unsure how much more context is needed. Thanks for any answers.
If you want to change the text of the label you have to assign a value to it, not read its current value. Make your last line the following:
label7.Text = resultInLabel;
I'm trying to make a hangman game in C#. I've done most of the work. I use dynamic buttons as keyboard. My problem is, that when user clicks on a letter on keyboard that is not present in the word that user should estimate, picturebox should replaced with picturebox2, and if his estimation is again wrong, replace with picturebox3, go on until final picturebox. However, if user estimates the letter correctly, picturebox should not replaced. I tried to do this, but my code does not work, as when I click on a button, picturebox keep changing until the last picture even if my estimation is correct or not. where is my mistake?
Here is the part of my code:
void btn_Click(object sender, EventArgs e)
{
Button btn = (Button)sender;
btn.BackColor = Color.Aqua;
btn.ForeColor = Color.Red;
int a = 0;
// xy is the word that user should estimate
for (int i = 0; i < xy.Length; i++)
{
if (this.Controls.Find("txt" + i, true)[0].Text == btn.Text)
{
this.Controls.Find("txt" + i, true)[0].Text = btn.Text;
this.Controls.Find("txt" + i, true)[0].BackColor = Color.White;
}
else
{
a++;
switch(a)
{
case 1:
pictbx.Image = Image.FromFile("D:/Csharp_Pro/Games/Mine/hangman/hangman/skeleton1.png");
break;
case 2:
pictbx.Image = Image.FromFile("D:/Csharp_Pro/Games/Mine/hangman/hangman/skeleton2.png");
break;
case 3:
pictbx.Image = Image.FromFile("D:/Csharp_Pro/Games/Mine/hangman/hangman/skeleton3.png");
break;
case 4:
pictbx.Image = Image.FromFile("D:/Csharp_Pro/Games/Mine/hangman/hangman/skeleton4.png");
break;
case 5:
pictbx.Image = Image.FromFile("D:/Csharp_Pro/Games/Mine/hangman/hangman/skeleton5.png");
break;
default:
break;
}
}
}
}
First mistake is what Hans mentioned in comments: your variable must be a field of the class and not a local variable on the function, and must reset on each new game.
Second mistake: you check the letter the player clicked against every letter on the word, and for everytime it doesn't match, you add one to your error counter. You must add 1 only after you have finished checking all the letters in your word.
void btn_Click(object sender, EventArgs e)
{
Button btn = (Button)sender;
btn.BackColor = Color.Aqua;
btn.ForeColor = Color.Red;
bool found = false;
// xy is the word that user should estimate
for (int i = 0; i < xy.Length; i++)
{
if (this.Controls.Find("txt" + i, true)[0].Text == btn.Text)
{
this.Controls.Find("txt" + i, true)[0].Text = btn.Text;
this.Controls.Find("txt" + i, true)[0].BackColor = Color.White;
found = true;
}
}
if (!found)
{
a++;
switch(a)
{
case 1:
pictbx.Image = Image.FromFile("D:/Csharp_Pro/Games/Mine/hangman/hangman/skeleton1.png");
break;
case 2:
pictbx.Image = Image.FromFile("D:/Csharp_Pro/Games/Mine/hangman/hangman/skeleton2.png");
break;
case 3:
pictbx.Image = Image.FromFile("D:/Csharp_Pro/Games/Mine/hangman/hangman/skeleton3.png");
break;
case 4:
pictbx.Image = Image.FromFile("D:/Csharp_Pro/Games/Mine/hangman/hangman/skeleton4.png");
break;
case 5:
pictbx.Image = Image.FromFile("D:/Csharp_Pro/Games/Mine/hangman/hangman/skeleton5.png");
break;
default:
break;
}
}
}
It still has a lot of room for improvement, buy I decided to stop here so you can eventually find it out by yourself while you're learning.
I'm an absolute beginner when it comes to C#. Trying to learn via examples. So I've found myself a nice little calculator tutorial. Everything goes fine up to last moment, the code is working, but it doesn't take multi-digit input like 33. There's a bool statement there for turning arithmetic operations on/off and tutorial instructor figured, that we should put bool = false before the number input/button press (in button_Click).
His code looks like this:
public partial class MainWindow : Window
{
double value = 0;
string operation = "";
bool operation_pressed = false;
public MainWindow()
{
InitializeComponent();
}
private void button_Click(object sender, RoutedEventArgs e)
{
if ((tb.Text == "0") || (operation_pressed == true))
tb.Clear();
operation_pressed = false;
Button b = (Button)sender;
tb.Text += "\n" + b.Content.ToString();
}
private void operator_Click(object sender, RoutedEventArgs e)
{
Button b = (Button)sender;
operation = b.Content.ToString();
value = double.Parse(tb.Text);
operation_pressed = true;
equation.Content = value + " " + operation;
}
private void result_Click(object sender, RoutedEventArgs e)
{
equation.Content = "";
switch(operation)
{
case "+":
tb.Text = "\n" + (value + double.Parse(tb.Text)).ToString();
break;
case "-":
tb.Text = "\n" + (value - double.Parse(tb.Text)).ToString();
break;
case "*":
tb.Text = "\n" + (value * double.Parse(tb.Text)).ToString();
break;
case "/":
tb.Text = "\n" + (value / double.Parse(tb.Text)).ToString();
break;
default:
break;
}
}
private void CE_Click(object sender, RoutedEventArgs e)
{
tb.Text = "\n 0";
}
private void C_Click(object sender, RoutedEventArgs e)
{
tb.Clear();
equation.Content = "";
value = 0;
}
}
It compiles nicely. But when I try to input a multidigit number and follow it with a mathematical operator, it throws an exception for value = double.Parse(tb.Text); that states:
When converting string to DateTime, parse the string to take the date before putting each variable into the DateTime object.
I'm so confused right now. There's no DateTime even involved! And I'm 100% positive, everything is like in the tutorial. What's going on? :/
Any help will be appreciated greatly!
EDIT
Screenshot of actual error:
First of all, you're interpreting the debugger incorrectly. This is not the error message:
When converting string to DateTime, parse the string to take the date before putting each variable into the DateTime object.
Notice how it's listed as "Troubleshooting Tips". In the vast majority of cases, you can ignore it. The error message itself is in a language I don't know, so I can't speak to what it says. But a FormatException essentially means that you're trying to parse a value which can't be parsed.
Your screen shot cuts off some information, but what is the value of tb.Text? Is it one of those "+" strings? If so, then that's your problem.
"+" can't be parsed as a numeric value, because "+" isn't a number.
You can make your code a little more resistant to errors by using TryParse instead of Parse. Something like this:
double result;
if (!double.TryParse(tb.Text, out result))
{
// couldn't parse
}
If the if block isn't entered, then result will contain the successfully parsed value. If it is entered, then the value couldn't be parsed. How you handle that situation is up to you. An error message to the user, a default value instead of the parsed value, etc. That's application logic for you to define.
The point is, tb.Text contains a non-numeric value which you're trying to convert into a numeric value. Hence the error.
Try this code in operator_Click event
Button b = (Button)sender;
operation = b.Text;
value = Convert.ToDouble(tb.text)
Several places in my program, the RadioButton matching the selected item has to be checked, and I have a lot of if statements like so:
DataRowView TempRow = (DataRowView)ScheduleDataGrid.SelectedItem;
if (Convert.ToString(TempRow["Bio"]) == "Bio1")
{
BioRB1.IsChecked = true;
}
if (Convert.ToString(TempRow["Bio"]) == "Bio2")
{
BioRB2.IsChecked = true;
}
if (Convert.ToString(TempRow["Bio"]) == "Bio3")
and so on... I want to replace all this with something short and smart.
I tried using the number of the bio to relate to the button like so:
string bioselected = Convert.ToString(TempRow["Bio"]);
int i = Convert.ToInt16(bioselected.Substring(bioselected.Length - 1, 1));
BioRB[i].IsChecked = true;
but doing a BioRB[i] doesn't work, it ignores the [i] and says BioRB does not exist. Any other suggestions?
BioRB[i] is not doing anything like what you think it's doing. All variable references (controls included) have to be well-defined at compile time - you can't refer to a control's name by building a string that matches the name.**
Try creating a list of your radio buttons. Then you can index into the list:
List<RadioButton> radioButtons = new List<RadioButton>()
{
BioRB1,
BioRB2
};
string bioselected = Convert.ToString(TempRow["Bio"]);
int i = Convert.ToInt16(bioselected.Substring(bioselected.Length - 1, 1));
radioButtons[i].IsChecked = true;
** Technically you can do this via reflection, but it's far more complex than what you've tried.
Maybe this will look better:
string caseSwitch = Convert.ToString(TempRow["Bio"]);
switch (caseSwitch)
{
case "Bio1":
BioRB1.IsChecked = true;
break;
case "Bio2":
BioRB2.IsChecked = true;
break;
case "Bio3":
BioRB3.IsChecked = true;
break;
default:
Console.WriteLine("Default case...is optional");
break;
}
Also, try doing what Alybaba726 said and use CellContentClick or something like this:
private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
DataGridView dgv = (DataGridView)sender;
if(e.ColumnIndex == dgv.Columns["Bio"].Index)
{
string bioSelected = dgv.Rows[e.RowIndex].Cells[e.ColumnIndex].Value.ToString();
switch (bioSelected)
{
case "Bio1":
BioRB1.IsChecked = true;
break;
case "Bio2":
BioRB2.IsChecked = true;
break;
case "Bio3":
BioRB3.IsChecked = true;
break;
default:
Console.WriteLine("Default case...this is optional");
break;
}
}
}
The title is only somewhat accurate. I'm trying to do something special with a textbox and the lack of certain events firing is causing some trouble, but I'd also like some general advice of how to do what it is I'm trying to do here. I'm trying to recreate a special textbox that exists on an old access application. It's for entering in a social security number, and when blank it displays ___-__-____.
When you click on any of the spaces it highlights the particular character. If you enter a number, it replaces the _ with that number. If you hit delete or backspace, it just replaces whatever character is highlighted with an _ or a -, depending.
I can sort of recreate this by having a textbox that is readonly and firing a PreviewMouseUp event to call a method that highlights the current cursor position. But since it's readonly it won't fire any KeyUp or KeyDown events to alter the selection. I can get it to do that if I put a KeyUp in the main UI grid, but it only works on KeyUp, so it winds up looking very laggy. Same issue with the PreviewMouseUp, I want it to highlight when the mouse is pressed down, not up, but PreviewMouseDown fires nothing.
I feel like I'm going about this in a messier and messier way. I've described what I want, does anyone have any better ideas of how to accomplish this that isn't super complicated? I want to keep the textbox readonly to allow me to handle the key inputs manually. What I mean is, My original way of formatting this was to simply run a method on KeyUp which checked the length of what you added and format it appropriately (add dashes, etc), but that results in this moment where everything looks unformatted until you release the key. For example, if I press '2' in the middle of the textbox it shifts all of the dashes over by a character until the '2' button is released, and then the formatting is fixed.
Thoughts?
It's funny how long I'd been working on this for now to finally get it, but the key was in AddHandler. For those of you who want a textbox like this, here's how I did it. There's a few messy bits in here, and those are simply to recreate the exact functionality of the access textbox. The most annoying part was implementing the backspace button, since it deletes what's before the selected section. Also, make sure your textbox is IsReadOnly.
In the constructor put:
textBox_ssn.AddHandler(Control.MouseDownEvent, new MouseButtonEventHandler(ClickSS), true);
textBox_ssn.AddHandler(Control.KeyDownEvent, new KeyEventHandler(ButtonSS), true);
Then use these two methods:
public void ClickSS(object sender, EventArgs e)
{
textBox_ssn.SelectionLength = 1;
}
public void ButtonSS(object sender, KeyEventArgs e)
{
bool on_first_char = false;
if (textBox_ssn.SelectionStart == 0) on_first_char = true;
if (e.Key == Key.Right && textBox_ssn.SelectionStart < 10)
{
++textBox_ssn.SelectionStart;
textBox_ssn.SelectionLength = 1; //Without this, it will move around large blocks of selection
if (textBox_ssn.SelectedText == "-") ++textBox_ssn.SelectionStart;
}
else if (e.Key == Key.Left && textBox_ssn.SelectionStart > 0)
{
--textBox_ssn.SelectionStart;
textBox_ssn.SelectionLength = 1;
if (textBox_ssn.SelectedText == "-") --textBox_ssn.SelectionStart;
}
else
{
string temp = "";
switch (e.Key)
{
case Key.D0:
temp = "0";
break;
case Key.D1:
temp = "1";
break;
case Key.D2:
temp = "2";
break;
case Key.D3:
temp = "3";
break;
case Key.D4:
temp = "4";
break;
case Key.D5:
temp = "5";
break;
case Key.D6:
temp = "6";
break;
case Key.D7:
temp = "7";
break;
case Key.D8:
temp = "8";
break;
case Key.D9:
temp = "9";
break;
case Key.Delete:
temp = "_";
break;
case Key.Back:
temp = "_";
if (textBox_ssn.SelectionStart > 0) --textBox_ssn.SelectionStart;
if (textBox_ssn.SelectedText == "-") --textBox_ssn.SelectionStart;
//else return; //or could do temp = selection text but only if selection length is 1 ectect
break;
}
if (temp != "")
{
if (textBox_ssn.SelectionLength > 1)
{
string underscores = "";
foreach (char c in textBox_ssn.SelectedText)
{
if (c == '-') underscores += "-";
else underscores += "_";
}
textBox_ssn.SelectedText = underscores;
textBox_ssn.SelectionLength = 1;
}
if (textBox_ssn.SelectedText == "-") ++textBox_ssn.SelectionStart;
if (textBox_ssn.SelectionLength == 1)
{
if (!(on_first_char && e.Key == Key.Back)) textBox_ssn.SelectedText = temp;
if (e.Key == Key.Delete) ;
else if (e.Key == Key.Back)
{
if (textBox_ssn.SelectionStart > 0)
{
//--textBox_ssn.SelectionStart;
if (textBox_ssn.SelectedText == "-") --textBox_ssn.SelectionStart;
}
}
else
{
++textBox_ssn.SelectionStart;
if (textBox_ssn.SelectedText == "-") ++textBox_ssn.SelectionStart;
}
}
}
}
}
What you are describing is known as a Masked Textbox. There is a free one in the VisualStudioGallery and in the Extended WPF ToolKit