What is the best way to dynamically modify the forecolor and background color of every control of a WinForm application consisting of buttons, toolstrips, panels, etc? Is there an easy way to cycle through each control automatically or do I have to manually change each one? Thanks.
You can cycle through controls, I believe that all controls have a Controls property that is a list of contained controls.
Hypothetical function:
public void ChangeControlsColours(Controls in_c)
{
foreach (Control c in in_c)
{
c.BackColor = Colors.Black;
c.ForeColor = Colors.White;
if (c.Controls.length >0 ) //I'm not 100% this line is correct, but I think you get the idea, yes?
ChangeControlsColours(c.Controls)
}
}
foreach (Control c in MyForm.Controls) {
c.BackColor = Colors.Black;
c.ForeColor = Colors.White;
}
It really depends on what you're trying to do. The most elegant way might be a linked application setting you define on design time and you're then be able to change on run time.
private void UpdateInternalControls(Control parent)
{
UpdateControl(parent, delegate(Control control)
{
control.BackColor = Color.Turquoise;
control.ForeColor = Color.Yellow;
});
}
private static void UpdateControl(Control c, Action<Control> action)
{
action(c);
foreach (Control child in c.Controls)
{
UpdateControl(child, action);
}
}
Related
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
}
I have some user controls that do not support RightToLeft Layout and I have the DLLs only.
I want implement RightToLeft Layout in these controls by code.
How can I do that?
Note : I try to use TableLayoutPanel and FlowLayoutPanel, but the problem still exists.
You have to do it manually using some logic.
private bool isLeft = true;
private void SwapPosition()
{
isLeft = !isLeft;
foreach (Control cnt in this.Controls)
SwapPosition(cnt);
}
private void SwapPosition(Control cnt)
{
cnt.Left = cnt.Parent.Width - (cnt.Left + cnt.Width);
///Assign other properties also
///ie. cnt.RightToLeft = !isLeft
///if (isLeft) then NormalFont else Hebrew or any
foreach (Controls cntChild in cnt.Controls)
RightToLeft(cntChild);
}
It's a bit difficult for me to describe, but this pseudo C# should explain what I'm trying to do.
There is a large number of labels on a windows form.
I'd like to change the text colour of some of those labels.
private void allBlackLabels()
{
int[] lray = { 1, 2, 3, 5, 6 };
foreach (int i in lray)
{
label[i].Forecolor = Color.Black;
}
}
I hope that explains what I am trying to do here.
Now it's obvious it won't work due to the label[i], but how would I get around this?
It might not work, because your Labels aren't held in an array. The following code will work, considering you know the names of the label to be changed:
Label[] lray = { labelOne, labelDifferent, labelWhatElse };
foreach (Label label in lray)
{
label.ForeColor = Color.Black;
}
That would work fine if you actually had an array of labels.
If you've only got lots of variables, like this:
private Label label1;
private Label label2;
private Label label3;
private Label label4;
private Label label5;
then it's harder. Options:
Change the code to use an array instead. Not as nice in the designer, but more logical
Use Controls.Find with each ID
Iterate over Controls to find all Label controls, regardless of name
foreach (Control c in this.Controls)
{
if (c is Label)
{
// do stuff
}
}
That'll grab all of the form's child controls (provided this code is in the form's code-behind) and check to see if they're labels. Just do any manipulation you want in place of the comment.
You could create the array yourself. This involves a bit of maintenance cost/risk each time your form changes though. Note: you probably want to put the array creation bit in a Form Loaded event, not a constructor, or at least, after the InitializeComponent call, so your controls are setup.
Or you could iterate on all the children of your Form (this.Controls from a Form method), mark your labels with a specific Tag, or get all Labels if that's your purpose here.
Please note that the first solution is probably much faster in runtime performance terms if you have many controls in your form.
private void allBlackLabels()
{
int[] lray = { 1, 2, 3, 5, 6 };
foreach (int i = 0; i < lray.Length; i++)
{
((Label)this.Controls["label" + i]).ForeColor = Color.Black;
}
}
If you want to achieve this for all labels on the form then something like this may help:
foreach (Control control in this.Controls) {
if (control is Label) {
(control as Label).Forecolor = Color.Black;
}
}
However if you only need to change a subset of all the labels then you need to either store the names or the indexes of the labels which need changing. This is because this.Controls has two indexers, an int32 and a string one. Thus you could try something like this
private void allBlackLabels()
{
int[] lray = { 1, 2, 3, 5, 6 };
foreach (int i in lray)
{
this.Controls[i].Forecolor = Color.Black;
}
}
It is defiantly worth noting however that the ordering in this.Controls will most likely not be as liniear looking as your lray array.
Hope this helps
Try some thing like this:
List<string> ListLabelNames = new List<string>() { /* Your label name list*/ };
foreach (Label TmpLabel in this.Controls.OfType<Label>())
{
foreach (string strTmp in ListLabelNames)
{
if (String.Compare(TmpLabel.Name, strTmp, true) == 0)
TmpLabel.ForeColor = System.Drawing.Color.Black;
}
}
Hope this helps.
I noticed that you excluded 4 from the "lray" array in your example. If you are looking to exclude one or more labels from being automatically updated by code (perhaps to highlight one among a group), try this.
private void allBlackLabels()
{
foreach (Control control in this.Controls)
{
if (control is Label && control.Name != "label4")
{
(control as Label).Forecolor = Color.Black;
}
}
}
in pseudo c#:
List<String> controlsToChange =new List<String>{"lable1Name","lable2Name"};
foreach(Control control in form.Controls)
{
if(control.GetType().Equals(typeof(Lable))
{
if( controlsToChange.Contains(control.Name)
{
control.Forecolor=Colour.Black;
}
}
}
I have groupbox I want to clear all the control in it , I try
public void ClearPanels(GroupBox control)
{
foreach (Control p in control.Controls)
{
control.Controls.Remove(p);
}
}
but a panel remain it , the problem I create the controls in runtime , and want to remove it in runtime
Better use this which clears all the controls at once without using a loop:
public void ClearPanels(GroupBox control)
{
control.Controls.Clear();
}
Use RemoteAt
while (control.Controls.Count > 0)
{
control.Controls.RemoveAt(0);
}
or Clear
control.Controls.Clear();
I have a panel with a bunch of labeles and textboxes inside of it.
The code:
foreach (Control ctrl in this.pnlSolutions.Controls)
Seems to only be finding html table inside the panel and 2 liternals.
But it does not get the textboxes that are in the html table.
Is there a simple way to get all the controls inside of a panel regardless of the nesting?
thanks!
Here's a lazy solution:
public IEnumerable<Control> GetAllControls(Control root) {
foreach (Control control in root.Controls) {
foreach (Control child in GetAllControls(control)) {
yield return child;
}
}
yield return root;
}
Remember also that some controls keep an internal collection of items (like the ToolStrip) and this will not enumerate those.
You would need to recursively "treewalk" through the controls, think about it like walking through a folder structure.
there is a sample Here
As far as I know your have to implement the recursion yourself, but its not really difficult.
A sketch (untested):
void AllControls(Control root, List<Control> accumulator)
{
accumulator.Add(root);
foreach(Control ctrl in root.Controls)
{
AllControls(ctrl, accumulator);
}
}
I had exactly the problem stated in the question so this may help somebody. I was attempting to clear a control collection prior to rewriting it.
private void clearCollection(Control.ControlCollection target)
{
foreach (Control Actrl in target)
{
if (Actrl is Label || Actrl is Button)
{
target.Remove(Actrl);
}
}
}
By removing the control inside the foreach loop it must mess with the internal pointers and the result is controls in the collection are missed.
My solution was to find all the controls then remove in a separate loop.
private void clearCollection(Control.ControlCollection target)
{
List<Control> accumulator = new List<Control>();
foreach (Control Actrl in target)
{
if (Actrl is Label || Actrl is Button)
{
accumulator.Add(Actrl); // find all controls first.
}
}
for (int i = 0; i < accumulator.Count; i++)
{
target.Remove(accumulator[i]);
}
}
The reason is because the only controls that are direct children of your panel are the table and the literals you mention, and it is only these that this.pnlSolutions.Controls returns.
The text boxes an labels are child controls of the table, making them grandchildren of the panel.
As #Yoda points out you need to recursively walk the controls to find them all.