Changing all Button background except button clicked - c#

I am working on a form that has lots of buttons. When the user clicks one button the background should change color. If they click another button on the form its background should change color and the previous buttons color should return back to the original color.
I can do this by hard coding in every button but this form has alot of buttons. I am sure there has to be a more efficient way of doing this
I have this so far
foreach (Control c in this.Controls)
{
if (c is Button)
{
if (c.Text.Equals("Button 2"))
{
Btn2.BackColor = Color.GreenYellow;
}
else
{
}
}
}
I can get the background for Btn2 to change. How would i change the background for all the other buttons in the form. Any ideas how i could do this without having to hardcode each button.

The code below will work without regard to the number of buttons on the form. Simply set the button_Click method to be the event handler of all buttons. When you click on a button, its background will change color. When you click on any other button, that button's background will change color, and the previously-colored button's background will revert to the default background color.
// Stores the previously-colored button, if any
private Button lastButton = null;
...
// The event handler for all button's who should have color-changing functionality
private void button_Click(object sender, EventArgs e)
{
// Change the background color of the button that was clicked
Button current = (Button)sender;
current.BackColor = Color.GreenYellow;
// Revert the background color of the previously-colored button, if any
if (lastButton != null)
lastButton.BackColor = SystemColors.Control;
// Update the previously-colored button
lastButton = current;
}

This will work as long as you don't have any control containers (eg Panels)
foreach (Control c in this.Controls)
{
Button btn = c as Button;
if (btn != null) // if c is another type, btn will be null
{
if (btn.Text.Equals("Button 2"))
{
btn.BackColor = Color.GreenYellow;
}
else
{
btn.BackColor = Color.PreviousColor;
}
}
}

if your buttons are inside of a panel do the code below, in foreach
you will get all the buttons inside of pnl2Buttons panel and then try to pass the text name of the button that you want to change the background
and the rest will have a SeaGreen color.
foreach (Button oButton in pnl2Buttons.Controls.OfType<Button>())
{
if (oButton.Text == clickedButton)
{
oButton.BackColor = Color.DodgerBlue;
}
else
{
oButton.BackColor = Color.SeaGreen;
}
}

Elaborating on the answer from #Brett Wolfington in 2013...
You can use a simple method to reduce the code in the mouse button_Click events methods.
Below I use the method Chgcolor and invoke it via a one liner in my button_Click events. It helps to reduce the redundancy and by calling current.BackColor = Color.GreenYellow; after all the checks I can now click on 1 button repeatedly without the color disappearing.
Example below from Visual Studio community 2022
private Button? lastButton = null;
private void Chgcolor(Button current)
{
if (lastButton != null)
{
lastButton.BackColor = SystemColors.Control;
}
lastButton = current;
current.BackColor = Color.GreenYellow;
}
private void Button_Click(object sender, EventArgs e)
{
Chgcolor((Button)sender);//call the check color method
}
private void Button2_Click(object sender, EventArgs e)
{
Chgcolor((Button)sender);//call the check color method
}

Related

How to correctly highlight buttons on click?

