how to use loops to access form elements in C#? - c#

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.

Related

Creating a class that loops through textboxes and labels making them visible in winform

I am very new to c# and visual studio.
I am using c# with Visual studio. I want to create a method that lops through a number of textboxes and labels and set their visible control to "True."
This is the code I have come up with so far, but it does not work.
public static void showFields(params string[] values)
{
foreach (var value in values)
{
value.Visible = true;
}
}
Any help would be greatly appreciated.
You are on the right path, just need to replace string with Control, by the way, string does not have the Visible property.
public static void showFields(params Control[] values)
{
foreach (var value in values)
{
value.Visible = true;
}
}
Code should be similar to this. You may have nested controls. In this case, you create a recursive method
private void MakeThemVisible(Control topControl)
{
foreach (var c in topControl.Controls)
{
if (c is TextBox txt && <your second criteria>) // <-- pattern matching
{
// <---- txt specific code here -------
txt.Visible = true;
continue;
}
else if (c is Label lbl && <your second criteria>) // <-- pattern matching
{
// <---- lbl specific code here -------
lbl.Visible = true;
continue;
}
MakeThemVisible(c);
}
}
Your form is also control
If you already have a list of needed controls in the form of array - Control[] values, you can use LINQ
values.ToList().ForEach(c => {c.Visible = true;});

a way to access "code generated" labels in C# winforms [duplicate]

