How to disable a List of buttons - c#

I have a number of buttons on a Windows Form. I only want to disable a number of them.
I have created a list of buttons and added the buttons that i want to disable. When i run the code the buttons are still enabled.
Below is what i have tried.
private List<Button> buttonsToDisable = new List<Button>();
buttonsToDisable.Add(btn1);
buttonsToDisable.Add(btn2);
buttonsToDisable.Add(btn3);
foreach (var control in this.Controls)
{
if (control is Button)
{
Button currentButton = (Button)control;
if (buttonsToDisable.Contains(currentButton))
{
currentButton.Enabled = false;
}
}
}
Can anyone see why this wont disable the button for me.
Any advice is welcome.

Why not simply?:
foreach(Button btn in buttonsToDisable)
{
btn.Enabled = false;
}

currentButton.Enabled = false;
this.Controls.Add(currentButton);

answering your question - your code would work if the buttons were direct descendants of the form - i.e. they were placed straight onto it.
If however you placed them in another container (e.g. a groupbox), then your code would need to change to something like:
foreach (var control in groupBox1.Controls)
If you have multiple levels of complexity, then you'd be looking at a recursive function to get to the buttons within their parents, and their parents, etc.
As others have pointed out, you could always just iterate over buttonsToDisable.

If is directly added to the form, then u just foreach Controls collection and disable buttons.
Button btn1 = new Button();
this.Controls.Add(btn1);
Button btn2 = new Button();
this.Controls.Add(btn1);
Button btn3 = new Button();
this.Controls.Add(btn1);
buttonsToDisable.Add(btn1);
buttonsToDisable.Add(btn2);
buttonsToDisable.Add(btn3);
foreach (var control in this.Controls)
{
((Button)control).Enabled = false;
}
or
foreach (var button in buttonsToDisable)
{
button.Enabled = false;
}

Related

C# Fill an array with all the buttons being used in Windows form

I am trying to fill an array with all the Buttons being used in Form1.
Button[] ButtonArray = new Button[5];
ButtonArray[0] = button1;
ButtonArray[1] = button2;
ButtonArray[2] = button3;
ButtonArray[3] = button4;
ButtonArray[4] = button5;
This code works fine.
But if I have for example 100 buttons it is a long procedure.
If all the Buttons are on the form you can try using Linq:
using System.Linq;
...
Button[] ButtonArray = Controls
.OfType<Button>()
.ToArray();
Edit: in case you have some buttons within groupboxes, panels (i.e. not directly on the form, but on some kind of container), you have to elaborate the code into something like this
private static IEnumerable<Button> GetAllButtons(Control control) {
IEnumerable<Control> controls = control.Controls.OfType<Control>();
return controls
.OfType<Button>()
.Concat<Button>(controls
.SelectMany(ctrl => GetAllButtons(ctrl)));
}
...
Button[] ButtonArray = GetAllButtons(this).ToArray();
See How to get ALL child controls of a Windows Forms form of a specific type (Button/Textbox)? for details
you can try this one:
ButtonArray[] buttonArray = new ButtonArray[this.Controls.OfType<Button>().Count()]
int i =0; //index for button array
foreach(var button in this.Controls.OfType<Button>()) //Iterate through each button control
{
buttonArray [i++] = button;
}
Enumerable.OfType doesn't search controls down the control-hierarchy. So if you want to find controls recursively you could use this extension method:
public static IEnumerable<T> RecursiveControlsOfType<T>(this Control rootControl) where T : Control
{
foreach (Control child in rootControl.Controls)
{
if (child is T targetControl)
yield return targetControl;
foreach (T targetControlChild in child.RecursiveControlsOfType<T>())
yield return targetControlChild;
}
}
Usage:
Button[] nonRecursiveButtons = this.Controls.OfType<Button>().ToArray();
Button[] recursiveButtons = this.RecursiveControlsOfType<Button>().ToArray();
List<Button> Buttons = new List<Button>();
foreach (var item in this.Controls) // Looping through all controls in the form
{
if (item is Button) // if the current is a button we add it
{
Buttons.Add(item as Button);
}
}

Foreach button in my panel containing other panels