So I have built an application in C# using Winforms and my application uses a few different buttons. I'd like to have a highlight on the button that has been clicked to show what 'tab' you're in.
I've tried doing the following;
// BUTTONS //
private void dashboard_btn_Click(object sender, EventArgs e)
{
// Load Form
OpenChildForm(new FormDashboard());
dashboard_btn.FlatAppearance.BorderColor = Color.Red;
dashboard_btn.FlatAppearance.BorderSize = 1;
}
However, this of course doesn't work nicely since it adds a border around the button but when I click another button the border also stays around the previous button.
How would you implement a feature to add a border around the button that get's clicked but have the border disappear after you click another button?
Thank you for any feedback!
EDIT:
I've implemented Jimi's advice and used the Leave event to change the border around the button back to 0. However I'm not sure how to implement this in a global way so all my buttons are subscribed to this event.
My code now looks like this;
// BUTTONS //
private void dashboard_btn_Click(object sender, EventArgs e)
{
// Load Form
OpenChildForm(new FormDashboard());
// Button Highlight
dashboard_btn.FlatAppearance.BorderColor = Color.Red;
dashboard_btn.FlatAppearance.BorderSize = 1;
}
// BUTTON REMOVE HIGHLIGHT //
private void dashboard_btn_Leave(object sender, EventArgs e)
{
dashboard_btn.FlatAppearance.BorderSize = 0;
}
EDIT 2:
I ended up using Jimi's example and this worked for me :)
This might lend itself to a RadioButton style functionality because clicking a different radio button in the same container will uncheck the others. So, to implement the "generalized approach" that you mention in your comment, you could make a simple custom RadioButtonEx class where the Appearance property is set to Button then change your border style when the Checked property changes. In this example, the Click event has been changed to static so that clicking on any button directs the event to the common onAnyClick method.
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
RadioButtonEx.Click += onAnyClick;
}
private void onAnyClick(object sender, EventArgs e)
{
label1.Text = ((RadioButtonEx)sender).Text;
}
}
public class RadioButtonEx : RadioButton
{
public static new event EventHandler Click;
public RadioButtonEx()
{
FlatAppearance.BorderColor = Color.Red;
FlatAppearance.BorderSize = 1;
Appearance = Appearance.Button;
}
protected override void OnCheckedChanged(EventArgs e)
{
base.OnCheckedChanged(e);
if(Checked)
{
FlatStyle = FlatStyle.Flat;
Click?.Invoke(this, EventArgs.Empty);
}
else
{
FlatStyle = FlatStyle.Standard;
}
}
}

How can I make a function to relocate and resize a set of controls

I have 10 panels all visible = false and have 10 buttons
panels name = p1, p2, p3...etc
buttons name = b1, b2, b3...etc
I wanna when click on button(b1)
make panel(p1) visible = true
relocate and resize panels
The new location and new size for all panels are same,
Can I make a function do the relocate and resize instead of write a code more times like this
private void b1_Click(object sender, EventArgs e)
{
p1.Visible = true;
p1.Location = new System.Drawing.Point(9, 247);
p1.Size = new System.Drawing.Size(1120, 464);
}
You can assign all buttons' click event to the same event handler. The parameter sender is the object that fires the event which in your case it is one of your buttons. Then check the sender's Text or Name property and find which button was clicked. For panels, you could make a method with a Panel type parameter and do what you want.
private void btn_Click(object sender, EventArgs e)
{
// here put code to hide all panels
//...
//then show and relocate the panel related the clicked button as follows
switch ((sender as Button).Name) //or button's Text
{
case "b1":
showPanel(pl);
break;
case"b2":
showPanel(p2);
break;
//other cases
//...
}
}
private void showPanel(Panel pnl)
{
//show and relocate
pnl.Visible = true; //I consider pnl.Show(); as it's more readable
//...
}
Don't forget to hide all panels at the beginning of the click event. You can use following method if you do not have any other panel in your control except those 10 ones.
private void hidePanels()
{
foreach (Control c in yourControl.Controls) //replace yourControl with the control that is the container of your panels e.g. your form
{
if (c is Panel) c.Visible = false; //or c.Hide();
}
}
I haven't tested this code, but it should work.

C# Winforms Application Button Event for Method in Another Class