I have a ToolStripMenuItem called myMenu. How can I access this like so:
/* Normally, I would do: */
this.myMenu... etc.
/* But how do I access it like this: */
String name = myMenu;
this.name...
This is because I am dynamically generating ToolStripMenuItems from an XML file and need to reference MenuItems by their dynamically generated names.
Use the Control.ControlCollection.Find method.
Try this:
this.Controls.Find()
string name = "the_name_you_know";
Control ctn = this.Controls[name];
ctn.Text = "Example...";
Assuming you have the menuStrip object and the menu is only one level deep, use:
ToolStripMenuItem item = menuStrip.Items
.OfType<ToolStripMenuItem>()
.SelectMany(it => it.DropDownItems.OfType<ToolStripMenuItem>())
.SingleOrDefault(n => n.Name == "MyMenu");
For deeper menu levels add more SelectMany operators in the statement.
if you want to search all menu items in the strip then use
ToolStripMenuItem item = menuStrip.Items
.Find("MyMenu",true)
.OfType<ToolStripMenuItem>()
.Single();
However, make sure each menu has a different name to avoid exception thrown by key duplicates.
To avoid exceptions you could use FirstOrDefault instead of SingleOrDefault / Single, or just return a sequence if you might have Name duplicates.
Control GetControlByName(string Name)
{
foreach(Control c in this.Controls)
if(c.Name == Name)
return c;
return null;
}
Disregard this, I reinvent wheels.
Using the same approach of Philip Wallace, we can do like this:
public Control GetControlByName(Control ParentCntl, string NameToSearch)
{
if (ParentCntl.Name == NameToSearch)
return ParentCntl;
foreach (Control ChildCntl in ParentCntl.Controls)
{
Control ResultCntl = GetControlByName(ChildCntl, NameToSearch);
if (ResultCntl != null)
return ResultCntl;
}
return null;
}
Example:
public void doSomething()
{
TextBox myTextBox = (TextBox) this.GetControlByName(this, "mytextboxname");
myTextBox.Text = "Hello!";
}
I hope it help! :)
this.Controls.Find(name, searchAllChildren) doesn't find ToolStripItem because ToolStripItem is not a Control
using SWF = System.Windows.Forms;
using NUF = NUnit.Framework;
namespace workshop.findControlTest {
[NUF.TestFixture]
public class FormTest {
[NUF.Test]public void Find_menu() {
// == prepare ==
var fileTool = new SWF.ToolStripMenuItem();
fileTool.Name = "fileTool";
fileTool.Text = "File";
var menuStrip = new SWF.MenuStrip();
menuStrip.Items.Add(fileTool);
var form = new SWF.Form();
form.Controls.Add(menuStrip);
// == execute ==
var ctrl = form.Controls.Find("fileTool", true);
// == not found! ==
NUF.Assert.That(ctrl.Length, NUF.Is.EqualTo(0));
}
}
}
One of the best way is a single row of code like this:
In this example we search all PictureBox by name in a form
PictureBox[] picSample =
(PictureBox)this.Controls.Find(PIC_SAMPLE_NAME, true);
Most important is the second paramenter of find.
if you are certain that the control name exists you can directly use it:
PictureBox picSample =
(PictureBox)this.Controls.Find(PIC_SAMPLE_NAME, true)[0];
You can use find function in your Form class. If you want to cast (Label) ,(TextView) ... etc, in this way you can use special features of objects. It will be return Label object.
(Label)this.Controls.Find(name,true)[0];
name: item name of searched item in the form
true: Search all Children boolean value
this.Controls["name"];
This is the actual code that is ran:
public virtual Control this[string key]
{
get
{
if (!string.IsNullOrEmpty(key))
{
int index = this.IndexOfKey(key);
if (this.IsValidIndex(index))
{
return this[index];
}
}
return null;
}
}
vs:
public Control[] Find(string key, bool searchAllChildren)
{
if (string.IsNullOrEmpty(key))
{
throw new ArgumentNullException("key", SR.GetString("FindKeyMayNotBeEmptyOrNull"));
}
ArrayList list = this.FindInternal(key, searchAllChildren, this, new ArrayList());
Control[] array = new Control[list.Count];
list.CopyTo(array, 0);
return array;
}
private ArrayList FindInternal(string key, bool searchAllChildren, Control.ControlCollection controlsToLookIn, ArrayList foundControls)
{
if ((controlsToLookIn == null) || (foundControls == null))
{
return null;
}
try
{
for (int i = 0; i < controlsToLookIn.Count; i++)
{
if ((controlsToLookIn[i] != null) && WindowsFormsUtils.SafeCompareStrings(controlsToLookIn[i].Name, key, true))
{
foundControls.Add(controlsToLookIn[i]);
}
}
if (!searchAllChildren)
{
return foundControls;
}
for (int j = 0; j < controlsToLookIn.Count; j++)
{
if (((controlsToLookIn[j] != null) && (controlsToLookIn[j].Controls != null)) && (controlsToLookIn[j].Controls.Count > 0))
{
foundControls = this.FindInternal(key, searchAllChildren, controlsToLookIn[j].Controls, foundControls);
}
}
}
catch (Exception exception)
{
if (ClientUtils.IsSecurityOrCriticalException(exception))
{
throw;
}
}
return foundControls;
}
Assuming you have Windows.Form Form1 as the parent form which owns the menu you've created. One of the form's attributes is named .Menu. If the menu was created programmatically, it should be the same, and it would be recognized as a menu and placed in the Menu attribute of the Form.
In this case, I had a main menu called File. A sub menu, called a MenuItem under File contained the tag Open and was named menu_File_Open. The following worked. Assuming you
// So you don't have to fully reference the objects.
using System.Windows.Forms;
// More stuff before the real code line, but irrelevant to this discussion.
MenuItem my_menuItem = (MenuItem)Form1.Menu.MenuItems["menu_File_Open"];
// Now you can do what you like with my_menuItem;
Since you're generating them dynamically, keep a map between a string and the menu item, that will allow fast retrieval.
// in class scope
private readonly Dictionary<string, ToolStripMenuItem> _menuItemsByName = new Dictionary<string, ToolStripMenuItem>();
// in your method creating items
ToolStripMenuItem createdItem = ...
_menuItemsByName.Add("<name here>", createdItem);
// to access it
ToolStripMenuItem menuItem = _menuItemsByName["<name here>"];
Have a look at the ToolStrip.Items collection. It even has a find method available.
You can do the following:
private ToolStripMenuItem getToolStripMenuItemByName(string nameParam)
{
foreach (Control ctn in this.Controls)
{
if (ctn is ToolStripMenuItem)
{
if (ctn.Name = nameParam)
{
return ctn;
}
}
}
return null;
}
A simple solution would be to iterate through the Controls list in a foreach loop. Something like this:
foreach (Control child in Controls)
{
// Code that executes for each control.
}
So now you have your iterator, child, which is of type Control. Now do what you will with that, personally I found this in a project I did a while ago in which it added an event for this control, like this:
child.MouseDown += new MouseEventHandler(dragDown);

Retrieve TextBox By Name