I'm using a custom Button which contains other elements and color styles like TopColor and BotColor. I need to handle this Button inside a panel with other panels.
I'm trying this:
foreach(CustomButton btn in panel1.Controls)
{
if(btn is CustomButton)
{
btn.TopColor=Color.Red;
}
Inside panel1 I'm containing other panels too. And the error I'm getting is
it can't be conversion element panel in a button.
One solution is to separate buttons in one panel. But I want to ask if there is some way to avoid other elements. The reason I don't want to use foreach (Control a in this.Controls) is it doesn't recognise my custom color style TopColor and BotColor
Take a look
Loop through all your controls (as Controls), check if it's a button, then cast it before you try and set the colour.
foreach(Control c in panel1.Controls)
{
if (c is CustomButton)
{
(c as CustomButton).TopColor = Color.Red;
}
}
I hope this solution works for you.
private void SetStylesToCustomButtons(Control.ControlCollection controls)
{
foreach (Control control in controls)
{
if (control is CustomButton)
{
(control as CustomButton).TopColor = Color.Red;
}
else if (control is Panel)
{
SetStylesToCustomButtons((control as Panel).Controls);
}
}
}
The reason you're getting an error is that you're trying to cast all your controls to CustomButton, even the panels. You already know the type that you're looking for, so you don't have to loop through every control in your panel.
Assuming all your custom buttons are in panel1 and that you don't need to recurse, you should rather filter the items down to the type that you want and then work with them:
var customButtons = panel1.Controls.OfType<CustomButton>();
foreach (CustomButton customButton in customButtons)
{
//do what you need here
}

Control is removed from old parent control but not if i use a List<Control>, why?

It's probably a very basic question about the behaviour of C# and WebControl. I got this working, but it would be nice if someone could clarify where the difference lays.
Before
I have a dictionary with a given key (Guid) and a Panel.
var tmpFormButtonPanel = new Panel();
_formButtonPanelDict.TryGetValue(new Guid(_hiddenField.Value), out tmpFormButtonPanel);
This panel contains a WebControl. Now I'd like to assign this button to another panel.
if (tmpFormButtonPanel != null)
{
var tmpControls = new List<Button>();
foreach (Button tmpButton in tmpFormButtonPanel.Controls)
{
tmpControls.Add(tmpButton);
}
tmpControls.Reverse();
foreach (var tmpButton in tmpControls)
{
tmpButton.AddCssClass("xy");
_buttonPanel.Controls.Add(tmpButton);
}
}
The moment I add the button to the _buttonPanel, it deletes the button out of tmpFormButtonPanel. From what I've heard or read, a WebControl can only be assigned to one panel. So this would explain why it doesn't work.
So I changed the code to this.
var tmpFormButtonList = new List<ButtonBaseUc>();
if (!_formButtonDict.TryGetValue(new Guid(_hiddenField.Value), out tmpFormButtonList))
{
tmpFormButtonList = new List<ButtonBaseUc>();
_formButtonDict.Add(new Guid(_hiddenField.Value), tmpFormButtonList);
}
foreach (var tmpButton in tmpFormButtonPanel.Controls)
{
if (tmpButton is ButtonBaseUc)
{
tmpFormButtonList.Add((ButtonBaseUc)tmpButton);
}
}
The last part does the same thing, but on the tmpFormButtonList.
if (tmpFormButtonList!= null)
{
var tmpControls = new List<Button>();
foreach (Button tmpButton in tmpFormButtonList)
{
tmpControls.Add(tmpButton);
}
tmpControls.Reverse();
foreach (var tmpButton in tmpControls)
{
tmpButton.AddCssClass("xy");
_buttonPanel.Controls.Add(tmpButton);
}
}
This is working. But why? I am only assigning the button to another list before adding it to the new panel. The references are still the same. What am I missing?
A control can only belong to one parent control. Since you have assigned it to the Panel in the dictionary-value, it will be removed there if you move it to the _buttonPanel.
This isn't documented but you can see it in the source:
// ...
if (control._parent != null) {
control._parent.Controls.Remove(control);
}
You have fixed this by not using a Panel as "storage" but a List<ButtonBaseUc>. This list is not a control(so the control has no parent), hence it must not be removed if you assign it to another (parent-)control.

C# add buttons to flow control without stealing focus

In my application I dynamically create buttons and add them to a flow control that is later cleared. I have this on a timer to refresh every X seconds to clear then add buttons. This is all being done on the main form.
The problem is when I have a child form launched the main form will steal focus every time the controls are added to the flow control.
Here is the code I have that dynamically clears and adds the controls on the main form.
I call this before adding the controls
flw_users.Controls.Clear();
This is what I call to dynamically create/add the buttons to the flow control.
private void DisplayNewMobileUser(string MobileUserName)
{
// Set Button properties
Button button = new Button();
button.Text = MobileUserName;
button.Size = new System.Drawing.Size(171, 28);
button.Name = MobileUserName;
button.BackColor = System.Drawing.Color.White;
button.FlatAppearance.BorderColor = System.Drawing.Color.White;
button.Font = new System.Drawing.Font("Segoe UI", 12F, System.Drawing.FontStyle.Bold);
button.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
button.ForeColor = System.Drawing.Color.Black;
button.Margin = new System.Windows.Forms.Padding(0, 1, 0, 1);
button.TextAlign = System.Drawing.ContentAlignment.TopLeft;
button.Click += new EventHandler(MobileUserName_OnClick);
flw_users.Controls.Add(button);
}
Is there a way to add buttons to a flow control with out it always stealing focus ?
Thanks to LarsTech I researched how to properly dispose each control added to flw_users. The main issues was fixed by changing the OnClick event to change focus to a label, which in turn didn't cause the main form to gain topmost every time the controls were cleared and re added. So everytime I clicked a button that button still had focus while the new form appeared.
Thanks everyone !
Here is the code I used to properly clear the controls
private void ClearUsers()
{
List<Control> ctrls = new List<Control>();
foreach (Control c in flw_users.Controls)
{
ctrls.Add(c);
}
flw_users.Controls.Clear();
foreach (Control c in ctrls)
{
c.Dispose();
}
}

Changing properties of controls that were added at runtime

I have a form in which several buttons are added at runtime via a 'for' method
public Form()
{
for (int i = 0 ... )
Button b = new Button()
b.text = (string) i ;
etc..
etc..
}
. now i wish to change the text property of the buttons on a certain event. How can this be accomplished? I have tried a few things but none worked.. since the buttons variables are inside the method , they are not available outside.
Thanks
The variables aren't important (although you could store them in a single List<T> field if it made things easier). The normal way to do this is to look through the Controls collection (recursively, if necessary).
foreach(Control control in someParent.Controls) {
Button btn = control as Button;
if(btn != null) {
btn.Text = "hello world";
// etc
}
}
The above assumes all the buttons were added to the same parent control; if that isn't the case, then walk recursively:
void DoSomething(Control parent) {
foreach(Control control in parent.Controls) {
Button btn = control as Button;
if(btn != null) {
btn.Text = "hello world";
// etc
}
DoSometing(control); // recurse
}
}
You can keep the reference of the button you have created ie you can either have a List with all the dynamic controls in it or if it is only one button, make the button object a class level object so that you can access it anywhere.

Categories