Easy way to identify button and auto load its target - c#

I have this portion of code
przyciski[i] = new Button();
przyciski[i].Visible = false;
przyciski[i].Name = "przycisk" + i;
przyciski[i].Click += new System.EventHandler(ButtonClickHandler);
which is describing dynamicly created button, and this eventhandler underneath the program
private void ButtonClickHandler(object sender, EventArgs e)
{
Button btn = (Button)sender;
if(btn.Name == "przycisk1")
{
//Open specific JPEG in external aplication
}
}
Is there any quicker way to identify button and its target?

Here's another option. If you're going to perform a different piece of code for every button anyway, why bother giving them a name and then having to detect the name in the click event?
Just create your buttons, and then specify what each should do.
var przyciski = new List<Button>();
for (var i = 0; i < 5; i++)
przyciski.Add(new Button { Visible = false });
przyciski[0].Click += (s, e) => { /* Do something */ };
przyciski[1].Click += (s, e) => { /* Open specific JPEG in external aplication */ };
przyciski[2].Click += (s, e) => { Console.WriteLine("You clicked button 2."); };
przyciski[3].Click += (s, e) => { };
przyciski[4].Click += (s, e) => { };

If przyciski is an instance variable, you can check for reference equality:
private void ButtonClickHandler(object sender, EventArgs e)
{
if (sender == przycisk[1])
{
//Open specific JPEG in external aplication
...
}
...
}

Related

C# VS - When one radio button is checked, uncheck another

