I have a windows form which include some textbox and labels.In my program I set all of them unvisible and when I press button it makes all of the labels and textbox visible with the code below and it works perfect.
List<Label> lbls = this.Controls.OfType<Label>().ToList();
foreach (var lbl in lbls)
{
if (lbl.Name.StartsWith("label"))
{
lbl.Visible = true;
}
}
List<TextBox> txts = this.Controls.OfType<TextBox>().ToList();
foreach (var txt in txts)
{
if (txt.Name.StartsWith("textBox"))
{
txt.Visible = true;
}
}
But when I put all of my labels and textboxes into groupbox.My code doesn't work.How can I do this?
Note: My groupbox is also unvisible and when I press button.
groupBox1.visible =true;
This code works and groupbox panel seems, but the code of labels and textboxes doesn't work.
Because you are working with the immediate child of Form here
List<Label> lbls = this.Controls.OfType<Label>().ToList();
Notice this that means your current form. so when you have controls outside in form it works,
But when you put them inside group box it won't be the immediate child anymore.
so use
List<Label> lbls = groupBox1.Controls.OfType<Label>().ToList();
This will give you access to immediate children of the group box.
You're better off creating a recursive method of your own. Try implementing something like this:
private void MakeControlsInvisible(Control container, params Type[] controlTypes)
{
foreach (Control control in container.Controls)
{
if (controlTypes.Contains(control.GetType()))
{
control.Visible = false;
}
if (control.Controls.Count > 0)
{
MakeControlsInvisible(control, controlTypes);
}
}
}
And then using it on whatever container you wish:
MakeControlsInvisible(this, typeof(Label), typeof(TextBox)); // Will make all labels and textboxes inside the entire form invisible.
MakeControlsInvisible(groupBox1, typeof(Label), typeof(TextBox));// Will make all labels and textboxes inside groupBox1 invisible.
Related
I'm new working with C# and I'm asking on here because I didn't find a solution searching in google and other questions on SO, I will explain what my example application does:
When I run it it display a form with a textbox by default, this textbox always will be shown, after type some text and press enter it will generate a new textbox and a new button (all the controls even the default textbox are inside a panel), and the new textboxes have the same functionality as the default textbox, when I click on the button generated next to its textbox it removes the button itself and the textbox but after that if I remove some random textboxes it leaves a space between these controls, how can reorganize this content to dont let space between them?
As you can see in the image, can you tell me how can fix this or give me an advice to achieve this? thank you, by the way this is the method I use to generate the buttons and textboxes
private void GenerarTextBox()
{
panelContenedor.VerticalScroll.Value = panelContenedor.VerticalScroll.Minimum;
TextBox tb = new TextBox();
tb.Text = "Prueba " + id;
tb.Name = "txtBox" + id;
tb.KeyDown += new KeyEventHandler(TextBox_Keydown);
Button bt = new Button();
bt.Cursor = Cursors.Hand;
bt.Text = "X";
bt.Name = "btnPrueba" + id;
bt.Click += new EventHandler(ClickBotones);
Point p = new Point(20, 30 * id);
Point pb = new Point(130, 30 * id);
tb.Location = p;
bt.Location = pb;
panelContenedor.Controls.Add(tb);
panelContenedor.Controls.Add(bt);
tb.Focus();
id++;
}
And this to remove the textboxes and the buttons
private void ClickBotones(object sender, EventArgs e)
{
Button bt = sender as Button;
string nombreBoton = bt.Name;
string idBoton = nombreBoton.Substring(9);
string nombreTextBox = "txtBox" + idBoton;
foreach (Control item in panelContenedor.Controls.OfType<Control>())
{
if (item.Name == nombreTextBox)
{
panelContenedor.Controls.Remove(item);
panelContenedor.Controls.Remove(bt);
}
}
}
You could place your dynamic controls on a FlowLayoutPanel. Either directly or grouped together in a Panel or UserControl.
Set the FlowDirection property of the FlowLayoutPanel to TopDown. The FlowLayoutPanel will then arrange your controls automatically. You can also set the WrapContents property to False and AutoScroll to true to make the scroll bar appear.
Alternatively you can use FlowDirection = LeftToRight, place the text box and the button directly on the FlowLayoutPanel and let the child controls wrap (WrapContents = True). In the child controls, a new property FlowBreak appears. It can be set to True for the last control to appear in a row and let the next one wrap independently of the width of the FlowLayoutPanel.
You can also play with the Margin property of the child controls to control their layout in the FlowLayoutPanel as the Location property becomes useless.
The FlowLayoutPanel (as well as the Panel) is available in the Toolbox in the section "Containers".
When you delete the controls, you need to do a recalc of the positions. So when you have added them in sequence, you can go with:
bool repos = false;
Point p;
foreach (Control item in panelContenedor.Controls.OfType<Control>())
{
if (repos)
{
Point tmp = item.Location;
item.Location = p;
p = tmp;
}
if (item.Name == nombreTextBox)
{
panelContenedor.Controls.Remove(item);
panelContenedor.Controls.Remove(bt);
repos = true;
p = item.Location;
}
}
I'm still new at coding. I'm making a calculator but I also want a lot of other things in it. like a conversion calculator, cook book, and kanji radical dictionary in c# WindowsFormsApplication I want to change from one to the next using a comboBox so I was going to make a array with all the control I wish to hide/show
string[] numList = {"button0","button1","button2", "button3"};//this will have all number and .
for (int i = 0; i < numList.Length; i++)
{
numList[i].Hide();
}
But it tell me there no definition for 'Hide' but when I switch numList[i] to button0 it work but I don't wish to wright the same 11 control for every time i add something to the comboBox anyway to fixes this or any other method
If you want to hide all Buttons then try this:
foreach (Button control in Controls.OfType<Button>())
{
(control).Hide();
}
This iterate through all Buttons of the form and hide them. But if you want to just hide a specific buttons then you can set the Tag property of that buttons to something like OP then to hide only that Buttons:
foreach (Button control in Controls.OfType<Button>())
{
if (control.Tag.ToString() == "OP")
{
(control).Hide();
}
}
Or with linq:
foreach (Button control in Controls.OfType<Button>().Where(control => control.Tag.ToString() == "OP"))
{
(control).Hide();
}
try below code
private void btnHide_Click(object sender, EventArgs e)
{
string[] buttonList = { "button1", "button2", "button3" };
for (int i = 0; i < buttonList.Length; i++)
{
Control[] ctrl = this.Controls.Find(buttonList[i], true);
((Button)ctrl[0]).Visible = false;
}
}
You are keeping a list of strings, you should actually add the buttons in to the list in order to have the Hide method visible
Control[] numList = {button0, button1, button2, button3 };
foreach (Control c in this.Controls)
{
if (c is TextBox && c.Text.Length==0)
{
// [Associatedlabel].ForeColor = System.Drawing.Color.Red;
err = true;
}
instead of [Associatedlabel], I want to associate each textbox to label, so eventually all labels near the textbox that are empty will be red, how it can be done?
Thanks.
There is no fantastic way to find the label control back from the textbox. Using the form's GetChildAtPoint() method is something you can make easily work but are going to regret some day. Naming helps, like FooBarLabel matches FooBarTextBox. Now you can simply use the Controls collection to find the label back:
var label = (Label)this.Controls[box.Name.Replace("TextBox", "Label")];
But Winforms solves many problems by simple inheritance. Add a new class to your project and paste this code:
using System;
using System.Windows.Forms;
class LabeledTextBox : TextBox {
public Label Label { get; set; }
}
Compile and drop the new control from the top of the toolbox. Set the Label property in the designer, just pick it from the dropdown list. Boomshakalaka.
You can first manually set your TextBox's Tag property to these labels. Tag is meant to contain user-defined data, so you can place any object there. Then you can do simply:
foreach (Control c in this.Controls)
{
if (c is TextBox && c.Text.Length==0 && c.Tag is Label)
{
((Label)c.Tag).ForeColor = System.Drawing.Color.Red;
err = true;
}
}
This is the simplest solution, but a few more sophisticated exists though.
Creating a custom composite control consisting of a label, textbox and custom behavior;
Creating a control deriving from a textbox, which stores information about label it is connected with (as Hans Passant suggests)
Creating a Dictionary<TextBox, Label> or Dictionary<Control, Label>, which allows resolving such matters in runtime (variation on Steve's idea).
I suppose that you are using WinForms. In this environment you don't have any built-in functionality that associate a label to a textbox. So you need to build your own association.
This could be done creating a dictionary in the constructor of your code
public class MyForm : Form
{
private Dictionary<string, Label> assoc = new Dictionary<string, Label>();
public MyForm()
{
// Key=Name of the TextBox, Value=Label associated with that textbox
assoc.Add("textbox1", Label1);
assoc.Add("textbox2", Label2);
assoc.Add("textbox3", Label3);
}
}
.....
foreach (TextBox t in this.Controls.OfType<TextBox>())
{
if(t.Text.Length == 0)
{
assoc[t.Name].ForeColor = System.Drawing.Color.Red;
err = true;
}
else
assoc[t.Name].ForeColor = ??? system forecolor ???
}
Some inits done earlier in the code...
private List<System.Windows.Forms.TabPage> tab_pages = new List<System.Windows.Forms.TabPage>();
int tab_increment = 0;
Somewhere in the code, I create a bunch of tab pages in real-time.
for (i=0; i<5; i++)
{
tab_pages.Add( new System.Windows.Forms.TabPage() );
tab_pages[tab_increment].Location = new System.Drawing.Point(4, 22);
tab_pages[tab_increment].Name = 1 + tab_increment.ToString();
tab_pages[tab_increment].Size = new System.Drawing.Size(501, 281);
tab_pages[tab_increment].Text = tab_increment.ToString();
this.tabControl.Controls.Add(tab_pages[tab_increment]);
tab_increment += 1;
}
Now I would like to access elements that are these tab pages. Also let's pretend that I created different elements on each page (example, tabPage[0] a button, tabPage[1] a checkbox, etc), how do I access them knowing that everything was added dynamically?
Check this approach:
void Walk(Control control)
{
foreach (Control c in control.Controls)
{
//just walking through controls...
//...do something
//but remember, it could contain containers itself (say, groupbox or panel, etc.)...so, do a recursion
if (c.Controls.Count > 0)
Walk(c);
}
//or
foreach (Button btn in control.Controls.OfType<Button>())
{
//an example of how to walk through controls sub array of certain type
//this loop won't have a single iteration if this page contains no Buttons
//..so you can replace Button
//and have some certain code for different types of controls
}
}
And launch it for tabcontrol:
foreach (TabPage page in tabControl1.TabPages)
Walk(page);
I guess there is no special need to have separate collection of tabpages for one tabcontrol, as soon as it has TabPages property.
In the code above I used Enumerable.OfType Method to get a subcollection of controls of certain type.
As for your code, try this:
for (int i = 0; i < 5; i++)
{
this.tabControl.Controls.Add(new System.Windows.Forms.TabPage());
this.tabControl.TabPages[i].Text = i.ToString();
//...do whatever you need
//...
//besdies, I think, ther's no need in tab_increment...loop index works well enough
}
In order to add pages, I think that using
tabControl.TabPages.Add(new TabPage("Name"));
or in your case
this.tabControl.TabPages.Add(tab_pages[tab_increment]);
is more suitable.
In order to access them you could use
TabPage tp = tabControl.TabPages[i]; //where i is the index of your TabPage
and you can use TabPage.Controls.Add of the Controls property to add any Control on the TabPage like:
Button btn = new Button();
btn.Name = "Button name";
tp.Controls.Add(btn);
You can use the Controls property on the TabPage object. Each control in the collection is given to you as a Control, and it is up to you to cast them to the type that you want.
I have a Panel and two LinkLabels added on the panel and a treeview.
now in the panel_Paint event i want that the linklabel colors become white and background color of treeview turns black.
how do i do this?
the below code works only when there is no tree view in the panel but when i add a treeview also in the panel then it says :
Unable to cast object of type 'System.Windows.Forms.TreeView' to type 'System.Windows.Forms.LinkLabel'.
foreach (LinkLabel link in panel1.Controls)
{
link.LinkColor = Color.White;
}
Your panel contains all the controls - one of them is a TreeView which cannot be cast into a LinkLabel. In your loop you need to check the type of the control like this:
foreach (Control control in panel1.Controls)
{
if (control is LinkLabel)
{
... set link color
}
else if (control is TreeView)
{
... set background
}
}
Alternatively if you only have one LinkLabel and one TreeView you would not need a loop - just access them by name like you did with panel1
Try this:
foreach (Control ctrl in panel1.Controls)
{
LinkLabel link = ctrl as LinkLabel;
if(link != null)
link.LinkColor = Color.White;
}
Your getting the error because your trying to cast all controls in panel1 to a LinkLabel. You need to try something like this
foreach (Control control in panel1.Controls)
{
if (control.GetType() == typeof(LinkLabel))
{
LinkLabel link = (LinkLabel)control;
link.LinkColor = Color.White;
}
}
Hope this helps.
Edit: I knew there was a method but wasn't sure 100% of the name or syntax. See below an improved answer.
foreach (LinkLabel link in panel1.Controls.OfType<LinkLabel>())
{
link.LinkColor = Color.White;
}
Hope this is better for you.