I'm trying to fix a computer program in C# for the game MasterMind. Right now, there is a lot of unnecessary code for the buttons. I know i can put them all into one method but i don't know how. Here is some of the code. Please help.
private void button1_Click(object sender, EventArgs e)
{
this.ActiveControl.BackColor = controlColor;
this.ActiveControl.Text = controlNumber;
allCellsClicked[0] = '1';
if (all_Buttons_Clicked())
{
allCellsClicked[0] = '0';
allCellsClicked[1] = '0';
allCellsClicked[2] = '0';
allCellsClicked[3] = '0';
button04.Enabled = false;
button03.Enabled = false;
button02.Enabled = false;
button01.Enabled = false;
guess++;
Label1.Text = "Guess Number " + Convert.ToString(guess);
label4.Visible = true;
label5.Visible = true;
label4.Text = "0";
label5.Text = "0";
int a = int.Parse(button01.Text), b = int.Parse(button02.Text), c = int.Parse(button03.Text), d = int.Parse(button04.Text);
int rightCol, rightPos;
CheckAnswer(a, b, c, d, out rightPos, out rightCol);
label4.Text = rightCol.ToString();
label5.Text = rightPos.ToString();
If what you are saying is that all of the buttons execute essentially the same code but it is copied multiple times, then you can look to the place where each button's click event is being hooked up to each of their event handlers and point them all to the same method.
Somewhere (probably in your filename.Designer.cs), you have something like this:
button1.Click += new EventHandler(button1_click);
To change this, you can make each of them like this (note that this does not need to be put in the Designer.cs file and that it is not recommended to manually edit this file):
button1.Click += new EventHandler(button_click);
button2.Click += new EventHandler(button_click);
button3.Click += new EventHandler(button_click);
button4.Click += new EventHandler(button_click);
...
where you have a method defined like this:
private void button_Click(object sender, EventArgs e)
{
// stuff that happens when a button is clicked
}
This will make all of the buttons use the same button_click event handler. If you need to know which button fired the event, you can check the sender's id:
Button buttonThatClicked = sender as Button;
if (buttonThatClicked != null)
{
// do whatever you need to, based on the button's properties
}
If you have duplicate code in several button_click methods just create a separate method and have the button_click methods call it.
private void button1_Click(object sender, EventArgs e)
{
this.ActiveControl.BackColor = controlColor;
this.ActiveControl.Text = controlNumber;
allCellsClicked[0] = '1';
checkGuess();
}
private void button2_Click(object sender, EventArgs e)
{
this.ActiveControl.BackColor = controlColor;
this.ActiveControl.Text = controlNumber;
allCellsClicked[0] = '2';
checkGuess();
}
private void checkGuess(){
if (all_Buttons_Clicked())
{
allCellsClicked[0] = '0';
allCellsClicked[1] = '0';
allCellsClicked[2] = '0';
allCellsClicked[3] = '0';
button04.Enabled = false;
button03.Enabled = false;
button02.Enabled = false;
.....
}
You can just associate the same Click event callback function with every button's Click event. You can do this via code or you can do this via the Properties pane. Simply select each button and then pick the same event handler for each one.
In your case, if you want every button to use the button1_Click event, then associate that button1_Click event with each button. If you do that, you might want to rename the event callback function to something more generic.
Related
public Form1()
{
InitializeComponent();
}
Random g = new Random();
bool b = false;
private void button_click(object sender, EventArgs e)
{
Button button= sender as Button;
b=true;
}
private void Form1_Load(object sender, EventArgs e)
{
button1.Click += button_click;
button2.Click += button_click;
button3.Click += button_click;
button4.Click += button_click;
button5.Click += button_click;
button6.Click += button_click;
button7.Click += button_click;
button8.Click += button_click;
button9.Click += button_click;
button10.Click += button_click;
button11.Click += button_click;
button12.Click += button_click;
button13.Click += button_click;
button14.Click += button_click;
button15.Click += button_click;
button16.Click += button_click;
button17.Click += button_click;
button18.Click += button_click;
button19.Click += button_click;
button20.Click += button_click;
button21.Click += button_click;
button23.Click += button_click;
button24.Click += button_click;
button25.Click += button_click;
button26.Click += button_click;
StreamReader sr = new StreamReader(#"C:\Users\victus-pc\OneDrive\Desktop\notepad1.txt");
int i;
string s = sr.ReadToEnd();
string[] t = s.Split(',');
int l = g.Next(t.Length);
Label[] l1 = new Label[t[l].Length];
for (i = 0; i < l1.Length; i++)
{
l1[i] = new Label();
l1[i].Size = new Size(30, 30);
l1[i].Left = 20 + 50 * i;
l1[i].Top = 20;
l1[i].Text = t[l][i].ToString();
l1[i].Visible = false;
this.Controls.Add(l1[i]);
}
if (b)
{
for (i = 0; i < l1.Length; i++)
{
if (button.Text.Equals(l1[i].Text))
{
l1[i].Visible = true;
}
else
label2.Text = (int.Parse(label2.Text) - 1).ToString();
break;
}
if (int.Parse(label2.Text) == 0)
MessageBox.Show("Game Over");
b = false;
}
}
I'm a beginner in programming,so please take that into consideration.
I'm trying to create a Hangman game using C# (WindowsForm).
My problem is in if (button.Text.Equals(l1[i].Text)); it gives me an error that is : "The name "button" does not exist in the current context", though i declared it as name in Button button= sender as Button;.
Another problem is that in a previous Hangman project, i tried another way but same concept that is to use bool b like here,and if the user clicked on a button,Form 1knows that bbecomes true and doesn't stay false.
But that doesn't happen, because Form1 loads before i click on a button,so even if b becomes true,it cannot load the Form1 again because a form can only be created once ,once we run the program.
So what should i do to fix these 2 problems?
There's not enough info here to be certain, so making some assumptions that all the buttons created in form designer with one for each letter of the alphabet and the user has as many tries as he wants until answer is revealed.
The issue is that you are testing for button click (if (b)) in the form Load event, which fires once and before any buttons have been pressed, so won't work.
I would suggest you declare Label[] l1; where you currently declare bool b = false; - that makes is accessible in the button_click event. You don't need b anyway so remove it.
Then change your Button Click event handler to this:
private void button_click(object sender, EventArgs e)
{
Button button= sender as Button;
for (int i = 0; i < l1.Length; i++)
{
if (button.Text.Equals(l1[i].Text))
{
l1[i].Visible = true;
}
else label2.Text = (int.Parse(label2.Text) - 1).ToString(); // Not sure what label2 is, so not sure if this is correct.
}
if (int.Parse(label2.Text) == 0) MessageBox.Show("Game Over");
}
I haven't created a working example, so can't be sure this will work as-is, but should help. I would have made it a comment, but couldn't quote code that way.
Your question is "how to let Form load recognize the name of the button in the event handler of 26 buttons". You also mention that when you click on buttons your objective is to change the states of bool values for your game.
One easy way to do the second thing is to use a Checkbox that looks like a button by setting its Appearance property to Button. Whether you end up using buttons or checkboxes (that look like buttons), one way to simplify your Load event handler is to iterate all the controls in your MainForm as shown below. This example will show how to not only recognize the Name of the control, but also use that name to automatically generate the characters of the alphabet that you require for the game setup and along the way add an event to handle the button when the user clicks.
Here's a view of a TableLayoutPanel in the designer window that holds 26 checkboxes.
This method will visit each and every control on your Form, calling the initCheckBox method on each one.
public MainForm() => InitializeComponent();
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
// This will call initCheckBox() for every Control of the `MainForm`.
IterateControlTree(null, initCheckBox, null);
}
internal delegate bool FxControlDlgt(Control control, Object args);
// Iterate the control tree with 'some function' generically known as `fX`.
internal bool IterateControlTree(Control control, FxControlDlgt fX, Object args)
{
if (control == null) control = this;
if (!fX(control, args)) return false;
foreach (Control child in control.Controls)
{
if (!IterateControlTree(child, fX, args))
{
return false;
}
}
return true;
}
The specific fX that we'll pass is going to set the text by looking at the control name, extracting the integer from it, and converting the integer to a character. We'll also assign a Click handler to each checkbox.
private bool initCheckBox(Control control, object args)
{
// This is called for every control, so filter for CheckBox only.
if (control is CheckBox checkbox)
{
// One way to autogenerate the Text from the Name property.
string sval = checkbox.Name.Replace("checkBox", string.Empty);
if(int.TryParse(sval, out int offset))
{
char c = (char)('A' + (offset - 1));
checkbox.Text = c.ToString();
}
checkbox.Click += onAnyClick;
}
return true;
}
Here's what the `MainForm' looks like now when the program is run:
What you can do is take this generic functionality of the Click handler and extend it to perform the functionality you need for your game. As a Minimal Reproducible Example of how one would go about doing this, let's implement onAnyClick by displaying the new bool value on the main form title bar:
private void onAnyClick(object sender, EventArgs e)
{
if (sender is CheckBox checkbox)
{
Text = $"{checkbox.Text} = {checkbox.Checked}";
}
}
After clicking on "button" T, the title bar display as follows:
I am trying to creat a dynamic button in a my application. So basically I have this code but when I run it I don’t see the bottom in the other form . The panel is empty. I create the bottom on a button click in a first form then it has to show the button in the second form’s panel.
private void btnsend_Click(object sender, EventArgs e)
{
this.Hide();
Form wrr = new Interface();
wrr.Show();
createnutton();
}
int i = 0;
int x = 0;
private void createnutton()
{
Button btn = new Button();
btn.Location = new Point(3 + i, 14 + x);
btn.BackColor = System.Drawing.Color.Red;
btn.ForeColor = System.Drawing.Color.Yellow;
btn.Text = "Tabel" + libtno.Text;
btn.Click += new EventHandler(btn_Click);
panel3.Controls.Add(btn);
i += 10;
x += 10;
}
void btn_Click(object sender,EventArgs e)
{
MessageBox.Show("me");
}
You have to set one more property "Visible=true" for your Button.
You need a reference to the instance of Interface that you created. Pass wrr to your createnutton function. For this to work, you have to change the MODIFIERS property of panel3 to PUBLIC. You also can't reference the Form with the generic Form type. It has to be of that specific Form type, which is Interface (a horrible name by the way, since interface has different meaning in C#):
private void btnsend_Click(object sender, EventArgs e)
{
this.Hide();
Interface wrr = new Interface();
wrr.Show();
createnutton(wrr); // <-- pass "wrr" to the function
}
int i = 0;
int x = 0;
private void createnutton(Interface frmInterface) // <-- parameter added
{
Button btn = new Button();
btn.Location = new Point(3 + i, 14 + x);
btn.BackColor = System.Drawing.Color.Red;
btn.ForeColor = System.Drawing.Color.Yellow;
btn.Text = "Tabel" + libtno.Text;
btn.Click += new EventHandler(btn_Click);
frmInterface.panel3.Controls.Add(btn); // <-- use the passed in form
i += 10;
x += 10;
}
BUT...this seems like a horrible design. I wouldn't do this if I were personally writing from the ground up.
I have a grid with 9 buttons. In the timer tick event a random button is higlighted. If one clicks the higlighted button, a dynamic click event is created and within the click event the button is marked with a different color. The counterHits variable in the dynamic button click event is supposed to keep track of the highlighted buttons that were hit. Sometimes though it increases the variable more than by one. I cannot figure out why this is happening. Any help anyone?
public partial class Form1 : Form
{
const int buttons = 9;
int counterHits;
int counterTicks;
int currentIndex;
int lastIndex;
bool hit = false;
Random r;
Timer timerGameLoop;
Timer timerUpdateUI;
public Form1()
{
InitializeComponent();
timerGameLoop = new Timer();
timerGameLoop.Interval = 1000;
timerGameLoop.Tick += t_Tick;
timerUpdateUI = new Timer();
timerUpdateUI.Interval = 10;
timerUpdateUI.Tick += timerUpdateUI_Tick;
r = new Random();
}
// set up the grid and start
private void btnStart_Click(object sender, EventArgs e)
{
for (int i = 0; i < buttons; i++)
{
var b = new Button();
b.Size = new Size(100, 100);
b.Margin = new Padding(0);
b.BackColor = Color.White;
flowLayoutPanel.Controls.Add(b);
}
timerGameLoop.Start();
timerUpdateUI.Start();
}
// tick event ui update loop
void timerUpdateUI_Tick(object sender, EventArgs e)
{
lblHitCounter.Text = "hits : " + counterHits.ToString();
lblTickCounter.Text = "ticks : " + counterTicks.ToString();
}
// tick event game loop
void t_Tick(object sender, EventArgs e)
{
// reset to white background if not clicked
if (!hit)
flowLayoutPanel.Controls[lastIndex].BackColor = Color.White;
// highlight button to be clicked
currentIndex = r.Next(buttons);
lastIndex = currentIndex;
flowLayoutPanel.Controls[currentIndex].BackColor = Color.Violet;
// highligted button clicked
flowLayoutPanel.Controls[currentIndex].Click += b_Click;
hit = false;
counterTicks++;
}
// highlighted button clicked event
void b_Click(object sender, EventArgs e)
{
var b = (Button)sender;
b.BackColor = Color.Olive;
hit = true;
counterHits++;
b.Click -= b_Click;
}
}
The following lines attaches b_Click to your button. That eventhandler is only removed if you press the button
flowLayoutPanel.Controls[currentIndex].Click += b_Click;
See the implementation of b_Click
// highlighted button clicked event
void b_Click(object sender, EventArgs e)
{
//Stugg
b.Click -= b_Click;←Removed Here only if it is pressed
}
This line indicates that some buttons have more than one EventHandler attached. Therefore when you click the button eventhandler runs more than once.
I am trying to figure out how to use a click event handler for my 4 buttons that I have generated dynamically without putting any code in page init or oninit. I have one button that once clicked it generates 4 more buttons. The click event handler for these 4 buttons is not working. Here is the code. Has anybody figured out a way to use the click events in asp.net c# without first putting it in page_load? If I can solve this problem, I can solve my real problem in a bigger scenario.:
protected void Page_Load(object sender, EventArgs e)
{
}
protected void Button1_Click(object sender, EventArgs e)
{
for (int i = 0; i < 4; i++)
{
Button b = new Button();
b.ID = i.ToString();
b.Text = "ClickMe";
b.Visible = true;
b.Click += new EventHandler(b_click);
PlaceHolder1.Controls.Add(b);
}
}
void b_click(object sender,EventArgs e)
{
Label1.Text = "ok";
}
Make sure the ID of your dynamic controls include a distinct keyword. In my example below I prepended "DYNAMIC_" to their ID. Then override OnPreRender() like this:
protected override void OnPreRender(EventArgs e)
{
if (Page.IsPostBack && !IsPostBackEventControlRegistered)
{
var controlName = this.Request.Form.AllKeys.SingleOrDefault(key => key.Contains("DYNAMIC_"));
processEventForDynamicControl(controlName);
}
base.OnPreRender(e);
}
private void processEventForDynamicControl(string controlName)
{
//Do your dynamic button click processing here
}
Of course, if your dynamic controls use doPost() (which sadly Button doesn't) you can retrieve the control directly from __EVENTTARGET like this:
var controlName = Request.Params.Get("__EVENTTARGET")
You want to load controls inside Page_Load. Otherwise, they are not in control tree, and they won't be able to trigger b_click event.
public int Counter
{
get { return (int?) ViewState["Counter"] ?? 0; }
set { ViewState["Counter"] = value; }
}
protected void Page_Load(object sender, EventArgs e)
{
var counter = Counter;
for (int i = 0; i < counter; i++)
{
Button b = new Button();
b.ID = i.ToString();
b.Text = "ClickMe";
b.Visible = true;
b.Click += b_click;
PlaceHolder1.Controls.Add(b);
}
}
protected void Button1_Click(object sender, EventArgs e)
{
Counter = 4;
for (int i = 0; i < 4; i++)
{
Button b = new Button();
b.ID = i.ToString();
b.Text = "ClickMe";
b.Visible = true;
b.Click += b_click;
PlaceHolder1.Controls.Add(b);
}
}
void b_click(object sender, EventArgs e)
{
Label1.Text = "ok";
}
Note: If you plan to load inside Page_Init, you want to use Session instead of ViewState.
Basically I got it working.There is no way around it. You have to use Oninit or Page_load and put your b.Click += new EventHandler(b_click) code there in addition to the PlaceHolder1.Controls.Add(b); there as well,for the event handler to register properly with the button. The problem with this method is that it places the button on top of the PlaceHolder portion of the web page which is not what I want. I want to beable to place the button at a particular position in the web page. So how do you go around doing this? Basically after the PlaceHolder1.Controls.Add(b) simply make the button invisible. Then in the when you are ready to place the button in a particular part of your html call PlaceHolder1.Controls.Add(b) again and make it visible. That works for me. If anyone needs help with this I can post some sample code and you can test it for yourself. Thanks all.
I have a class that creates panels with controls based on my database. It creates a panel with a button on each panel, per row in DB. How do I address one specific button to make a click event?
I'm a rookie, and maybe abit over my head, but you don't learn to swim in shallow water ;)
Any help appreciated!
while (myDataReader.Read())
{
i++;
Oppdrag p1 = new Oppdrag();
p1.Location = new Point (0, (i++) * 65);
oppdragPanel.Controls.Add(p1);
p1.makePanel();
}
class Oppdrag : Panel
{
Button infoBtn = new Button();
public void makePanel()
{
this.BackColor = Color.White;
this.Height = 60;
this.Dock = DockStyle.Top;
this.Location = new Point(0, (iTeller) * 45);
infoBtn.Location = new Point(860, 27);
infoBtn.Name = "infoBtn";
infoBtn.Size = new Size(139, 23);
infoBtn.TabIndex = 18;
infoBtn.Text = "Edit";
infoBtn.UseVisualStyleBackColor = true;
}
}
You'll need a method that matches the event thrown by clicking on the button.
i.e.)
void Button_Click(object sender, EventArgs e)
{
// Do whatever on the event
}
Then you'll need to assign the click event to the method.
p1.infoBtn.Click += new System.EventHandler(Button_Click);
Hope this helps.
You can add the event handler for the button when you create the button. You can even add a unique CommandArgument per button so you can distinguish one button from another.
public void makePanel()
{
/* ... */
infoBtn.UseVisualStyleBackColor = true;
infoBtn.Click += new EventHandler(ButtonClick);
infoBtn.CommandArgument = "xxxxxxx"; // optional
}
public void ButtonClick(object sender, EventArgs e)
{
Button button = (Button)sender;
string argument = button.CommandArgument; // optional
}