How to know which button of button array is clicked - c#

I have array of buttons, which length is variable that User types in. So I made one eventHandler for all buttons. But I have a problem, I need to know which Button is clicked so I can in eventHandler do something that I want. It's more complicated in my code, but I have summarized it. Actually, I just need index of that button that has been clicked.
public Button[] btn;
public void creatingButtons()
{
btn = new Button[x];
for(int i=0; i<btn.Length; i++){
Controls.Add(btn[i]);
btn[i].Click += new EventHandler(btn_Click);
}
}
private void btn_Click(object sender , EventArgs e)
{
int index;
btn[index].Text = "This is clicked button";
}

the Sender is the object what is being clicked so you can use:
private void btn_Click(object sender , EventArgs e)
{
Button clickedBut = sender as Button;
clickedBut.Text = "This is clicked button";
}

By looking at the documentation (found as ~first result by googling "c# button click")
https://learn.microsoft.com/en-us/dotnet/api/system.web.ui.webcontrols.button.-ctor?view=netframework-4.8
public Button[] btns;
public void createButtons(int count) {
btns = new Button[count];
for (int i=0; i<count; i++) {
btns[i] = new Button()
Controls.Add(btns[i]);
btns[i].Click += new EventHandler(btn_Click);
}
}
private void btn_Click(object sender, EventArgs e) {
Button clickedButton = (Button)sender;
int index = Array.IndexOf(btns, clickedButton);
clickedButton.Text = "...button clicked...";
}
Note that you can cast the sender as a Button, and presumably use Array.IndexOf to find the index.

As other answers have pointed out, you can use sender.
But a better solution would be to add a different click handler for the button. If the click handler needs to do different things for each button, or group of buttons then it's technically a different handler. During the creation of the button, you know the purpose of the button, you have the instance of the button, so make the decision then and add an appropriate handler for it.
This way your code is following OOP principles, has good separation of concerns rather than a bunch of adhoc if-statements patched together as an afterthought.

Related

Getting access to Button parent

I'm using a Button in a class. When the button is pressed, it should call a routine with the button's corresponding text. How do I convert the sender into a String_Entry? Also, I'm quite a newbie regarding object oriented/class programming, so comments are welcome.
public class String_Entry
{
public TextBox textbox;
public Button send;
// other stuff
public String_Entry()
{
textbox = new TextBox();
send = new Button();
send.Click += new System.EventHandler(this.bSend_Click);
// put in GUI, set parameters and other stuff
}
// other stuff
private void bSend_Click(object sender, EventArgs e)
{
// Trying to get the corresponding String_Entry from the Button click event
Button cntrl = (Button)sender;
String_Entry entry = (String_Entry)(cntrl.Parent);
parse.ProcessHexLine(entry);
}
}
Your solution of encapsulating a button with a textbox and the event handler is sound. It just goes wrong in the event handler:
private void bSend_Click(object sender, EventArgs e)
{
Button cntrl = (Button)sender;
String_Entry entry = (String_Entry)(cntrl.Parent);
parse.ProcessHexLine(entry);
}
Firstly, there is no point to doing anything with sender as it'll be the same as the field send. Next cntrl.Parent will give you a reference to the Form, or other container object, that contains the button, not this instance of String_Entry. To access that, use this. So you can change the event handler to:
private void bSend_Click(object sender, EventArgs e)
{
parse.ProcessHexLine(this);
}

Clicking a Button in a button array

I have the code below.
public void WepaonEquip(Object sender, System.EventArgs e)
{
if (button[0].BackColor == Color.Beige)
{
button[0].BackColor = Color.OrangeRed;
}
else if (button[1].BackColor == Color.Beige)
{
button[1].BackColor = Color.OrangeRed;
}
else if (button[2].BackColor == Color.Beige)
{
button[2].BackColor = Color.OrangeRed;
}
}
The code in the class containing this chunk of code generates a button array. What I want is that the user will click a button and the colour of the button clicked will change.
However, when the user clicks, lets say, the 3rd button, the first button in the array changes colour, not the one clicked. Any idea as to why this isn't working? I believe the logic of the code works, perhaps I'm missing something.
Set each button in the panel to use the same Click Event handler. In the handler cast sender as a button and change the color
Assuming that WeaponEquip is the click event handler for the buttons it would look something like this:
public void WepaonEquip(Object sender, System.EventArgs e)
{
Button clickedbutton = (Button)sender
clickedbutton.BackColor = Color.OrangeRed;
}