My problem is that I have a button in a winforms application that I would like to create a hover effect for. I have already achieved this effect by selecting this button, moving to the properties pane, selecting the Events, and double clicking the MouseEnter Event. This automatically creates a method in the c# code, and I can go into that method change the background color, no problem. I use a similar process for the MouseLeave Event and change the color back. This I know how to do.
Since each user control also has many buttons on it, I've been able to create generic methods (like below), and reuse these methods for each button within the user control. This is easy to select a method with the appropriate signature from the properties under events. I can find it in the dropdown next to the method. However, I have many user controls which have buttons on them, so these 2 methods are repeated in every single class.
What I've done to attempt to clean this up, is create a little static class. Then I can go into the designer (after building) and this works 100%. This not only reduces redundant code but also allows for a style change if ever the hover color needed to change, without modifying each code behind. However, if I were ever to make a modification the the user control, my reference to the method in the designer gets wiped out by the designer. The line of code just disappears.
Everything I read says "don't change the designer" for this exact reason. However, the visual studio user interface does not allow me a way to reference a method in an outside class. Any advice would be much appreciated.
private void Mouse_Enter(object sender, EventArgs e)
{
Button btn = (Button)sender;
if (btn.Enabled == true) btn.BackColor = Color.LightGray;
}
private void Mouse_Leave(object sender, EventArgs e)
{
Button btn = (Button)sender;
if (btn.Enabled == true) btn.BackColor = Color.White;
}
public static class ButtonHelper
{
public static void Mouse_Enter(object sender, EventArgs e)
{
Button btn = (Button)sender;
if (btn.Enabled == true) btn.BackColor = Color.LightGray;
}
public static void Mouse_Leave(object sender, EventArgs e)
{
Button btn = (Button)sender;
if (btn.Enabled == true) btn.BackColor = Color.White;
}
designer
this.btnEdit.UseVisualStyleBackColor = false;
this.btnEdit.Click += new System.EventHandler(this.btnEdit_Click);
this.btnEdit.MouseEnter += new System.EventHandler(ButtonHelper.Mouse_Enter);
this.btnEdit.MouseLeave += new System.EventHandler(this.Mouse_Leave);
Here is the updated code based on the advice by 41686d6564
public class HoverButton:Button
{
protected override void OnMouseEnter(EventArgs e)
{
if (Enabled == true) BackColor = Color.LightGray;
base.OnMouseEnter(e);
}
protected override void OnMouseLeave(EventArgs e)
{
if (Enabled == true) BackColor = Color.White;
base.OnMouseLeave(e);
}
protected override void OnEnabledChanged(EventArgs e)
{
if (Enabled)
{
ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(22)))), ((int)(((byte)(137)))));
BackColor = Color.White;
}
else
{
ForeColor = Color.Gray;
BackColor = Color.LightGray;
}
base.OnEnabledChanged(e);
}
}

All buttons state change in C# [duplicate]

This question already has answers here:
How to get ALL child controls of a Windows Forms form of a specific type (Button/Textbox)?
(28 answers)
Closed 2 years ago.
What I am trying to do is to change background color of the button once it's active. So far I achieved it by this way:
private void button3_Click(object sender, EventArgs e) // METEO BUTTON
{
DefaultButtons();
button3.BackColor = Color.LimeGreen;
// REST OF THE CODE HOES HERE
}
While DefaultButtons function is like this:
public void DefaultButtons()
{
List<Button> buttonsToDefualt = new List<Button>()
{
// MAIN MENU
button1,
button2,
[...]
buttonX
};
foreach (var item in buttonsToDefualt)
{
item.BackColor = Color.Green;
}
}
Now swapping buttons works like this: Change entire list to default color, then activated button change color to LimeGreen. It would be fine but:
1) I have to launch DefaultButtons(); for EACH button Click
2) I have to manually add all buttons to list, and now I have more than 120 buttons (Yeah, building custom interface...), and keep adding that by hand is tiring.
I tried this:
void DefaultButtonsNew()
{
foreach (Button b in this.Controls)
{
if (b != null)
{
b.BackColor = Color.Green;
}
}
}
But I've got an Exception: System.InvalidCastException: 'Can't throw object 'System.Windows.Forms.SplitContainer' on type 'System.Windows.Forms.Button'.'
If you're looking for a way to reset all buttons on the form, and some buttons are inside other containers, then we need to recursively loop through each control's Controls collection to find all the buttons.
One easy way to do that is to write a method that takes in a container (like the form), iterates through its Controls collection, changes the BackColor of any Button controls, and calls itself for the other control types:
private void ResetButtons(Control container)
{
// Loop through each control in this container
foreach (Control control in container.Controls)
{
var button = control as Button;
// If the control is a button, change it's backcolor
if (button != null) button.BackColor = Color.Green;
// Otherwise check it's controls collection (recursive call)
else ResetButtons(control);
}
}
Next, it sounds like you're looking for a way to avoid writing out a call to this method, and to change the BackColor of the current button, in every button click event.
One easy way around this is to simply add this method, and the BackColor change, to every button click in code. We can write a method to do this using a similar pattern - loop through every control in every container, and if it's a button, add a method to it's click event:
private void HookupButtonClickEvent(Control container)
{
// Loop through each control in this container
foreach (Control control in container.Controls)
{
var button = control as Button;
// If the control is a button, add a method to it's click event
if (button != null)
{
button.Click += (s, e) =>
{
ResetButtons(container);
button.BackColor = Color.LimeGreen; // Change this button's color
};
}
// Otherwise check it's controls collection (recursive call)
else HookupButtonClickEvent(control);
}
}
Now, all we have to do is call the ResetButtons and HookupButtonClickEvent in our form's constructor, and every button will start with the same backcolor and will have our reset method call in it's click event:
public Form1()
{
InitializeComponent();
HookupButtonClickEvent(this);
ResetButtons(this);
}
Note that this does not prevent you from adding additional click events to the buttons. It merely provides a way to hook up the common functionality to all buttons without writing a bunch of duplicated code.
You can still double-click the controls on your form to add other Click event handlers:
private void button1_Click(object sender, EventArgs e)
{
MessageBox.Show("Button one clicked - doing something unique here");
}
private void button2_Click(object sender, EventArgs e)
{
MessageBox.Show("Button two clicked - doing something else here");
}
The iterator on Controls collection returns all the controls and trying to cast it to Button should an do fail.
Change your method like this:
void DefaultButtonsNew()
{
foreach (Control b in this.Controls)
{
if (b is Button)
{
b.BackColor = Color.Green;
}
}
}