In my project i know the names of TextBoxes which are dynamically generated is there any solution to retrieve this TextBox text from other methods.In other sense i want to get TextBox by name and want to use in other part of code.
I have TextBox allocated like this...
private void Met(string rowNo)
{
TextBox t2 = new TextBox();
t2.Name = "itemAmt" + rowNo;
PurchaseItemEntryDyPanel.Controls.Add(t2);
}
Is there any way other than using name? Any Solution?
I personaly use name when I want to read posted data from a form.
And I would use Id when controls are supposed to be unique. So the code is a little different:
var t2 = new TextBox();
t2.ID = "itemAmt" + rowNo;
//since you mention in the comments, add it to the panel
yourPanel.Controls.Add(t2);
Then to get the textBox value
var controlId = "itemAmt" + rowNo;
var t2 = ((TextBox)(yourPanel.FindControl(controlId)));
if(t2 != null)
{
//do someting
//t2.Text = "something";
//t2.Enabled = true;
}
If you are not willing to make that change, go over the solution posted earlier.
You can get your TextBox from Controls collection of Form by it's name like this:
var myTextBox = this.Controls[textBoxName];
You don't show too much of your code, but I assume you're adding it to the collection of controls on your form. Otherwise, the TextBox you create in Met goes out of scope when your method ends, just like any other local variable.
private void Met(string rowNo)
{
TextBox t2 = new TextBox();
t2.Name = "itemAmt" + rowNo;
this.Controls.Add(t2); // need to add the TextBox to your form's controls
}
Then you can use Selman22's solution or, if the control might be added to a GroupBox or Panel, you'll want to search all child controls too:
var myControl = this.Controls.Find("itemAmt4", true);
if (myControl != null)
myControl.Enabled = true;
Use this in your Class:
foreach (Control tempCtrl in this.Controls)
{
// Determine he control is textBox1,
if (tempCtrl.Name == "itemAmt" + rowNo)
{
this.Controls.Remove(tempCtrl);
}
}

How can I get all Labels on a form and set the Text property of those with a particular name pattern to string.empty?

I want to clear all values on a form where the control is a label and its name starts with "label"
This code:
List<Label> lbls = this.Controls.OfType<Label>().ToList();
foreach (var lbl in lbls)
{
if (lbl.Name.StartsWith("label"))
{
lbl.Text = string.Empty;
}
}
...doesn't work, because the lambda is finding nothing - lbls.Count = 0.
Wouldn't this get ALL the controls on the form, even those that are children of other controls (such as, in my case, Panels)?
Try to use this method:
public void ClearLabel(Control control)
{
if (control is Label)
{
Label lbl = (Label)control;
if (lbl.Text.StartsWith("label"))
lbl.Text = String.Empty;
}
else
foreach (Control child in control.Controls)
{
ClearLabel(child);
}
}
You just need to pass form to ClearLabel method.
No, it will not recursively search Panels.
To do what you want, you can do:
void changeLabel(Control c)
{
if (lbl.Name.StartsWith("label"))
{
lbl.Text = string.Empty;
}
foreach(Control _c in c.Controls)
changeLabel(_c);
}
This does not touch the matter of recursion brought up in the previous answers; it's just another, a little more succint way of expressing what you had:
var labels = Controls.OfType<Label>().Where( x => x.Name.StartsWith("label") );
foreach (var label in labels)
{
label.Text = "";
}
That's what I ended up writing, I thought of adding it here just for completeness - essentially, you don't need ToList(), and String.Empty hasn't had any advantage over "" for ages.

Accessing a UserControls methods from its object

I have created a UserControl called AutorControl with a method to clear its textbox:
public void LimpiarAutorTextbox()
{
textBox1.Text = "";
}
Then my intention is from another form with a Panal, using a for loop add X ammount of the above user control. Then I want to call the UserControls method: "LimpiarAutorTextbox" (which is just a method for clearing the text of the textbox) using a foreach loop like this, however it's not working. I'm not sure what to do in this case:
AutorControl usercontrolAutorControl = new AutorControl();
private override void ClearControls()
{
txtTitulo.Text = "";
//Panel1 will only hold controls of the same type: "AutorControl"
foreach (Control X in panel1.Controls)
{
X as AutorControl;//?????? I want to access each created usercontrols' method.
}
}
The panel will always hold a usercontrol of AutorControl, never anything else. How can I achieve this programatically?
Thanks.
Your line here is fine:
X as AutorControl
just add:
(X as AutorControl).LimpiarAutorTextbox()
that should do the trick.
Also, I know you said that there would only be AutorControls in there, but you may want to do something more like this:
AutorControl currentControl == X as AutorControl;
if (AutorControl != null)
{
currentControl.LimpiarAutorTextbox();
}
Or alternatively, you can change your declaration of the for foreach loop to do the cast for you:
foreach(AutorControl currentControl in form.Controls)
{
if (currentControl != null)
{
currentControl.LimpiarAutorTextbox();
}
}
Some alternatives :)

Categories

Resources