Referring to programmatically created button and it's click event

I'm absolute beginner when it comes to mono for android.
I've used following code snippet to create 50 buttons programmatically:
for(int i=0;i<50;i++)
{
//code to calculate x and y position
btn=new Button(this);
//btn.SetBackgroundColor(Android.Resource.Color.);
btn.SetTextSize(Android.Util.ComplexUnitType.Sp,8);
btn.Text="Scrip "+i+"\n"+"CMP "+i+"\n"+"%Chg "+i;
lp = new RelativeLayout.LayoutParams(new ViewGroup.MarginLayoutParams((width+30)/5, (height-10)/10));
btn.LayoutParameters=lp;
lp.SetMargins(leftMargin,topMargin, 0, 0);
main.AddView(btn);
}
String str="";
btn.Click += (sender, e) =>
{
str=btn.Text;
Toast.MakeText(this, "Selected="+str,ToastLength.Short).Show();
Console.WriteLine("Selected="+str);
};
But one big problem with this code is at the end of the loop, btn object has reference of the last button only.
So if any button other than last button is pressed, button click event is not fired.
How to resolve it?
Ideally, it should return the text of the clicked button.
Also, referring to below screenshot, the default button style doesn't look good here. So I want to change it to exact rectangle and not rounded-rectangel(the default one).
Any idea on this?
As I'm very new to this, any help will be appreciated !!
EDIT
Asa result of your help, I'm able to create and refer all buttons appropriately.
But how to set their style as exact rectangle??
Move btn.Click += (sender, e) subscription inside for loop.
Even better - create one named method instead of creating many anonymous. E.g. Button_Click and subscribe to it:
btn = new Button(this);
btn.Click = Button_Click;
Inside that method you can cast sender object to Button and know which button was clicked.
UPDATE: here is complete code
const int rowsCount = 10;
const int columnsCount = 5;
int buttonsCount = rowsCount * columnsCount;
for (int i = 0; i < buttonsCount; i++)
AddButton();
I prefer not to use magic numbers in code :)
private void AddButton()
{
Button button = new Button(this);
button.Click += Button_Click;
// add text and other properties
main.AddView(button);
}
private void Button_Click(object sender, EventArgs e)
{
Button button = (sender as Button);
// use clicked button e.g. Console.WriteLine("Selected = {0}", button.Text);
}
Your for loop operates on a button and creates a new instance of it every time, but your click event is only added once (it is outside your for loop). Therefore it will only be added to the last instance of Button that is put into btn (the last button from the for loop).
You need to either create each button separately (putting them in a List say) and then outside the for loop you will have a reference to each that you can add the click event to each button individually. Or (the much better way) add the click event inside the for loop, so that each button you create adheres to it. Bear in mind that since the event will then be reached by an arbitrary button(one of your 50) that it will be best to use the sender parameter to determine its text value.
i.e.:
btn.Click += (sender, e) =>
{
Button b = sender as Button;
if ( b == null ) return;
String str;
str=b.Text;
Toast.MakeText(this, "Selected="+str,ToastLength.Short).Show();
Console.WriteLine("Selected="+str);
};
You have created 50 buttons, so you need to have 50 references to it. The easiest way to achieve this is to create an array of buttons, like so:
Button[] btns = new Button[50];
for(int i=0;i<50;i++)
{
{
//code to calculate x and y position
btns[i]=new Button(this);
//btn.SetBackgroundColor(Android.Resource.Color.);
btns[i].SetTextSize(Android.Util.ComplexUnitType.Sp,8);
btns[i].Text="Scrip "+i+"\n"+"CMP "+i+"\n"+"%Chg "+i;
lp = new RelativeLayout.LayoutParams(new ViewGroup.MarginLayoutParams((width+30)/5, (height-10)/10));
btns[i].LayoutParameters=lp;
lp.SetMargins(leftMargin,topMargin, 0, 0);
main.AddView(btn);
}
btns[i].Click += (sender, e) =>
{
String str= ( (sender as Button) != null) ? (sender as Button).Content.ToString() : "";
Toast.MakeText(this, "Selected="+str,ToastLength.Short).Show();
Console.WriteLine("Selected="+str);
}
}
//EDIT: You'll also need to create an eventhandler for each button
it's because you are setting the button click event outside the for loop. put it on the inside so it gets assigned to every button, not just the last one.