Multiselect picture gallery with winforms c#

I'm trying to create a multiselect picturegallery with winforms.
Currently I have created a flowcontrolpanel that adds images as a selectablepicturebox control.
The selectablepicturebox control is a customer usercontrol that is a blank control with a picturebox and a checkbox on the top right of the picturebox. The picturebox is slightly smaller and centered in the usercontrol.
Clicking on the selectablepicturebox control will turn the background on and off indication selection.
What I want to be able to do is to select a bunch of selectablepicturebox controls and be able to capture the spacebar event to check and uncheck the checkboxes in the selected controls.
The problem is that the flowlayoutpanel never knows to capture the spacebar event.
Does anyone know away of doing this or another technology? I'm happy to use any .net based tech.
Thanks
EDIT:
Here is a link to the code
Are you trying the KeyDown event ?
As per MSDN, This member is not meaningful for this control.
Read here & here. Instead, you may try PreviewKeyDown
Solution: [The GitHub codebase]
[Code Changes]
1. SelectablePictureBox.cs - NOTE the Set Focus
public void SetToSelected()
{
SelectedCheckBox.Checked = true;
PictureHolder.Focus();
}
private void PictureHolder_Click(object sender, EventArgs e)
{
BackColor = BackColor == Color.Black ? Color.Transparent : Color.Black;
// TODO: Implement multi select features;
if ((Control.ModifierKeys & Keys.Shift) != 0)
{
// Set the end selection index.
}
else
{
// Set the start selection index.
}
PictureHolder.Focus();
}
// subscribe to picture box's PreviewKeyDown & expose a public event
public event PreviewKeyDownEventHandler OnPicBoxKeyDown;
private void OnPicBoxPrevKeyDown(object sender, PreviewKeyDownEventArgs e)
{
if (OnPicBoxKeyDown != null)
{
OnPicBoxKeyDown(sender, e);
}
}
[Code Changes]
1. FormMain.cs
private void FormMain_Load(object sender, EventArgs e)
{
SensitiveInformation sensitiveInformation = new SensitiveInformation();
int index = 0;
//foreach (var photo in Flickr.LoadLatestPhotos(sensitiveInformation.ScreenName))
for (int i = 0; i < 10; i++)
{
SelectablePictureBox pictureBox = new SelectablePictureBox(index);
// subscribe to picture box's event
pictureBox.OnPicBoxKeyDown += new PreviewKeyDownEventHandler(pictureBox_OnPicBoxKeyDown);
PictureGallery.Controls.Add(pictureBox);
index++;
}
}
// this code does the selection. Query the FLowLayout control which is the 1st one and select all the selected ones
void pictureBox_OnPicBoxKeyDown(object sender, PreviewKeyDownEventArgs e)
{
if (e.KeyCode != Keys.Space) return;
foreach (SelectablePictureBox item in Controls[0].Controls)
{
if (item.IsHighlighted)
{
item.SetToSelected();
}
}
}

Categories

Resources