I have a form, on which i placed 2 radio buttons. My issue is I need it to function in a way where if one is clicked, the other will be unclicked. I have the following code however it gets stuck in an inifinite loop once you do the first click and I do understand why. Wanted to see if any of you guys know how to go about making this in c#? I'm fairly new to c#
public partial class Form1 : Form
{
public Form1()
{
radAllCols.CheckedChanged += new EventHandler(this.radAllCols_Checked);
radSelCols.CheckedChanged += new EventHandler(this.radSelCols_Checked);
}
private void radAllCols_Checked(object sender, EventArgs e)
{
if (radAllCols.Checked == true)
{
radAllCols.Checked = false;
radSelCols.Checked = true;
}
}
private void radSelCols_Checked(object sender, EventArgs e)
{
if (radSelCols.Checked == true)
{
radSelCols.Checked = false;
radAllCols.Checked = true;
}
}
}
If the radio buttons have different RadioGroup values you have to first, unregister the Checked event, change the Checked property value and re-register the Checked event.
private void radAllCols_Checked(object sender, EventArgs e)
{
if (radAllCols.Checked == true)
{
radAllCols.CheckedChanged -= new
EventHandler(this.radAllCols_Checked);
radSelCols.CheckedChanged -= new
EventHandler(this.radSelCols_Checked);
radAllCols.Checked = false;
radSelCols.Checked = true;
radAllCols.CheckedChanged += new
EventHandler(this.radAllCols_Checked);
radSelCols.CheckedChanged += new
EventHandler(this.radSelCols_Checked);
}
}
private void radSelCols_Checked(object sender, EventArgs e)
{
if (radSelCols.Checked == true)
{
radAllCols.CheckedChanged -= new
EventHandler(this.radAllCols_Checked);
radSelCols.CheckedChanged -= new
EventHandler(this.radSelCols_Checked);
radSelCols.Checked = false;
radAllCols.Checked = true;
radAllCols.CheckedChanged += new
EventHandler(this.radAllCols_Checked);
radSelCols.CheckedChanged += new
EventHandler(this.radSelCols_Checked);
}
}
The code above is for very custom scenarios and should be avoided as much as possible. The radio boxes should behave the way you want automatically. Make sure you have the same RadioGroup property value on both of them.
RadioButtons placed in the same parent control (like a panel) behave this way by default.
There is no need to use a checked event for this.
Setting values of the radAllCols.Checked = true property fires the radAllCols_Checked event this causes your infinite "loop"
Since you are trying to uncheck the same radioButton to checked
private void radSelCols_Checked(object sender, EventArgs e)
{
if (radSelCols.Checked == true)
{
radSelCols.Checked = false; // reversed
radAllCols.Checked = true; // reversed
}
}
If you use GroupBox Container Element for same Radio Buttons that you want select one of them, you don`t need handle check state of Radio Buttons manually, When you select a Radio Button all the other Radio Buttons in the same group will be unchecked.
Your rest of the code is fine but you need to change your code in Checked methods() as mentioned below to prevent infinite loop and then it will work fine:
private void radAllCols_Checked(object sender, EventArgs e)
{
radAllCols.Checked = !radSelCols.Checked;
}
private void radSelCols_Checked(object sender, EventArgs e)
{
radSelCols.Checked = !radAllCols.Checked;
}

How to dynamically create buttons and add events to them?

I have array of buttons, and array of labels:
Label[] labels = new Label[10];
Button[] but = new Button[10];
While clicking the other button I want to dynamically create new button and new label from the array, i also want the but[i] to change the tex of labels[i]:
private void button1_Click(object sender, EventArgs e)
{
labels[i] = new Label();
labels[i].Location = new System.Drawing.Point(0, 15+a);
labels[i].Parent = panel1;
labels[i].Text = "Sample text";
labels[i].Size = new System.Drawing.Size(155, 51);
labels[i].BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
a = labels[i].Height + labels[i].Top;
but[i] = new Button();
but[i].Text = "-";
but[i].Location = new System.Drawing.Point(0, labels[i].Height + labels[i].Top);
but[i].Parent = panel1;
but[i].Size = new System.Drawing.Size(155, 10);
but[i].Click += new System.EventHandler(but_Click);
i++;
}
private void but[i]_Click(object sender, EventArgs e)
{
labels[i].Text = "Changed Text";
}
But apparently I can't put an array in an event handler, how should I do it then?
One way to do this is to make your method return a handler instead of being a handler:
private EventHandler but_Click(int i)
{
return (s, e) => labels[i].Text = "Changed Text";
}
And use it like:
but[i].Click += but_Click(i);
Or do it inline:
but[i].Click += (s, ea) => labels[i].Text = "Changed Text";
What's happening in either of these is some compiler magic to capture the i variable. It's equivalent to this (which is also a valid, if verbose, way to do it):
class MyWrapper {
private int i;
public MyWrapper(int i) {
this.i = i;
}
public void TheHandler(object sender, EventArgs e) {
// TODO: capture the object that owns `labels` also, or this won't work.
labels[i].Text = "Changed Text";
}
}
//call with
but[i].Click += new EventHandler(new MyWrapper(i).TheHandler);
You could add the array index to the button as Tag property, and then pull it back out in but_Click.
So, add
but[i].Tag = i;
to the button creation. And then change the event handler:
private void but_Click(object sender, EventArgs e)
{
int buttonIndex = (int)((Button)sender).Tag;
labels[buttonIndex].Text = "Changed Text";
}
Or put the event handler inline:
but[i].Click += (s,e) => { label[i].Text = "Changed Text"; }
Or another option using the Tag property, add:
but[i].Tag = label[i];
...
private void but_Click(object sender, EventArgs e)
{
Label label = (Label)((Button)sender).Tag;
label.Text = "Changed Text";
}
Advantage of this approach is you're not relying on keeping arrays in synch after the initial creation of the controls.
I guess this is self-explaining:
public void SomeMehthod()
{
Button btn1 = new Button();
Button btn2 = new Button();
Button btn3 = new Button();
// Your button-array
Button[] btns = new Button[]
{
btn1,
btn2,
btn3
};
foreach(Button btn in btns)
{
// For each button setup the same method to fire on click
btn.Click += new EventHandler(ButtonClicked);
}
}
private void ButtonClicked(Object sender, EventArgs e)
{
// This will fire on any button from the array
// You can switch on the name, or location or anything else
switch((sender as Button).Name)
{
case "btn1":
// Do something
break;
case "btn2":
// Do something
break;
case "btn3":
// Do something
break;
}
}
Or if your array is accessible globaly:
Button[] btns = new Button[5];
Label[] lbls = new Label[5];
private void ButtonClicked(Object sender, EventArgs e)
{
Button clicked = sender as Button;
int indexOfButton = btns.ToList().IndexOf(clicked);
// ..IndexOf() returns -1 if nothign is found
if(indexOfButton > 0)
{
lbls[indexOfButton].DoWhatYouWant...
}
}

How do I add click events to all buttons that have names starting with a certain string in C#?

I am writing a simple calculator script for my C# programming class. It will of course have buttons 0-9 that will update the output textbox to add the number of whatever button is clicked. My problem right now that is I would rather not have to have 10 different click events in my script. I would rather have a loop that cycles through the buttons that will add the same click event to each one and then decide what number to add to the output based on the button.
So right now, I have a click event for the "1" button which is this...
private void btnNum1_Click(object sender, EventArgs e)
{
txtOutput.Text = Convert.ToString(txtOutput.Text + "1");
}
This works fine, but, again, I would rather not have to do this 10 times. How can I create a loop that prevents this?
The button names are btnNum1, btnNum2, btnNum3, etc.
Assuming the button text is just "1", "2" etc you could do this:
private void btnNum_Click(object sender, EventArgs e)
{
var button = sender as Button
txtOutput.Text += button.Content.ToString();
}
Then just apply this event to all the buttons.
Also note you don't need Convert.ToString() as what you are trying to convert is already a string. Using += also cleans up your code a bit.
You could do this to wire-up all of the events in one go:
for (var n = 0; n <= 9; n++)
{
var btn =
this
.Controls
.Find("btnNum" + n.ToString(), false)
.Cast<Button>()
.First();
var digit = n;
btn.Click += (s, e) =>
{
txtOutput.Text = digit.ToString();
};
}
You could enumerate the children controls of your Form/Control, look the type of controls which are type of Button and the name StartWith 'btnNum', with each of these buttons, add a Click event address to btnNum_Click().
Say if all your buttons are contained in a Panel named 'pnlButtons', you could loop all the children like this.
foreach (var control in pnlButtons.Controls)
{
if(control.GetType() == typeof(Button))
{
var button = control as Button;
if (button .Name.StartWith('btnNum'))
{
button.Click += btnNum_Click;
}
}
}
You can use the "Tag" property of the Button control and make an array of Buttons to subscribe to the same event. See sample below:
void InitializeButtons()
{
Button btnNum1 = new Button();
btnNum1.Text = "1";
btnNum1.Tag = 1;
//Button 2..8 goes here
Button btnNum9 = new Button();
btnNum9.Text = "9";
btnNum9.Tag = 9;
Button[] buttons = new Button[]{
btnNum1, btnNum2, btnNum3, btnNum4, btnNum5, btnNum6, btnNum7, btnNum8, btnNum9
};
for (int i = 0; i < buttons.Length; i++)
{
buttons[i].Click += Button_Click;
}
}
void Button_Click(object sender, EventArgs e)
{
Button button = (Button)sender;
int value = (int)button.Tag;
//Do something with value
}
Assuming WinForms, you can recursively search for buttons that start with "btnNum" and wire them up to a common handler like this:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.Load += Form1_Load;
}
void Form1_Load(object sender, EventArgs e)
{
FindButtons(this);
}
private void FindButtons(Control ctl)
{
foreach(Control ctrl in ctl.Controls)
{
if (ctrl.Name.StartsWith("btnNum") && (ctrl is Button))
{
Button btn = (Button)ctrl;
btn.Click += btn_Click;
}
else if(ctrl.HasChildren)
{
FindButtons(ctrl);
}
}
}
private void btn_Click(object sender, EventArgs e)
{
Button btn = (Button)sender;
txtOutput.Text = Convert.ToString(txtOutput.Text + btn.Text);
}
}

Attach event to dynamically created button click

I want to attach an event to a button clicked generated at runtime. Till this point I've wrote the code, but can't pass the button's ID to the method. Here is my code
This code does not through any error, another problem is after the click event the controls get washed away. How to prevent this ?
protected void Button1_Click(object sender, EventArgs e)
{
int i = int.Parse(TextBox1.Text);
for (int x = 1; x <= i; x++)
{
Button b = new Button();
b.ID = "btn_" + x.ToString();
b.Text = "btn_" + x.ToString();
b.Click += new System.EventHandler(myEventHandler);
pnlHolder.Controls.Add(b);
}
}
private void myEventHandler(object sender, EventArgs e)
{
txtMain.Text = sender.ToString(); // I want to know which button was pressed
}
try,
txtMain.Text = (sender as Button).Name;
or
txtMain.Text = (sender as Button).Text;
Try this
private void myEventHandler(object sender, EventArgs e)
{
Button b = (Button) sender;
txtMain.Text = b.ID;
//
txtMain.Text = b.Text;
if(b.ID == "button1")
doThis();
else if(b.ID == "button2")
doThat();
}

C# create an array of controls

Is it possible to create an array of controls? Is there a way to get the index of a control if more than one of the controls in the array share the same event handler?
This is certainly possible to do. Sharing the event handler is fairly easy to do in this case because the Button which raised the event is sent as part of the event args. It will be the sender value and can be cast back to a Button
Here is some sample code
class Form1 : Form {
private Button[] _buttons;
public Form1(int count) {
_buttons = new Button[count];
for ( int i = 0; i < count; i++ ) {
var b = new Button();
b.Text = "Button" + i.ToString()
b.Click += new EventHandler(OnButtonClick);
_buttons[i] = b;
}
}
private void OnButtonClick(object sender, EventArgs e) {
var whichButton = (Button)sender;
...
}
}
Based on Kevins comment:
foreach(Button b in MyForm.Controls.OfType<Button>())
{
b.Click += Button_Click;
}
void Button_Click(object sender, EventArgs e)
{
Button clickedButton = sender as Button;
}

Categories

Resources