I have a Form that contains a few TableLayoutPanel (List Panels) that I create dynamically.
Each TableLayoutPanel has a unique Tag. Actually each panel has Lable and this Lable has Name = "lable_name"
I need to update this exact Label inside a TableLayoutPanel.
public void UpdateLable(string tag, string newText)
{
foreach(var tlp in Views)
{
if (tlp.Tag.ToString().Equals(tag))
{
var lable = tlp.findViewByName("lable_name") as Label;
lable.Text = newText;
}
}
}
But I can't find method like findViewByName()
So, question is - how to find view by name?
Create a method as below
public static IEnumerable<Control> GetControlsOfType<T>(Control control)
{
var controls = control.Controls.Cast<Control>();
return controls.SelectMany(ctrl => GetControlsOfType<T>(ctrl)).Concat(controls).Where(c => c is T);
}
Use it like
Var control= GetControlsOfType<Label>(yourView).FirstOrDefault(x => x.Tag == tag);
if(control != null)
control.Text = newText
there is no such method directly in TableLayoutPanel class. But each Control has Controls property - collection of child controls.
that specialized collection has Find method which allows to get child by name:
var label = tlp.Controls.Find("lable_name", true)[0] as Label;
Related
I have created a class named Design
contain this codes
public static void Edit(Form frm, Color bkColor, Color btnColor,Color pnlColor)
{
frm.BackColor = bkColor;
frm.RightToLeft = RightToLeft.Yes;
frm.RightToLeftLayout = true;
foreach (Button btn in frm.Controls.OfType<Button>())
{
btn.BackColor = btnColor;
}
foreach (Panel pnl in frm.Controls.OfType<Panel>())
{
pnl.BackColor = pnlColor;
}
}
and I am calling it by this in the form:
Design.Edit(this, Color.Blue, Color.Green, Color.Yellow);
NOW it works good on the form background BUT on the panel and buttons not working at all
You need a recoursive search of your control inside of all the controls of the form.
Look that accepted answer that implement a very good recoursive approach.
Doing this:
frm.Controls.OfType<Button>()
you search only in the first layer of controls of your forms, so if you've a button inside a panel or another element (the 99,999999% of the situations) your foreach cannot find it.
adapting the Accepted answer at your Question:
public IEnumerable<Control> GetAll(this Control control,Type type)
{
var controls = control.Controls.Cast<Control>();
return controls.SelectMany(ctrl => ctrl.GetAll(type))
.Concat(controls)
.Where(c => c.GetType() == type);
}
[...]
foreach (Button btn in frm.GetAll(typeof(Button)))
{
btn.BackColor = btnColor;
}
L-
I've found a few answers around that work fine with modifying .Text, .Checked values and so, but none of them worked when I tried changing the .Value property. I can't get that to work on progress bars.
Last I tried:
foreach (Control c in this.Controls)
{
if (c.Name == "test" && c is ProgressBar)
{
((ProgressBar)c).Value = 23;
}
}
Am I missing a using statement or something?
Assuming that your progressbar control is named "test" (all lowercase letters) and is placed directly on the surface of your form (not inside a groupbox,panel or other control container) then this code should work and simplify your work
foreach (var c in this.Controls.OfType<ProgressBar>().Where(x => x.Name == "test")
{
c.Value = 23;
}
instead if the ProgressBar is placed inside a control container (like a panel) the above code should be changed to loop over the controls collection of the container
foreach (var c in this.panel1.Controls.OfType<ProgressBar>().Where(x => x.Name == "test")
{
c.Value = 23;
}
As pointed out in the comment by KingKing, if you are absolutely sure that a control named "test" exists in your groupbox then a simple lookup in the controls collection should result in your progressbar. Looping is not necessary in this case
ProgressBar pb = this.groupBox1.Controls["test"] as ProgressBar;
if(pb != null) pb.Value = 23;
The trick here is that Controls is not a List<> or IEnumerable but a ControlCollection.
I recommend using an extension of Control. Add this class to your project:
public static class ControlExtensionMethods
{
public static IEnumerable<Control> All(this System.Windows.Forms.Control.ControlCollection controls)
{
foreach (Control control in controls)
{
foreach (Control grandChild in control.Controls.All())
yield return grandChild;
yield return control;
}
}
}
Then you can do :
foreach(var textbox in this.Controls.All())
{
// Apply logic to a control
}
Source: Click
I've used this code before in another program, but now I'm having trouble understanding why it won't run the code after my second line.
foreach (Control c in Controls)
if (c.GetType() == typeof(TextBox)) //doesn't run any further
{
if ((string)c.Tag == "Filled")
{
...
}
...
}
I'm either missing some minor little detail or something else is incorrect. Any ideas?
EDIT: my textboxes are inside a panel.
It might be simpler to do this:
foreach ( TextBox tb in this.Controls.OfType<TextBox>())
{
if ((string)tb.Tag == "Filled")
// .....
}
When you call Control.Controls, it will only return the controls at the outermost level. It won't recursively descend into any container controls that hold other controls.
If your controls are in another container, you will need to use that container's .Controls property instead.
Alternatively you can generalize it by writing a method to recursively return all the controls from the parent and all it's children, like so:
public IEnumerable<Control> AllControls(Control container)
{
foreach (Control control in container.Controls)
{
yield return control;
foreach (var innerControl in AllControls(control))
yield return innerControl;
}
}
You can then use that instead of Control.Controls as follows:
private void test() // Assuming this is a member of a Form other class derived from Control
{
var textboxesWithFilledTag =
AllControls(this).OfType<TextBox>()
.Where(tb => (string) tb.Tag == "Filled");
foreach (var textbox in textboxesWithFilledTag)
Debug.WriteLine(textbox.Text);
}
As the comment says, I'm assuming that the test() method is a member of your Form or another class derived from Control. If it isn't, you will have to pass the parent control to it:
private void test(Control container)
{
var textboxesWithFilledTag =
AllControls(container).OfType<TextBox>()
.Where(tb => (string) tb.Tag == "Filled");
foreach (var textbox in textboxesWithFilledTag)
Debug.WriteLine(textbox.Text);
}
The following method has identical results to the one above, for reference (and is more readable IMHO):
private void test(Control container)
{
foreach (var textbox in AllControls(container).OfType<TextBox>())
if ((string)textbox.Tag == "Filled")
Debug.WriteLine(textbox.Text);
}
For your code, your button click handler might look something like this:
void button1_Click(object sender, EventArgs e)
{
foreach (var c in AllControls(this).OfType<TextBox>())
{
if ((string) c.Tag == "Filled")
{
// Here is where you put your code to do something with Textbox 'c'
}
}
}
Note that you also need the AllControls() method, of course.
To get all controls (not only the direct children of the form) you can use this recursive Linq
Func<Control, IEnumerable<Control>> allControls = null;
allControls = c => new Control[] { c }
.Concat(c.Controls.Cast<Control>()
.SelectMany(x=>allControls(x)));
Now you can filter the TextBoxes
var tbs = allControls(this).OfType<TextBox>()
.Where(t=>(string)t.Tag=="Filled")
.ToList();
Better use if (c is TextBox).
Furthermore, if you want to know why your code breaks, use try/catch
I'd recommend to use following syntax:
foreach (Control c in Controls)
if (c is TextBox)
Are you setting tag property from yourself. This is a string type of property.so you can try this:
if (c.Tag == "Filled")
{
Console.WriteLine(c.Name);
}
if you want to check that text box is not empty then you can simply try this :
if (c.Text.Trim().Length == 0)
{
Console.WriteLine(c.Name);
}
if(pictureBox1.Tag.ToString() == "accept")
{
char room1 = Convert.ToChar(lbl_roomid1.Text);
row1[13] = (byte)room1;
DateTime sdt1 = DateTime.Parse(txt_sdate1.Text);
//some code
}
if (pictureBox2.Tag.ToString() == "accept")
{
char room2 = Convert.ToChar(lbl_roomid2.Text);
row1[13] = (byte)room2;
DateTime sdt1 = DateTime.Parse(txt_sdate2.Text);
//some code
}
/* What if i wanted to type this code inside a loop?? i need to do the same for 10 pictureboxes */
Something like this:
public void DoMagic(Label label, TextBox textBox)
{
//...
}
And this:
foreach (Control currentControl in this.Controls)
{
if (currentControl is PictureBox)
{
if (((PictureBox)currentControl).Tag.ToString().Equals("accept"))
{
string controlId = currentControl.Name.Remove(0, 11);
string labelName = string.Concat("lbl_roomid", controlId);
string txtName = string.Concat("txt_sdate", controlId);
this.DoMagic(this.Controls.Find(labelName, true)[0] as Label, this.Controls.Find(txtName, true)[0] as TextBox);
}
}
}
Regards
You could make an array of the elements.
The following is a little dirty, but...
class PBRoomDate {
// Helper data holder class. Could probably be an anonymous class in C# 4.0
public PictureBox PB;
public Label RoomLabel;
public TextBox DateText;
PBRoomDate(PictureBox PB, Label RoomLabel, TextBox DateText) {
this.PB = PB; this.RoomLabel = RoomLabel; this.DateText = DateText;
}
}
// [...]
var pbRoomDates = new PBRoomDate[]{
new PBRoomDate(pictureBox1, lbl_roomid1, txt_sdate1),
new PBRoomDate(pictureBox2, lbl_roomid2, txt_sdate2),
new PBRoomDate(pictureBox3, lbl_roomid3, txt_sdate3),
// etc.
};
foreach(var pbRoomDate in pbRoomDates) {
if(pbRoomDate.PB.Tag.ToString() == "accept") {
row1[13] = (byte)Convert.ToChar(pbRoomDate.RoomLabel.Text);
DateTime dt = DateTime.Parse(pbRoomDate.DateText.Text);
}
}
The cleaner solution would be to use a custom UserControl to contain the three elements per "picturebox" and lay those out. That would also be easier to maintain and more extendable should the need arise.
Loops to access form elements in c#.
I usually use something like this.
Let say i have 10 picturebox i name it picturebox1 - picturebox10.
Then
Do a loop for the number to loop to 10 i use a variable no
inside it put this code
String Picturebox = "picturebox" + no.ToString();
Control[] oControl = Controls.Find(Picturebox, true);
foreach(Control foundControl in oControl)
{
PictureBox foundControlA = foundControl as PictureBox;
foundControlA.(methods or property here) = (what you want to put to foundControlA)
}
If you have more controls accompanied by each control you can use the same method. The hint here is that i use the same naming convention on my elements or object in my winforms and loop the variable no according to what you want.
the following one doesn't work:
foreach (Control control in Controls) {
if (control is DropDownList) {
DropDownList list = control as DropDownList;
...
}
}
PS: My class extends System.Web.UI.Page
You just need to replace Controls with Form.Controls
foreach (Control c in Form.Controls)
{
if (c is DropDownList)
{
// do something
}
}
Or you can use this extension:
public static IEnumerable<T> AllControls<T>(this Control startingPoint) where T : Control
{
bool hit = startingPoint is T;
if (hit)
{
yield return startingPoint as T;
}
foreach (var child in startingPoint.Controls.Cast<Control>())
{
foreach (var item in AllControls<T>(child))
{
yield return item;
}
}
}
Then you can use it for search of any type of System.Web.UI.Control within specific control. In case of DropDownList you can use it like:
IEnumerable<DropDownList> allDropDowns = this.pnlContainer.AllControls<DropDownList>();
this will find all drop downs within Panel control with ID="pnlContainer".
The problem is that some of the DropDownList controls may be nested in other controls.
If you page has a panel and all of your controls are in that panel the page's control array will only have that panel and all of the control will be in the Panel's control array.
The link that ajax81 linked to will work well.