Events and Buttons

I want to get the text of the button whenever I click on it.
The algorithm that I made is where i have a function that is a loop that creates a number of buttons and assigns numbers:
void ListAllPage()
{
if (pageMax < 50)
{
//if page max less than 50
for (int i = 0; i < pageMax; i++)
{
Button newBtn = new Button();
newBtn.Text = i.ToString();
newBtn.Width = 50;
newBtn.Click += page_Clicked;
pageCell.Controls.Add(newBtn);
}
}
}
Now buttons will appear on the screen, their events will be triggered and the function page_Click; will be executed:
public void page_Clicked(object sender, EventArgs e)
{
//inside this function I want to obtain the button number that was clicked by the user. How do I do that?
}
Take note, I must all the functions that I described here,...
My thinking is to feed all the buttons that i created inside the loop to a dictionary..
Dictionary.. it will take variables like this btndic.Add(Button b=new Button,b.text);
But the issue is how to retrieve the buttons,,,
if there is a better way, i would like to hear about it...
instead of using the Click Event -> Use the Command Event: http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.button.oncommand.aspx then you can distinguish which button has been clicked
You just need to cast the sender object to a Button, or more generally, a Control:
public void page_Clicked(object sender, EventArgs e)
{
Control c = sender as Control;
MessageBox.Show("Clicked on " + c.Text);
}
Also, it might be more appropriate to use the Tag property to store your custom information (number). In that case, Text property can be anything you like.
Try this way
public void page_Clicked(object sender, EventArgs e)
{
Button btn=(Button)sender;
}
in your ListAllPage method assign Tag to each button:
newBtn.Tag = i;
In your handler you can obtain button instance from sender:
var clickedButton = (Button)sender;
int pageIndex = (int)clickedButton.Tag;

Button id as an event handler

I am creating 7 buttons on the fly
when i create the buttons i am trying to have an event handler than can deal with all clicks in one method via a switch. Ideally i want to pass an id with the button that indicates what was clicked, opposed to this solution of
void pdfButton_Click(object sender, EventArgs e)
{
Button b = (Button)sender;
Console.WriteLine(b.Text);
}
as all of the buttons using this event handler have the same text. I have a unique id associated witht the buttons but no idea how to send them
thanks
You can use the Name or Tag properties.
Put the ID in the Tag property on the button when you create them and then check the ID in your event handler.
Button button = new Button();
button.Tag = 1;
...
void pdfButton_Click(object sender, EventArgs e)
{
Button b = (Button)sender;
switch ((int)b.Tag)
{
...
}
}
First: Bad practice to handle several clicks in one event via switch. But however a solution would be:
Create your own control which inherits the button and ad your ID as an property. So you can access it via:
MyButton b = (MyButton)sender;
switch(b.ID) {
//Code goes here
}
If each button you add has a unique Id, why not just use the ID property of the button?
Button button = new Button();
button.ID= "Button1";
//...
void pdfButton_Click(object sender, EventArgs e)
{
Button b = (Button)sender;
switch(button.ID)
{
case "Button1":
//...
}
}

Categories