C# - How to find out which dynamic button was clicked? - c#

I am writing a program where I dynamically add buttons, I do that by storing them in a Dictionary to get a certain value from them later on (the color of the background).
I need to set a Click event on every one of them, but every Click event has to be a little different, as by clicking the button, a ColorDialog pops up and changes the background of the button.
Is there a way to know which button I clicked? In the following code, the button1 click event adds the other buttons and sets the EventHandler for each of them, what should be the code for the EventHandler? Thank you so much in advance guys.
int i = 0;
Dictionary<int, Button> buttonDictionary = new Dictionary<int, Button>();
Dictionary<int, ColorDialog> colorsDictionary = new Dictionary<int ColorDialog>();
public void button1_Click(object sender, EventArgs e)
{
i++;
buttonDictionary.Add(i, new Button());
buttonDictionary[i].Click += new EventHandler(Click);
this.Controls.Add(buttonDictionary[i]);
}
public void Click(object sender, EventArgs e)
{
//Somehow get the int key of the button that was clicked???? (in this case: int j)
int j;
if (!colorsDictionary.ContainsKey(j))
{
colorsDictionary.Add(j, new ColorDialog());
}
if (colorsDictionary[j].ShowDialog() == DialogResult.OK)
{
buttonDictionary[j].BackColor = colorsDictionary[j].Color;
}
}
The code is made just for adding the buttons, I will be glad for any kind of help, thank you guys!

Well, a direct answer to your question is: cast the sender to a Button
Button pressedButton = (Button) sender;
and then check to which button of the dictionary it matches:
foreach (var entry in buttonDictionary)
{
if (entry.Value == pressedButton)
{
j = entry.Key;
break;
}
}
However, that's overly complex for what you want to achieve. It would be much easier if you had a direct relationship between the button and the color picker:
Dictionary<Button, ColorDialog> buttonDictionary = new Dictionary<Button, ColorDialog>();
Then fill it like this:
public void button1_Click(object sender, EventArgs e)
{
i++;
var button = new Button();
this.Controls.Add(button);
button.Click += new EventHandler(Click);
buttonDictionary.Add(button, null);
}
And later access it with
public void Click(object sender, EventArgs e)
{
Button pressedButton = (Button) sender;
ColorDialog dialog = buttonDictionary[pressedButton];
if (dialog == null)
{
dialog = new ColorDialog();
buttonDictionary[pressedButton] = dialog;
}
if (dialog.ShowDialog() == DialogResult.OK)
{
pressedButton.BackColor = dialog.Color;
}
}
Even more, the question is why you would need so many ColorDialgos, since it should be possible with one dialog only. You can get rid of i, j, all dictionaries and most handling as well. IMHO, the following should be sufficient:
public void button1_Click(object sender, EventArgs e)
{
var button = new Button();
Controls.Add(button);
button.Click += Click;
}
public void Click(object sender, EventArgs e)
{
Button pressedButton = (Button) sender;
ColorDialog dialog = new ColorDialog {Color = pressedButton.BackColor};
if (dialog.ShowDialog() == DialogResult.OK)
{
pressedButton.BackColor = dialog.Color;
}
}
Bonus info:
I don't exactly know what you want to achieve. But your buttons will all be in the same place, overlapping each other. To avoid this, drag a flow layout panel onto the form and then add the buttons to the flow layout:
flowLayoutPanel1.Controls.Add(button);
This will ensure that your buttons are nicely arranged.

Related

How to link buttons with lines based in graphs

I have a "button creator"(that creates my own custom buttons) in my form and I need to, after creating some buttons in the form, clicking in 2 random ones to connect then with a simple line (can be a System.Drawing.Pen). And i should use some kind of graph logical connection to do it. But I have no idea how I should do. Any code suggestions? Thank You
Here is an example:
// two variables we will need:
Button lastBtn = null;
List<Tuple<Button, Button>> buttons = new List<Tuple<Button, Button>>();
void commonButton_Click(object sender, EventArgs e)
{
Button btn = sender as Button;
if (btn == null) return;
if (lastBtn == null) { lastBtn = btn; return; }
else if (btn == lastBtn) { lastBtn = null; return; }
else { buttons.Add(new Tuple<Button, Button>(lastBtn, btn)); lastBtn = null; }
Invalidate();
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
foreach ( Tuple<Button, Button> t in buttons)
{
e.Graphics.DrawLine(Pens.RoyalBlue, t.Item1.Location, t.Item2.Location);
}
}
When creating your buttons hook each up with the common click event:
yourButtonClass btn = new yourButtonClass()..
..
btn.Click += commonButton_Click;
This always draw lines from and to the upper left corner. Using the middle instead or a smart loaction on an edge the is cloest to the other button if left for you. In the latter case you could also add start- and endcaps to the pen, if you want to.

