Events and Buttons - c#

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;

Related

Grabbing the textbox label

Hello im making my first project with about 10 different textboxes where the user puts data in. when he/she clicks the the textbox the textbox text clears and a virtual numpad form pops up and when he leaves the textbox the numpad "hides".
right now (or i would) i have 2 events for every textbox, a click event and a leave event,
private void sheetWidthBox_Enter(object sender, EventArgs e)
{
vnumPadForm.Location = PointToScreen(new Point(sheetWidthBox.Right, sheetWidthBox.Top));
vnumPadForm.Show();
}
Im sure there is a way of dynamically coding that in one event and just grabbing the label name. i have played around with it a bit on my numpad like this and it works good;
private void button_Click(object sender, EventArgs e)
{
Button b = (Button)sender;
string num = b.Text;
SendKeys.SendWait(num);
}
Like that but instead i want to get the label name
right now (or i would) i have 2 events for every textbox, a click event and a leave event,
it works but very inefficient.
Change the name of the handler to something generic like "anyBox_Enter()", and update to the code below:
TextBox curTextBox = null;
private void anyBox_Enter(object sender, EventArgs e)
{
curTextBox = sender as TextBox;
vnumPadForm.Location = PointToScreen(new Point(curTextBox.Right, curTextBox.Top));
vnumPadForm.Show();
}
Note that I added a class level variable called "curTextBox" that gets set from the generic handler! This will track whatever TextBox was entered last.
Now, one by one, select each TextBox on your Form that you want to wire up to this common handler. After selecting each one, in the Properties Pane, click on the "Lightning Bolt" Icon to switch to the events for that control if they are not already showing. Find the "Enter" entry and change the dropdown to the right so that it says "anyBox_Enter".
Then in your button click handlers you can use the "curTextBox" variable to know where to send the key:
private void button_Click(object sender, EventArgs e)
{
Button b = (Button)sender;
string num = b.Text;
if (curTextBox != null) {
curTextBox.Text = num; // or possibly APPEND this to the TB?
}
}

How to know which button of button array is clicked

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.

Registering one click event for multiple buttons and passing a different value per button

I procedurally generate buttons based on what is in a list, this list contains file paths. I need each button to open the specific file from the path using:
System.Diagnostics.Process.Start(filePath)
However, the button.Click = requires the function it runs to be System.EventHandlerwhereas the code to open the file is a System.Diagnostics.Process.
Below is the code which generates the buttons:
private int importButtonFactory()
{
int numberOfButtons = 0;
int top = 70;
int left = 100;
foreach (Import import in ImportList)
{
Button button = new Button();
button.Left = left;
button.Top = top;
this.Controls.Add(button);
top += button.Height + 2;
numberOfButtons++;
button.Text = import.Scheme;
button.Click += openFile_Click(import.Path);
}
return numberOfButtons;
}
The function for button.Click "openFile_Click()":
private void openFile_Click(string filePath)
{
System.Diagnostics.Process.Start(filePath);
}
This is what I initially thought would simply work, but but function in the previous function complains with error: "Cannot implicitly convert type 'void' to 'System.EventHandler'" If I make the function of that type to try and please it says the function doesn't return any values.... which I don't want it do, but System.EventHandler seems to need it to.
I'm not sure if there is any dummy data I can have it return as System.EventHandler just to shut it up, or of there is a proper way I don't know of to get my scenario to work.
Edit: This is a Windows Form Application
Your event handler must match the event signature. So your button click handler must use this signature:
private void Button_Click(object sender, System.EventArgs e)
{
}
Now to identify which URL belongs to which button, you can give the button a Tag, for example holding the list index, assuming it is a List<T> or another indexable collection:
for (int i = 0; i < ImportList.Count; i++)
{
// ...
button.Text = ImportList[i].Scheme;
button.Tag = i;
button.Click += Button_Click;
}
Then in your click handler:
private void Button_Click(object sender, System.EventArgs e)
{
Button button = sender as Button;
int index = (int)button.Tag;
var import = ImportList[index];
Process.Start(import.Path);
}
You can use a lambda expression to do something like this:
button.Click += (object sndr, EventArgs c_args) => openFile_Click(import.Path);
This code works. However, the compiler will give you a warning that you are accessing the foreach loop variable (import) in closure. To fix this, create a local variable like this:
var path = import.Path;
button.Click += (object sndr, EventArgs c_args) => openFile_Click(path);

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.

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