How to design a keypad in C#?

I am new to C# and I am planing to design my own keypad but I don't know how/where to start. as shown in photo, I have 4 textBoxes the keypad buttons.
The first problem came into my mind was: how can I detect the cursor location (which textBox is the cursor in?).
So for example if I had only one textbox then it is easy I could write inside button1 : textBox1.text = "1" and inside button2 : textBox1.text = "2" and inside button_A : textBox1.text = "A".... and so on but I have 4 textBoxes and it is confusing.
Can you please provide me with an idea or what to write inside each button to print its value in the textbox which the cursor is in.
Thank you professionals.
Firstly, have a textbox that represents the one that is selected (outside of subroutines but inside the class):
TextBox SelectedTextBox = null;
And then make the "Click" event of each TextBox look like this:
private void textBoxNUM_Click(object sender, EventArgs e)
{
SelectedTextBox = sender as TextBox;
}
And then make the "Click" event of each Button look like this:
private void buttonNUM_Click(object sender, EventArgs e)
{
if (SelectedTextBox != null)
{
SelectedTextBox.Text = buttonNUM.Text;//Or set it to the actual value, whatever.
}
}
Or if that one doesn't work, this should.
private void buttonNUM_Click(object sender, EventArgs e)
{
if (SelectedTextBox != null)
{
(SelectedTextBox as TextBox).Text = buttonNUM.Text;//Or set it to the actual value, whatever.
}
}
To check if a textbox is focused you can do
if(textbox1.Focused)
{
//Print the value of the button to textbox 1
}
else if (textbox2.Focused)
{
//Print the value to textbox 2
}
UPDATE:
Since the textbox will lose focus when you click the button, you should have a temporary textbox (ie lastTextboxThatWasFocused) which is saved to everytime a textbox gains focus. Write an OnFocused Method and do something like
public void Textbox1OnFocused(/*Sender Event Args*/)
{
lastTextboxThatWasFocused=textbox1;
}
Then on button click you can do
if(lastTextboxThatWasFocused.Equals(textbox1))
{
//ETC.
}
You can give something along these lines a try. Create a generic click handler for the buttons and then assign the value to a textbox the text from the button, which happens to be the value. You can check which box was the last one focused in the TextBoxes' Click event. Create a global variable to store which one and use it in the below method.
private TextBox SelectedTextBox { get; set; }
private void NumericButton_Click(object sender, EventArgs e)
{
var clickedBox = sender as Button;
if (clickedBox != null)
{
this.SelectedTextBox.Text += clickedBox.Text;
}
}
private void TextBox_Click(object sender, EventArgs e)
{
var thisBox = sender as TextBox;
if (thisBox == null)
{
return;
}
this.SelectedTextBox = thisBox;
}
Try this code:
TextBox LastTxtBox;
private void textBox_Enter(object sender, EventArgs e)
{
LastTxtBox = sender as TextBox;
}
private void button_Click(object sender, EventArgs e)
{
LastTxtBox.Text = this.ActiveControl.Text;
}
Add textBox_Enter function to all textboxes enter event.
Add button_Click to all buttons click event.
Button Enter Event
Control _activeControl;
private void NumberPadButton_Click(object sender, EventArgs e)
{
Button btn = (Button)sender;
if (_activeControl is TextBox || _activeControl is RichTextBox)
{
_activeControl.Text += btn.Text;
if (!_activeControl.Focused) _activeControl.Focus();
}
}
TextBox or RihTextBox Enter Event
private void TextBoxEnter_Click(object sender, EventArgs e)
{
_activeControl = (Control)sender;
}

Button text bold on click

I made a quiz game and I want the text on the button to be bold when clicked. This code works:
button7.Font = new Font(button7.Font.Name, button7.Font.Size, FontStyle.Bold);
The problem I'm having is when I click on the 'Next' button to go to the next question, the text is still bold even though the answer hasn't been clicked. How do I solve this?
Just do this on "Next" button click
button7.Font = new Font(button7.Font.Name, button7.Font.Size, FontStyle.Regular);
You need to un-bold everything when you click Next. The code below should help (it also includes a possibly cleaner bolding implementation).
// usage
foreach(var button in GetAnswerButtons())
{
button.Click += OnClickToBold;
button.Click += OnClickSetPropertyBasedOnCorrectness;
}
nextButton.Click += NextClick;
// implementations
private void OnClickToBold(object sender, EventArgs e)
{
var button = sender as Button;
if (button == null) return;
button.Font = new Font(button.Font.Name, button.Font.Size, FontStyle.Bold);
}
private void OnClickSetPropertyBasedOnCorrectness(object sender, EventArgs e)
{
var button = sender as Button;
if (button == null) return;
button.WhateverProperty = IsCorrectAnswer(button)
? valueWhenCorrect
: valueWhenWrong;
}
private void NextClick(object sender, EventArgs e)
{
foreach(var button in GetAnswerButtons())
{
button.Font = new Font(button.Font.Name, button.Font.Size, FontStyle.Regular);
UnsetPropertyBasedOnCorrectness(button);
}
}
private IEnumerable<Button> GetAnswerButtons() { ... }
private void UnsetPropertyBasedOnCorrectness(Button b) { ... }

how to create events on dynamic `textboxes`

I managed to create textboxes that are created at runtime on every button click. I want the text from textboxes to disappear when I click on them. I know how to create events, but not for dynamically created textboxes.
How would I wire this up to my new textboxes?
private void buttonClear_Text(object sender, EventArgs e)
{
myText.Text = "";
}
This is how you assign the event handler for every newly created textbox :
myTextbox.Click += new System.EventHandler(buttonClear_Text);
The sender parameter here should be the textbox which sent the even you will need to cast it to the correct control type and set the text as normal
if (sender is TextBox) {
((TextBox)sender).Text = "";
}
To register the event to the textbox
myText.Click += new System.EventHandler(buttonClear_Text);
Your question isn't very clear, but I suspect you just need to use the sender parameter:
private void buttonClear_Text(object sender, EventArgs e)
{
TextBox textBox = (TextBox) sender;
textBox.Text = "";
}
(The name of the method isn't particularly clear here, but as the question isn't either, I wasn't able to suggest a better one...)
when you create the textBoxObj:
RoutedEventHandler reh = new RoutedEventHandler(buttonClear_Text);
textBoxObj.Click += reh;
and I think (not 100% sure) you have to change the listener to
private void buttonClear_Text(object sender, RoutedEventArgs e)
{
...
}
I guess the OP wants to clear all the text from the created textBoxes
private void buttonClear_Text(object sender, EventArgs e)
{
ClearSpace(this);
}
public static void ClearSpace(Control control)
{
foreach (var c in control.Controls.OfType<TextBox>())
{
(c).Clear();
if (c.HasChildren)
ClearSpace(c);
}
}
This should do the job :
private void button2_Click(object sender, EventArgs e)
{
Button btn = new Button();
this.Controls.Add(btn);
// adtionally set the button location & position
//register the click handler
btn.Click += OnClickOfDynamicButton;
}
private void OnClickOfDynamicButton(object sender, EventArgs eventArgs)
{
//since you dont not need to know which of the created button is click, you just need the text to be ""
((Button) sender).Text = string.Empty;
}

How can i take dynamically created buttons' name when they are clicked?

I'm making a mahjong game and I'm totally new at C#, I wonder how i can take a button's name when it's clicked. All the buttons are created dynamically in the form.
public Button createButton(node x)
{
Button nButton;
nButton = new Button();
nButton.Name = x.info.ToString();
nButton.Text = x.info.ToString();
nButton.Width = 55;
nButton.Height = 75;
nButton.Visible = true;
if (x.isValid())
nButton.Enabled = true;
else
nButton.Enabled = false;
nButton.Click += new System.EventHandler(n1_click);
return nButton;
}
in the form i take buttons with this code
myButton = createButton(tp);
myButton.Location = new System.Drawing.Point(25 , 25);
this.Controls.Add(myButton);
The first argument to the event handler is the sender, you can cast that to a Button and then access the Name property.
Here is a small example of the event handler.
private void Button_Click(object sender, EventArgs e)
{
Button button = sender as Button;
if (button != null)
{
// Do something with button.Name
}
}
Edit: As Hans mentioned in the comments, using as could hide a potential bug. Using the as operator as in the example above will ensure that if you inadvertently wire this handler to an event of another control the code will handle it graciously and not throw an InvalidCastException, but there-in lies a problem as well, because this now silently fails you might not pickup a bug in your code. If the exception was thrown you would have realized there is a problem and been able to track it down. So the updated code would be something like this.
private void Button_Click(object sender, EventArgs e)
{
// If sender is not a Button this will raise an exception
Button button = (Button)sender;
// Do something with button.Name
}
With the following code you can get the button that was clicked
protected void Button1_Click(object sender, EventArgs e)
{
Button btn = (Button)sender;
}
on the function which handles the click "n1_click"
private void n1_click(object sender, EventArgs e)
{
Button temp = (Button)sender;
string neededText = temp.Text;
}

Categories